From a5fed3c9f8f3454f38ad46d5af03994199066847 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Wed, 9 Mar 2016 09:02:09 +0100 Subject: [PATCH 001/311] test: tcp - verbose string length --- test/tcp/service.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/tcp/service.cpp b/test/tcp/service.cpp index 3cfc4fd499..1a43754e8c 100644 --- a/test/tcp/service.cpp +++ b/test/tcp/service.cpp @@ -157,7 +157,7 @@ void Service::start() CHECK(tcp.activeConnections() == 0, "tcp.activeConnections() == 0"); tcp.bind(TEST1).onConnect([](Connection_ptr conn) { - INFO("TEST", "SMALL string"); + INFO("TEST", "SMALL string (%u)", small.size()); conn->onReceive([](Connection_ptr conn, bool) { CHECK(conn->read() == small, "conn.read() == small"); conn->close(); @@ -174,7 +174,7 @@ void Service::start() TEST: Send and receive big string. */ tcp.bind(TEST2).onConnect([](Connection_ptr conn) { - INFO("TEST", "BIG string"); + INFO("TEST", "BIG string (%u)", big.size()); auto response = std::make_shared(); conn->onReceive([response](Connection_ptr conn, bool) { *response += conn->read(); @@ -191,7 +191,7 @@ void Service::start() TEST: Send and receive huge string. */ tcp.bind(TEST3).onConnect([](Connection_ptr conn) { - INFO("TEST", "HUGE string"); + INFO("TEST", "HUGE string (%u)", huge.size()); auto buffer = std::make_shared(huge.size()); conn->onReceive([buffer](Connection_ptr conn, bool) { // if not all expected data is read From 364a613558fea2d96cd3420b7226bb5399c7a3d2 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Thu, 10 Mar 2016 23:37:38 +0100 Subject: [PATCH 002/311] Fixed the crt-test, #265 --- test/crt/Makefile | 128 +++------------------------------------------- 1 file changed, 7 insertions(+), 121 deletions(-) diff --git a/test/crt/Makefile b/test/crt/Makefile index f8578bbedb..37904ead96 100644 --- a/test/crt/Makefile +++ b/test/crt/Makefile @@ -3,132 +3,18 @@ ################################################# # The name of your service -SERVICE = Test_C_Runtime +SERVICE = Test_crt +SERVICE_NAME = "C runtime test" # Your service parts FILES = service.cpp +# Your disk image +DISK= +LOCAL_INCLUDES= # IncludeOS location ifndef INCLUDEOS_INSTALL - INCLUDEOS_INSTALL=$(HOME)/IncludeOS_install +INCLUDEOS_INSTALL=$(HOME)/IncludeOS_install endif -# Shorter name -INSTALL = $(INCLUDEOS_INSTALL) - -# Compiler/Linker -################################################### - -OPTIONS = -Ofast -msse3 -Wall -Wextra -mstackrealign - -# External Libraries -################################################### -LIBC_OBJ = $(INSTALL)/newlib/libc.a -LIBG_OBJ = $(INSTALL)/newlib/libg.a -LIBM_OBJ = $(INSTALL)/newlib/libm.a - -LIBGCC = $(INSTALL)/libgcc/libgcc.a -LIBCXX = $(INSTALL)/libcxx/libc++.a $(INSTALL)/libcxx/libc++abi.a - - -INC_NEWLIB=$(INSTALL)/newlib/include -INC_LIBCXX=$(INSTALL)/libcxx/include - -DEBUG_OPTS = -ggdb3 -v - -CPP = clang++-3.6 -target i686-elf -LD = ld - -INCLUDES = -I$(INC_LIBCXX) -I$(INSTALL)/api/sys -I$(INC_NEWLIB) -I$(INSTALL)/api - -CAPABS_COMMON = -msse3 -mstackrealign # Needed for 16-byte stack alignment (SSE) - -all: CAPABS = $(CAPABS_COMMON) -O2 -debug: CAPABS = $(CAPABS_COMMON) -O0 -stripped: CAPABS = $(CAPABS_COMMON) -Oz - -WARNS = -Wall -Wextra #-pedantic -CPPOPTS = $(CAPABS) $(WARNS) -c -m32 -std=c++14 -fno-stack-protector $(INCLUDES) -D_LIBCPP_HAS_NO_THREADS=1 #-flto -fno-exceptions - -LDOPTS = -nostdlib -melf_i386 -N --script=$(INSTALL)/linker.ld -flto - - -# Objects -################################################### - -CRTBEGIN_OBJ = $(INSTALL)/crt/crtbegin.o -CRTEND_OBJ = $(INSTALL)/crt/crtend.o -CRTI_OBJ = $(INSTALL)/crt/crti.o -CRTN_OBJ = $(INSTALL)/crt/crtn.o - -# Full link list -OBJS = $(FILES:.cpp=.o) .service_name.o -LIBS = $(INSTALL)/os.a $(LIBCXX) $(INSTALL)/os.a $(LIBC_OBJ) $(LIBM_OBJ) $(LIBGCC) - -OS_PRE = $(CRTBEGIN_OBJ) $(CRTI_OBJ) -OS_POST = $(CRTEND_OBJ) $(CRTN_OBJ) - -DEPS = $(OBJS:.o=.d) - -# Complete bulid -################################################### -# A complete build includes: -# - a "service", to be linked with OS-objects (OS included) - -all: service - -stripped: LDOPTS += -S #strip all -stripped: CPPOPTS += -Oz -stripped: service - - -# The same, but with debugging symbols (OBS: Dramatically increases binary size) -debug: CCOPTS += $(DEBUG_OPTS) -debug: CPPOPTS += $(DEBUG_OPTS) -debug: LDOPTS += -M --verbose - -debug: OBJS += $(LIBG_OBJ) - -debug: service #Don't wanna call 'all', since it strips debug info - -# Service -################################################### -service.o: service.cpp - @echo "\n>> Compiling the service" - $(CPP) $(CPPOPTS) -o $@ $< - -.service_name.o: $(INSTALL)/service_name.cpp - $(CPP) $(CPPOPTS) -DSERVICE_NAME="\"$(SERVICE)\"" -o $@ $< - -# Link the service with the os -service: $(OBJS) $(LIBS) - @echo "\n>> Linking service with OS" - $(LD) $(LDOPTS) $(OS_PRE) $(OBJS) $(LIBS) $(OS_POST) -o $(SERVICE) - @echo "\n>> Building image " $(SERVICE).img - $(INSTALL)/vmbuild $(INSTALL)/bootloader $(SERVICE) - -# Object files -################################################### - -# Runtime -crt%.o: $(INSTALL)/crt/crt%.s - @echo "\n>> Assembling C runtime:" $@ - $(CPP) $(CPPOPTS) -x assembler-with-cpp $< - -# General C++-files to object files -%.o: %.cpp - @echo "\n>> Compiling OS object without header" - $(CPP) $(CPPOPTS) -o $@ $< - -# AS-assembled object files -%.o: %.s - @echo "\n>> Assembling GNU 'as' files" - $(CPP) $(CPPOPTS) -x assembler-with-cpp $< - -# Cleanup -################################################### -clean: - $(RM) $(OBJS) $(DEPS) $(SERVICE) - $(RM) $(SERVICE).img - --include $(DEPS) +include $(INCLUDEOS_INSTALL)/Makeseed From 523e78257798667e2f71c83c41254079ec734d5a Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Thu, 10 Mar 2016 23:43:18 +0100 Subject: [PATCH 003/311] Fixed exceptions test #265 --- test/crt/debug/service.gdb | 5 -- test/exceptions/Makefile | 128 ++---------------------------- test/exceptions/debug/service.gdb | 5 -- test/exceptions/service.cpp | 2 +- 4 files changed, 8 insertions(+), 132 deletions(-) delete mode 100644 test/crt/debug/service.gdb delete mode 100644 test/exceptions/debug/service.gdb diff --git a/test/crt/debug/service.gdb b/test/crt/debug/service.gdb deleted file mode 100644 index f5acb4ff3c..0000000000 --- a/test/crt/debug/service.gdb +++ /dev/null @@ -1,5 +0,0 @@ -file service -break _start -break OS::start -set non-stop off -target remote localhost:1234 \ No newline at end of file diff --git a/test/exceptions/Makefile b/test/exceptions/Makefile index aa0ca134aa..f05714f6b7 100644 --- a/test/exceptions/Makefile +++ b/test/exceptions/Makefile @@ -3,132 +3,18 @@ ################################################# # The name of your service -SERVICE = Test_Exceptions +SERVICE = test_exceptions +SERVICE_NAME = Exceptions test # Your service parts FILES = service.cpp +# Your disk image +DISK= +LOCAL_INCLUDES= # IncludeOS location ifndef INCLUDEOS_INSTALL - INCLUDEOS_INSTALL=$(HOME)/IncludeOS_install +INCLUDEOS_INSTALL=$(HOME)/IncludeOS_install endif -# Shorter name -INSTALL = $(INCLUDEOS_INSTALL) - -# Compiler/Linker -################################################### - -OPTIONS = -Ofast -msse3 -Wall -Wextra -mstackrealign - -# External Libraries -################################################### -LIBC_OBJ = $(INSTALL)/newlib/libc.a -LIBG_OBJ = $(INSTALL)/newlib/libg.a -LIBM_OBJ = $(INSTALL)/newlib/libm.a - -LIBGCC = $(INSTALL)/libgcc/libgcc.a -LIBCXX = $(INSTALL)/libcxx/libc++.a $(INSTALL)/libcxx/libc++abi.a - - -INC_NEWLIB=$(INSTALL)/newlib/include -INC_LIBCXX=$(INSTALL)/libcxx/include - -DEBUG_OPTS = -ggdb3 -v - -CPP = clang++-3.6 -target i686-elf -LD = ld - -INCLUDES = -I$(INC_LIBCXX) -I$(INSTALL)/api/sys -I$(INC_NEWLIB) -I$(INSTALL)/api - -CAPABS_COMMON = -msse3 -mstackrealign # Needed for 16-byte stack alignment (SSE) - -all: CAPABS = $(CAPABS_COMMON) -O2 -debug: CAPABS = $(CAPABS_COMMON) -O0 -stripped: CAPABS = $(CAPABS_COMMON) -Oz - -WARNS = -Wall -Wextra #-pedantic -CPPOPTS = $(CAPABS) $(WARNS) -c -m32 -std=c++14 -fno-stack-protector $(INCLUDES) -D_LIBCPP_HAS_NO_THREADS=1 #-flto -fno-exceptions - -LDOPTS = -nostdlib -melf_i386 -N --script=$(INSTALL)/linker.ld -flto - - -# Objects -################################################### - -CRTBEGIN_OBJ = $(INSTALL)/crt/crtbegin.o -CRTEND_OBJ = $(INSTALL)/crt/crtend.o -CRTI_OBJ = $(INSTALL)/crt/crti.o -CRTN_OBJ = $(INSTALL)/crt/crtn.o - -# Full link list -OBJS = $(FILES:.cpp=.o) .service_name.o -LIBS = $(INSTALL)/os.a $(LIBCXX) $(INSTALL)/os.a $(LIBC_OBJ) $(LIBM_OBJ) $(LIBGCC) - -OS_PRE = $(CRTBEGIN_OBJ) $(CRTI_OBJ) -OS_POST = $(CRTEND_OBJ) $(CRTN_OBJ) - -DEPS = $(OBJS:.o=.d) - -# Complete bulid -################################################### -# A complete build includes: -# - a "service", to be linked with OS-objects (OS included) - -all: service - -stripped: LDOPTS += -S #strip all -stripped: CPPOPTS += -Oz -stripped: service - - -# The same, but with debugging symbols (OBS: Dramatically increases binary size) -debug: CCOPTS += $(DEBUG_OPTS) -debug: CPPOPTS += $(DEBUG_OPTS) -debug: LDOPTS += -M --verbose - -debug: OBJS += $(LIBG_OBJ) - -debug: service #Don't wanna call 'all', since it strips debug info - -# Service -################################################### -service.o: service.cpp - @echo "\n>> Compiling the service" - $(CPP) $(CPPOPTS) -o $@ $< - -.service_name.o: $(INSTALL)/service_name.cpp - $(CPP) $(CPPOPTS) -DSERVICE_NAME="\"$(SERVICE)\"" -o $@ $< - -# Link the service with the os -service: $(OBJS) $(LIBS) - @echo "\n>> Linking service with OS" - $(LD) $(LDOPTS) $(OS_PRE) $(OBJS) $(LIBS) $(OS_POST) -o $(SERVICE) - @echo "\n>> Building image " $(SERVICE).img - $(INSTALL)/vmbuild $(INSTALL)/bootloader $(SERVICE) - -# Object files -################################################### - -# Runtime -crt%.o: $(INSTALL)/crt/crt%.s - @echo "\n>> Assembling C runtime:" $@ - $(CPP) $(CPPOPTS) -x assembler-with-cpp $< - -# General C++-files to object files -%.o: %.cpp - @echo "\n>> Compiling OS object without header" - $(CPP) $(CPPOPTS) -o $@ $< - -# AS-assembled object files -%.o: %.s - @echo "\n>> Assembling GNU 'as' files" - $(CPP) $(CPPOPTS) -x assembler-with-cpp $< - -# Cleanup -################################################### -clean: - $(RM) $(OBJS) $(DEPS) $(SERVICE) - $(RM) $(SERVICE).img - --include $(DEPS) +include $(INCLUDEOS_INSTALL)/Makeseed diff --git a/test/exceptions/debug/service.gdb b/test/exceptions/debug/service.gdb deleted file mode 100644 index f5acb4ff3c..0000000000 --- a/test/exceptions/debug/service.gdb +++ /dev/null @@ -1,5 +0,0 @@ -file service -break _start -break OS::start -set non-stop off -target remote localhost:1234 \ No newline at end of file diff --git a/test/exceptions/service.cpp b/test/exceptions/service.cpp index c8c67fe336..15a0123cce 100644 --- a/test/exceptions/service.cpp +++ b/test/exceptions/service.cpp @@ -17,7 +17,7 @@ #include #include - +#include class CustomException : public std::runtime_error { using runtime_error::runtime_error; From 07ca884bbc671393e292cd243a497ee4235ace66 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Thu, 10 Mar 2016 23:55:38 +0100 Subject: [PATCH 004/311] Fixed quick_exit test #265 --- test/quick_exit/Makefile | 128 ++---------------------------- test/quick_exit/debug/service.gdb | 5 -- test/quick_exit/service.cpp | 20 ++++- 3 files changed, 24 insertions(+), 129 deletions(-) delete mode 100644 test/quick_exit/debug/service.gdb diff --git a/test/quick_exit/Makefile b/test/quick_exit/Makefile index 749e17842f..c4018195c9 100644 --- a/test/quick_exit/Makefile +++ b/test/quick_exit/Makefile @@ -3,132 +3,18 @@ ################################################# # The name of your service -SERVICE = Test_quick_exit +SERVICE = test_quick_exit +SERVICE_NAME = Quick Exit Test # Your service parts FILES = service.cpp +# Your disk image +DISK= +LOCAL_INCLUDES= # IncludeOS location ifndef INCLUDEOS_INSTALL - INCLUDEOS_INSTALL=$(HOME)/IncludeOS_install +INCLUDEOS_INSTALL=$(HOME)/IncludeOS_install endif -# Shorter name -INSTALL = $(INCLUDEOS_INSTALL) - -# Compiler/Linker -################################################### - -OPTIONS = -Ofast -msse3 -Wall -Wextra -mstackrealign - -# External Libraries -################################################### -LIBC_OBJ = $(INSTALL)/newlib/libc.a -LIBG_OBJ = $(INSTALL)/newlib/libg.a -LIBM_OBJ = $(INSTALL)/newlib/libm.a - -LIBGCC = $(INSTALL)/libgcc/libgcc.a -LIBCXX = $(INSTALL)/libcxx/libc++.a $(INSTALL)/libcxx/libc++abi.a - - -INC_NEWLIB=$(INSTALL)/newlib/include -INC_LIBCXX=$(INSTALL)/libcxx/include - -DEBUG_OPTS = -ggdb3 -v - -CPP = clang++-3.6 -target i686-elf -LD = ld - -INCLUDES = -I$(INC_LIBCXX) -I$(INSTALL)/api/sys -I$(INC_NEWLIB) -I$(INSTALL)/api - -CAPABS_COMMON = -msse3 -mstackrealign # Needed for 16-byte stack alignment (SSE) - -all: CAPABS = $(CAPABS_COMMON) -O2 -debug: CAPABS = $(CAPABS_COMMON) -O0 -stripped: CAPABS = $(CAPABS_COMMON) -Oz - -WARNS = -Wall -Wextra #-pedantic -CPPOPTS = $(CAPABS) $(WARNS) -c -m32 -std=c++14 -fno-stack-protector $(INCLUDES) -D_LIBCPP_HAS_NO_THREADS=1 #-flto -fno-exceptions - -LDOPTS = -nostdlib -melf_i386 -N --script=$(INSTALL)/linker.ld -flto - - -# Objects -################################################### - -CRTBEGIN_OBJ = $(INSTALL)/crt/crtbegin.o -CRTEND_OBJ = $(INSTALL)/crt/crtend.o -CRTI_OBJ = $(INSTALL)/crt/crti.o -CRTN_OBJ = $(INSTALL)/crt/crtn.o - -# Full link list -OBJS = $(FILES:.cpp=.o) .service_name.o -LIBS = $(INSTALL)/os.a $(LIBCXX) $(INSTALL)/os.a $(LIBC_OBJ) $(LIBM_OBJ) $(LIBGCC) - -OS_PRE = $(CRTBEGIN_OBJ) $(CRTI_OBJ) -OS_POST = $(CRTEND_OBJ) $(CRTN_OBJ) - -DEPS = $(OBJS:.o=.d) - -# Complete bulid -################################################### -# A complete build includes: -# - a "service", to be linked with OS-objects (OS included) - -all: service - -stripped: LDOPTS += -S #strip all -stripped: CPPOPTS += -Oz -stripped: service - - -# The same, but with debugging symbols (OBS: Dramatically increases binary size) -debug: CCOPTS += $(DEBUG_OPTS) -debug: CPPOPTS += $(DEBUG_OPTS) -debug: LDOPTS += -M --verbose - -debug: OBJS += $(LIBG_OBJ) - -debug: service #Don't wanna call 'all', since it strips debug info - -# Service -################################################### -service.o: service.cpp - @echo "\n>> Compiling the service" - $(CPP) $(CPPOPTS) -o $@ $< - -.service_name.o: $(INSTALL)/service_name.cpp - $(CPP) $(CPPOPTS) -DSERVICE_NAME="\"$(SERVICE)\"" -o $@ $< - -# Link the service with the os -service: $(OBJS) $(LIBS) - @echo "\n>> Linking service with OS" - $(LD) $(LDOPTS) $(OS_PRE) $(OBJS) $(LIBS) $(OS_POST) -o $(SERVICE) - @echo "\n>> Building image " $(SERVICE).img - $(INSTALL)/vmbuild $(INSTALL)/bootloader $(SERVICE) - -# Object files -################################################### - -# Runtime -crt%.o: $(INSTALL)/crt/crt%.s - @echo "\n>> Assembling C runtime:" $@ - $(CPP) $(CPPOPTS) -x assembler-with-cpp $< - -# General C++-files to object files -%.o: %.cpp - @echo "\n>> Compiling OS object without header" - $(CPP) $(CPPOPTS) -o $@ $< - -# AS-assembled object files -%.o: %.s - @echo "\n>> Assembling GNU 'as' files" - $(CPP) $(CPPOPTS) -x assembler-with-cpp $< - -# Cleanup -################################################### -clean: - $(RM) $(OBJS) $(DEPS) $(SERVICE) - $(RM) $(SERVICE).img - --include $(DEPS) +include $(INCLUDEOS_INSTALL)/Makeseed diff --git a/test/quick_exit/debug/service.gdb b/test/quick_exit/debug/service.gdb deleted file mode 100644 index f5acb4ff3c..0000000000 --- a/test/quick_exit/debug/service.gdb +++ /dev/null @@ -1,5 +0,0 @@ -file service -break _start -break OS::start -set non-stop off -target remote localhost:1234 \ No newline at end of file diff --git a/test/quick_exit/service.cpp b/test/quick_exit/service.cpp index 4504e901b0..cceea17662 100644 --- a/test/quick_exit/service.cpp +++ b/test/quick_exit/service.cpp @@ -17,15 +17,29 @@ #include #include +#include +/** + Test 'quick-exit' and 'at_quick_exit' from C11 + + NOTE: This test is supposed to result in a PANIC, + after calling the quick-exit handler, and then quick_exit + +**/ void Service::start() { - printf("TESTING Quick Exit\n"); + INFO("Test Quick Exit","Expect panic after exit handler"); + + at_quick_exit([](){ + CHECK(1,"Custom quick exit-handler called"); + return; + }); - at_quick_exit([](){ printf("[x] Custom quick exit-handler called \n"); return; }); quick_exit(0); // Make sure we actually exit (This is dead code - but for testing) - at_quick_exit([](){ printf("[0] Service didn't actually exit \n"); return; }); + at_quick_exit([](){ + CHECK(0, "FAIL: Service didn't actually exit \n"); return; }); + } From d76d520b42b74f7c8729ff4a1daf21f311f66c2a Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Fri, 11 Mar 2016 01:14:03 +0100 Subject: [PATCH 005/311] Fixed crt test name --- test/crt/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/crt/Makefile b/test/crt/Makefile index 37904ead96..c662fdfbae 100644 --- a/test/crt/Makefile +++ b/test/crt/Makefile @@ -4,7 +4,7 @@ # The name of your service SERVICE = Test_crt -SERVICE_NAME = "C runtime test" +SERVICE_NAME = C runtime test # Your service parts FILES = service.cpp From d182282b9ded5acece71ca786b00bcc3d15c70aa Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Fri, 11 Mar 2016 02:33:12 +0100 Subject: [PATCH 006/311] Fixed STREAM-test. Close #265 --- etc/qemu_cmd.sh | 17 +++++++++-------- src/seed/Makefile | 3 ++- test/STL/Makefile | 2 +- test/STL/test.sh | 5 ----- test/STREAM/Makefile | 1 + test/STREAM/run.sh | 2 +- test/UDP/Makefile | 1 + test/memdisk/test.sh | 1 + 8 files changed, 16 insertions(+), 16 deletions(-) delete mode 100755 test/STL/test.sh diff --git a/etc/qemu_cmd.sh b/etc/qemu_cmd.sh index 565def0e0b..73a7a39d01 100755 --- a/etc/qemu_cmd.sh +++ b/etc/qemu_cmd.sh @@ -10,14 +10,15 @@ fi export macaddress="c0:01:0a:00:00:2a" INCLUDEOS_HOME=${INCLUDEOS_HOME-$HOME/IncludeOS_install} -export qemu_ifup="$INCLUDEOS_HOME/etc/qemu-ifup" - -export DEV_NET="-device virtio-net,netdev=net0,mac=$macaddress -netdev tap,id=net0,script=$qemu_ifup" -export SMP="-smp 1" -export DEV_GRAPHICS="-nographic" +export qemu_ifup="$INCLUDEOS_HOME/etc/qemu-ifup" -export SERIAL="-virtioconsole stdio" +[ ! -v NET ] && export NET="-device virtio-net,netdev=net0,mac=$macaddress -netdev tap,id=net0,script=$qemu_ifup" +[ ! -v SMP ] && export SMP="-smp 1" +[ ! -v GRAPHICS ] && export GRAPHICS="-nographic" +[ ! -v SERIAL ] && export SERIAL="-virtioconsole stdio" +[ ! -v MEM ] && export MEM="-m 128" +[ ! -v HDD ] && export HDD="-drive file=$IMAGE,format=raw,if=ide" +[ ! -v CPU ] && export CPU="-cpu host" -export DEV_HDD="-drive file=$IMAGE,format=raw,if=ide" -export QEMU_OPTS="$DEV_HDD $DEV_NET $DEV_GRAPHICS $SMP" +export QEMU_OPTS="$HDD $NET $GRAPHICS $SMP $MEM $CPU" diff --git a/src/seed/Makefile b/src/seed/Makefile index ce30c13f3a..b467af8fa2 100644 --- a/src/seed/Makefile +++ b/src/seed/Makefile @@ -40,7 +40,7 @@ ifndef LD_INC LD_INC = ld endif -INCLUDES = -I$(INC_LIBCXX) -I$(INSTALL)/api/sys -I$(INC_NEWLIB) -I$(INSTALL)/api -I$(LOCAL_INCLUDES) " " +INCLUDES = -I$(INC_LIBCXX) -I$(INSTALL)/api/sys -I$(INC_NEWLIB) -I$(INSTALL)/api $(LOCAL_INCLUDES) all: CAPABS = $(CAPABS_COMMON) -O2 debug: CAPABS = $(CAPABS_COMMON) -O0 @@ -59,6 +59,7 @@ CRTN_OBJ = $(INSTALL)/crt/crtn.o # Full link list OBJS = $(FILES:.cpp=.o) .service_name.o + LIBS = $(INSTALL)/os.a $(LIBCXX) $(INSTALL)/os.a $(LIBC_OBJ) $(LIBM_OBJ) $(LIBGCC) OS_PRE = $(CRTBEGIN_OBJ) $(CRTI_OBJ) diff --git a/test/STL/Makefile b/test/STL/Makefile index 4037d03c72..12d0723356 100644 --- a/test/STL/Makefile +++ b/test/STL/Makefile @@ -9,7 +9,7 @@ SERVICE_NAME = IncludeOS basic STL test # Your service parts FILES = service.cpp -LOCAL_INCLUDES = $(PWD)/../lest/include/lest +LOCAL_INCLUDES=-I$(PWD)/../lest/include/lest # Your disk image DISK= diff --git a/test/STL/test.sh b/test/STL/test.sh deleted file mode 100755 index 0ec44520d7..0000000000 --- a/test/STL/test.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -source ../test_base - -make SERVICE=Test_STL FILES=service.cpp -start Test_STL.img "Basic STL test" diff --git a/test/STREAM/Makefile b/test/STREAM/Makefile index 94d46d692b..0b039e572b 100644 --- a/test/STREAM/Makefile +++ b/test/STREAM/Makefile @@ -8,6 +8,7 @@ SERVICE_NAME = STREAM Memory benchmark # Your service parts FILES = service.cpp stream.cpp + # Your disk image DISK= diff --git a/test/STREAM/run.sh b/test/STREAM/run.sh index 3b2132d2cb..961760823a 100755 --- a/test/STREAM/run.sh +++ b/test/STREAM/run.sh @@ -1,3 +1,3 @@ #! /bin/bash -source ${INCLUDEOS_HOME-$HOME/IncludeOS_install}/etc/run.sh +MEM="-m 256" source ${INCLUDEOS_HOME-$HOME/IncludeOS_install}/etc/run.sh diff --git a/test/UDP/Makefile b/test/UDP/Makefile index 463b31fa1c..3a9cc498c1 100644 --- a/test/UDP/Makefile +++ b/test/UDP/Makefile @@ -8,6 +8,7 @@ SERVICE_NAME = "IncludeOS\ UDP\ test" # Your service parts FILES = service.cpp + # Your disk image DISK= diff --git a/test/memdisk/test.sh b/test/memdisk/test.sh index 167000decf..e508abfc7b 100755 --- a/test/memdisk/test.sh +++ b/test/memdisk/test.sh @@ -19,6 +19,7 @@ sudo cp banana.txt tmpdisk/ sync # Mui Importante make SERVICE=Test DISK=big.disk FILES=bigdisk.cpp +export MEM="-m 256" start Test.img "Memdisk: Big disk test" make SERVICE=Test FILES=bigdisk.cpp clean From 8720d3fee5176c9d56f324eef36dfeb399a27772 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Fri, 11 Mar 2016 02:51:19 +0100 Subject: [PATCH 007/311] Added memory parameter to vboxrun --- etc/vboxrun.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/etc/vboxrun.sh b/etc/vboxrun.sh index bdc786d487..dd84186958 100755 --- a/etc/vboxrun.sh +++ b/etc/vboxrun.sh @@ -91,6 +91,10 @@ else # NETWORK $VB modifyvm "$VMNAME" --nic1 hostonly --nictype1 virtio --hostonlyadapter1 vboxnet0 + + # Memory + $VB modifyvm "$VMNAME" --memory 256 + fi # START VM $VB startvm "$VMNAME" & From 34d43bd3486fa35537c8e30e62cbd6cf9d5d28c5 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Fri, 11 Mar 2016 13:26:34 +0100 Subject: [PATCH 008/311] test: Async FAT file read --- src/Makefile | 2 +- test/fat/fat32.cpp | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index 0cbbebcc7e..fb038b8fe1 100644 --- a/src/Makefile +++ b/src/Makefile @@ -187,7 +187,7 @@ bootloader: boot/bootloader.asm boot/disk_read_lba.asm # Disk image as a section ################################################### -memdisk: memdisk.asm +memdisk: @echo "\n>> Assembling memdisk" nasm -f elf -o memdisk.o $< diff --git a/test/fat/fat32.cpp b/test/fat/fat32.cpp index 213ab575b6..e0c97d2901 100644 --- a/test/fat/fat32.cpp +++ b/test/fat/fat32.cpp @@ -96,6 +96,35 @@ void Service::start() CHECK(ent.name() == "banana.txt", "Name is 'banana.txt'"); assert(ent.name() == "banana.txt"); + // asynch file reading test + fs.readFile(ent, + [] (fs::error_t err, fs::buffer_t buf, uint64_t len) + { + CHECK(!err, "Read 'banana.txt' asynchronously"); + if (err) + { + panic("Failed to read file async"); + } + + std::string banana((char*) buf.get(), len); + std::string internal_banana = + R"( ____ ___ + | _ \ ___ _ _.' _ `. + _ | [_) )' _ `._ _ ___ ! \ | | (_) | _ +|:;.| _ <| (_) | \ | |' _ `| \| | _ | .:;| +| `.[_) ) _ | \| | (_) | | | | |.',..| +':. `. /| | | | | _ | |\ | | |.' :;::' + !::, `-!_| | | |\ | | | | | \ !_!.' ':;! + !::; ":;:!.!.\_!_!_!.!-'-':;:'' '''! + ';:' `::;::;' '' ., . + `: .,. `' .::... . .::;::;' + `..:;::;:.. ::;::;:;:;, :;::;' + "-:;::;:;: ':;::;:'' ;.-' + ""`---...________...---'"" +)"; + CHECK(banana == internal_banana, "Correct banana"); + printf("%s\n", banana.c_str()); + }); }); INFO("FAT32", "SUCCESS"); From 14e912bd50d687f187be28f0887533d90f8d50d0 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Fri, 11 Mar 2016 14:08:41 +0100 Subject: [PATCH 009/311] test: VGA setup --- api/vga | 25 +++++++++++++++++++++++++ test/vga/Makefile | 19 +++++++++++++++++++ test/vga/test.sh | 7 +++++++ test/vga/vga.cpp | 37 +++++++++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+) create mode 100644 api/vga create mode 100644 test/vga/Makefile create mode 100755 test/vga/test.sh create mode 100644 test/vga/vga.cpp diff --git a/api/vga b/api/vga new file mode 100644 index 0000000000..3b141fc65c --- /dev/null +++ b/api/vga @@ -0,0 +1,25 @@ +// -*-C++-*- +// This file is a part of the IncludeOS unikernel - www.includeos.org +// +// Copyright 2015 Oslo and Akershus University College of Applied Sciences +// and Alfred Bratterud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once +#ifndef VGA_HEADER +#define VGA_HEADER + +#include "kernel/vga.hpp" + +#endif diff --git a/test/vga/Makefile b/test/vga/Makefile new file mode 100644 index 0000000000..92d5beedee --- /dev/null +++ b/test/vga/Makefile @@ -0,0 +1,19 @@ +################################################# +# IncludeOS SERVICE makefile # +################################################# + +# The name of your service +SERVICE = Test +SERVICE_NAME = The VGA Test Service + +# Your service parts +FILES=vga.cpp +# Your disk image +DISK= + +# IncludeOS location +ifndef INCLUDEOS_INSTALL +INCLUDEOS_INSTALL=$(HOME)/IncludeOS_install +endif + +include $(INCLUDEOS_INSTALL)/Makeseed diff --git a/test/vga/test.sh b/test/vga/test.sh new file mode 100755 index 0000000000..6cc38ed71d --- /dev/null +++ b/test/vga/test.sh @@ -0,0 +1,7 @@ +#!/bin/bash +source ../test_base + +export QEMU_EXTRA="-vga cirrus" +make SERVICE=Test FILES=vga.cpp +start Test.img "VGA: Verify that the service starts test" +make SERVICE=Test FILES=vga.cpp clean diff --git a/test/vga/vga.cpp b/test/vga/vga.cpp new file mode 100644 index 0000000000..81f12709ee --- /dev/null +++ b/test/vga/vga.cpp @@ -0,0 +1,37 @@ +// This file is a part of the IncludeOS unikernel - www.includeos.org +// +// Copyright 2015 Oslo and Akershus University College of Applied Sciences +// and Alfred Bratterud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include +ConsoleVGA vga; + +void Service::start() +{ + INFO("VGA", "Running tests for VGA"); + + OS::set_rsprint( + [] (const char* data, size_t len) + { + vga.write(data, len); + }); + printf("Hello there!\n"); + + INFO("VGA", "SUCCESS"); +} From fa10f3cf63f8311faa61a2ddc253c960f66103c3 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Fri, 11 Mar 2016 15:00:57 +0100 Subject: [PATCH 010/311] test: VGA more helper files --- test/vga/debug.sh | 2 ++ test/vga/run.sh | 3 +++ test/vga/service.gdb | 3 +++ test/vga/vbox.sh | 2 ++ test/vga/vga.cpp | 12 ++++++++++++ 5 files changed, 22 insertions(+) create mode 100755 test/vga/debug.sh create mode 100755 test/vga/run.sh create mode 100644 test/vga/service.gdb create mode 100755 test/vga/vbox.sh diff --git a/test/vga/debug.sh b/test/vga/debug.sh new file mode 100755 index 0000000000..f55e4c7471 --- /dev/null +++ b/test/vga/debug.sh @@ -0,0 +1,2 @@ +#!/bin/bash +gdb -x service.gdb diff --git a/test/vga/run.sh b/test/vga/run.sh new file mode 100755 index 0000000000..3b2132d2cb --- /dev/null +++ b/test/vga/run.sh @@ -0,0 +1,3 @@ +#! /bin/bash +source ${INCLUDEOS_HOME-$HOME/IncludeOS_install}/etc/run.sh + diff --git a/test/vga/service.gdb b/test/vga/service.gdb new file mode 100644 index 0000000000..6c699abfe8 --- /dev/null +++ b/test/vga/service.gdb @@ -0,0 +1,3 @@ +file Test +break Service::start +target remote localhost:1234 diff --git a/test/vga/vbox.sh b/test/vga/vbox.sh new file mode 100755 index 0000000000..3ce34897a7 --- /dev/null +++ b/test/vga/vbox.sh @@ -0,0 +1,2 @@ +#!/bin/bash +../../etc/vboxrun.sh Test.img diff --git a/test/vga/vga.cpp b/test/vga/vga.cpp index 81f12709ee..43e1425b07 100644 --- a/test/vga/vga.cpp +++ b/test/vga/vga.cpp @@ -19,6 +19,10 @@ #include #include +#include +using namespace net; +std::unique_ptr> inet; + #include ConsoleVGA vga; @@ -33,5 +37,13 @@ void Service::start() }); printf("Hello there!\n"); + hw::Nic& eth0 = hw::Dev::eth<0,VirtioNet>(); + inet = std::make_unique>(eth0); + inet->network_config( + {{ 10,0,0,42 }}, // IP + {{ 255,255,255,0 }}, // Netmask + {{ 10,0,0,1 }}, // Gateway + {{ 8,8,8,8 }} ); // DNS + INFO("VGA", "SUCCESS"); } From b9787642bf045609d3503817a621768aec757e77 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Fri, 11 Mar 2016 20:19:42 +0100 Subject: [PATCH 011/311] Removed default CPU arg, which breaks emulated mode --- etc/qemu_cmd.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/qemu_cmd.sh b/etc/qemu_cmd.sh index 73a7a39d01..27cc16766e 100755 --- a/etc/qemu_cmd.sh +++ b/etc/qemu_cmd.sh @@ -19,6 +19,6 @@ export qemu_ifup="$INCLUDEOS_HOME/etc/qemu-ifup" [ ! -v SERIAL ] && export SERIAL="-virtioconsole stdio" [ ! -v MEM ] && export MEM="-m 128" [ ! -v HDD ] && export HDD="-drive file=$IMAGE,format=raw,if=ide" -[ ! -v CPU ] && export CPU="-cpu host" +[ ! -v CPU ] && export CPU="" export QEMU_OPTS="$HDD $NET $GRAPHICS $SMP $MEM $CPU" From 852bd649a1f42bd28ecda4e9b26dbfdd2fe93f7e Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sat, 12 Mar 2016 17:01:42 +0100 Subject: [PATCH 012/311] Added serial port class, with read. #31 --- api/hw/serial.hpp | 90 ++++++++++++++++++++++++++++++++++++++++++++ src/hw/serial.cpp | 96 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100644 api/hw/serial.hpp create mode 100644 src/hw/serial.cpp diff --git a/api/hw/serial.hpp b/api/hw/serial.hpp new file mode 100644 index 0000000000..a5eba1ebaf --- /dev/null +++ b/api/hw/serial.hpp @@ -0,0 +1,90 @@ +// This file is a part of the IncludeOS unikernel - www.includeos.org +// +// Copyright 2015 Oslo and Akershus University College of Applied Sciences +// and Alfred Bratterud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef HW_SERIAL_HPP +#define HW_SERIAL_HPP + +//#define DEBUG + +#include +#include +#include + +namespace hw{ + + class Serial { + + public: + + /** On Data handler. Return value indicates if the buffer should be flushed **/ + using on_data_handler = delegate; + using on_string_handler = delegate; + + using irq_delg = IRQ_manager::irq_delegate; + + template + static Serial& port(){ + static Serial s{PORT}; + return s; + } + + void on_data(on_data_handler del); + void on_readline(on_string_handler del, char delim = '\r'); + + void enable_interrupt(); + void disable_interrupt(); + + char read(); + void write(char c); + int received(); + int is_transmit_empty(); + + // We don't want copies + Serial( Serial& ) = delete; + Serial( Serial&& ) = delete; + Serial& operator=(Serial&) = delete; + Serial operator=(Serial&&) = delete; + + void init(); + + private: + + Serial(int port); + static constexpr uint16_t ports_[] {0x3F8, 0x2F8, 0x3E8, 0x2E8 }; + static constexpr uint8_t irqs_[] {4, 3, 15, 15 }; + + //static const char default_newline = '\r'; + char newline = '\r'; //default_newline; + + int nr_{0}; + int port_{0}; + uint8_t irq_{4}; + std::string buf{}; + + on_data_handler on_data_ = [](char c){ debug("Default on_data: %c \n", c); }; + on_string_handler on_readline_ = [](std::string s) { (void)s; }; + + void irq_handler_ (); + void readline_handler_(char c); + }; + + + +} + + +#endif diff --git a/src/hw/serial.cpp b/src/hw/serial.cpp new file mode 100644 index 0000000000..be904e5205 --- /dev/null +++ b/src/hw/serial.cpp @@ -0,0 +1,96 @@ +#include + +#undef DEBUG + +using namespace hw; + +// Storage for port numbers +constexpr uint16_t Serial::ports_[]; + + +void Serial::init(){ + hw::outb(port_ + 1, 0x00); // Disable all interrupts + hw::outb(port_ + 3, 0x80); // Enable DLAB (set baud rate divisor) + hw::outb(port_ + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud + hw::outb(port_ + 1, 0x00); // (hi byte) + hw::outb(port_ + 3, 0x03); // 8 bits, no parity, one stop bit + hw::outb(port_ + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold + hw::outb(port_ + 4, 0x0B); // IRQs enabled, RTS/DSR set +} + +Serial::Serial(int port) : + nr_{port}, + port_{ port < 5 ? ports_[port -1] : 0 } + { + //init(); + } + +void Serial::on_data(on_data_handler del){ + enable_interrupt(); + on_data_=del; + IRQ_manager::subscribe(irq_, irq_delg::from(this) ); + INFO("Serial", "Subscribing to IRQ %i \n",irq_); +} + +void Serial::on_readline(on_string_handler del, char delim){ + newline = delim; + on_readline_ = del; + on_data(on_data_handler::from(this)); + INFO("Serial::on_readline", "Subscribing to data %i \n",irq_); +} + + +void Serial::enable_interrupt(){ + outb(port_ + 1, 0x01); + IRQ_manager::eoi(irq_); +} + +void Serial::disable_interrupt(){ + outb(port_ + 1, 0x00); +} + +char Serial::read(){ + return hw::inb(port_); +} + +void Serial::write(char c){ + while (is_transmit_empty() == 0); + hw::outb(port_, c); +} + +int Serial::received(){ + return hw::inb(port_ + 5) & 1; +} + +int Serial::is_transmit_empty() { + return hw::inb(port_ + 5) & 0x20; +} + + +void Serial::irq_handler_ () { + IRQ_manager::eoi(irq_); + + while (received()) + on_data_(read()); + +} + + +void Serial::readline_handler_ (char c) { + + if (c != newline) { + buf += c; + write(c); + return; + } + +#ifdef DEBUG + for ( auto& ch : buf ) + debug(" 0x%x | ", ch); +#endif + + // Call the event handler + on_readline_(buf); + buf.clear(); + +}; From 7d9e17bc79e67ebb77fe85746de06a8803ab4832 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sat, 12 Mar 2016 17:02:32 +0100 Subject: [PATCH 013/311] Started test program for serial class --- test/serial/Makefile | 21 +++++++++++++++++++++ test/serial/run.sh | 3 +++ test/serial/service.cpp | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 test/serial/Makefile create mode 100755 test/serial/run.sh create mode 100644 test/serial/service.cpp diff --git a/test/serial/Makefile b/test/serial/Makefile new file mode 100644 index 0000000000..9b39995ca6 --- /dev/null +++ b/test/serial/Makefile @@ -0,0 +1,21 @@ +################################################# +# IncludeOS SERVICE makefile # +################################################# + +# The name of your service +SERVICE = test_serial +SERVICE_NAME = Serial port test + +# Your service parts +FILES = service.cpp + +# Your disk image +DISK= +LOCAL_INCLUDES= + +# IncludeOS location +ifndef INCLUDEOS_INSTALL +INCLUDEOS_INSTALL=$(HOME)/IncludeOS_install +endif + +include $(INCLUDEOS_INSTALL)/Makeseed diff --git a/test/serial/run.sh b/test/serial/run.sh new file mode 100755 index 0000000000..3b2132d2cb --- /dev/null +++ b/test/serial/run.sh @@ -0,0 +1,3 @@ +#! /bin/bash +source ${INCLUDEOS_HOME-$HOME/IncludeOS_install}/etc/run.sh + diff --git a/test/serial/service.cpp b/test/serial/service.cpp new file mode 100644 index 0000000000..d6b9819e5f --- /dev/null +++ b/test/serial/service.cpp @@ -0,0 +1,39 @@ +// This file is a part of the IncludeOS unikernel - www.includeos.org +// +// Copyright 2015 Oslo and Akershus University College of Applied Sciences +// and Alfred Bratterud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +using namespace std::chrono; + +void Service::start() +{ + + auto& com1 = hw::Serial::port<1>(); + + com1.on_readline([](const std::string& s){ + printf("\nReceived: %s \n", s.c_str()); + + }); + + INFO("Serial Test","Doing some serious serial"); + + +} + + From 54efb757fec1b948a969574d2256080d41d6e2d9 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sat, 12 Mar 2016 17:05:48 +0100 Subject: [PATCH 014/311] Now using the Serial port class --- api/kernel/os.hpp | 7 +++-- src/Makefile | 4 +-- src/kernel/irq_manager.cpp | 4 +-- src/kernel/kernel_start.cpp | 58 ++----------------------------------- src/kernel/os.cpp | 49 +++++++++++++++---------------- src/seed/Makefile | 2 +- 6 files changed, 36 insertions(+), 88 deletions(-) diff --git a/api/kernel/os.hpp b/api/kernel/os.hpp index 2dcee64db7..7f64e49f4b 100644 --- a/api/kernel/os.hpp +++ b/api/kernel/os.hpp @@ -26,7 +26,8 @@ #include -#include "../hw/pit.hpp" +#include +namespace hw{ class Serial; } /** * The entrypoint for OS services @@ -60,7 +61,7 @@ class OS { static size_t rsprint(const char* ptr, const size_t len); /** - * Write a character to serial port. @todo Should be moved Dev::serial(n) + * Write a character to serial port. * * @param c: The character to print to serial port */ @@ -100,6 +101,8 @@ class OS { static rsprint_func rsprint_handler_; + static hw::Serial& com1; + // Prohibit copy and move operations OS(OS&) = delete; OS(OS&&) = delete; diff --git a/src/Makefile b/src/Makefile index 0cbbebcc7e..6fa11c5c62 100644 --- a/src/Makefile +++ b/src/Makefile @@ -42,7 +42,7 @@ ifndef AR_INC endif # Compiler options -CCOPTS = -target i686-elf -v +CCOPTS = -target i686-elf CPPOPTS = -target i686-elf INCLUDES = -I../api/sys -I$(INSTALL)/libcxx/include -I$(INC_NEWLIB) -Iinclude -I../api # @@ -63,7 +63,7 @@ OS_OBJECTS = kernel/kernel_start.o kernel/syscalls.o kernel/vga.o \ kernel/irq_manager.o kernel/pci_manager.o \ crt/c_abi.o crt/string.o crt/quick_exit.o crt/cxx_abi.o crt/mman.o \ util/memstream.o \ - hw/ide.o hw/pit.o hw/pic.o hw/pci_device.o hw/cpu_freq_sampling.o \ + hw/ide.o hw/pit.o hw/pic.o hw/pci_device.o hw/cpu_freq_sampling.o hw/serial.o\ virtio/virtio.o virtio/virtio_queue.o virtio/virtionet.o \ virtio/block.o virtio/console.o \ net/ethernet.o net/inet_common.o net/arp.o net/ip4.o \ diff --git a/src/kernel/irq_manager.cpp b/src/kernel/irq_manager.cpp index 198faba382..63878ee3a6 100644 --- a/src/kernel/irq_manager.cpp +++ b/src/kernel/irq_manager.cpp @@ -15,8 +15,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#define DEBUG // Enable debugging -#define DEBUG2 +//#define DEBUG // Enable debugging +// #define DEBUG2 #include diff --git a/src/kernel/kernel_start.cpp b/src/kernel/kernel_start.cpp index 4d775ba328..03de9092ef 100644 --- a/src/kernel/kernel_start.cpp +++ b/src/kernel/kernel_start.cpp @@ -23,14 +23,8 @@ extern "C" { - extern void _init_c_runtime(); - static void init_serial(); - -#ifdef DEBUG - static const int _test_glob = 123; - static int _test_constructor = 0; -#endif - + void _init_c_runtime(); + // enables Streaming SIMD Extensions static void enableSSE(void) { @@ -44,14 +38,6 @@ extern "C" __asm__ ("mov %eax, %cr4"); } -#ifdef DEBUG - __attribute__((constructor)) void test_constr() - { - OS::rsprint("\t * C constructor was called!\n"); - _test_constructor = 1; - } -#endif - void _start(void) { __asm__ volatile ("cli"); @@ -59,49 +45,11 @@ extern "C" // enable SSE extensions bitmask in CR4 register enableSSE(); - // init serial port - init_serial(); - // Initialize stack-unwinder, call global constructors etc. - #ifdef DEBUG - OS::rsprint("\t * Initializing C-environment... \n"); - #endif _init_c_runtime(); - FILLINE('='); - CAPTION("#include // Literally"); - FILLINE('='); - -// verify that global constructors were called -#ifdef DEBUG - assert(_test_glob == 123); - assert(_test_constructor == 1); -#endif // Initialize some OS functionality OS::start(); - - // Will only work if any destructors are called (I think?) - //_fini(); - } - - #define SERIAL_PORT 0x3f8 - void init_serial() { - hw::outb(SERIAL_PORT + 1, 0x00); // Disable all interrupts - hw::outb(SERIAL_PORT + 3, 0x80); // Enable DLAB (set baud rate divisor) - hw::outb(SERIAL_PORT + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud - hw::outb(SERIAL_PORT + 1, 0x00); // (hi byte) - hw::outb(SERIAL_PORT + 3, 0x03); // 8 bits, no parity, one stop bit - hw::outb(SERIAL_PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold - hw::outb(SERIAL_PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set - } - - int is_transmit_empty() { - return hw::inb(SERIAL_PORT + 5) & 0x20; - } - - void write_serial(char a) { - while (is_transmit_empty() == 0); - - hw::outb(SERIAL_PORT, a); + } } diff --git a/src/kernel/os.cpp b/src/kernel/os.cpp index dbd3cadd1b..e4c31c920e 100644 --- a/src/kernel/os.cpp +++ b/src/kernel/os.cpp @@ -21,23 +21,32 @@ #include #include #include - #include -// A private class to handle IRQ #include +#include #include #include bool OS::power_ {true}; -MHz OS::cpu_mhz_ {0}; +MHz OS::cpu_mhz_ {1000}; // Set default rsprint_handler OS::rsprint_func OS::rsprint_handler_ = &OS::default_rsprint; +hw::Serial& OS::com1 = hw::Serial::port<1>(); extern "C" uint16_t _cpu_sampling_freq_divider_; void OS::start() { + + // Initialize serial port + com1.init(); + + // Print a fancy header + FILLINE('='); + CAPTION("#include // Literally\n"); + FILLINE('='); + debug("\t[*] OS class started\n"); srand(time(NULL)); @@ -48,21 +57,17 @@ void OS::start() { MYINFO("Heap start: @ %p", heap_end); MYINFO("Current end is: @ %p", &_end); - // OS::rsprint("\t[*] IRQ handler\n"); - - asm("cli"); - + // Set up interrupt handlers IRQ_manager::init(); - + // Initialize the Interval Timer hw::PIT::init(); // Initialize PCI devices PCI_manager::init(); - - asm("sti"); - + /** Estimate CPU frequency + MYINFO("Estimating CPU-frequency"); INFO2("|"); INFO2("+--(10 samples, %f sec. interval)", @@ -70,10 +75,12 @@ void OS::start() { INFO2("|"); // TODO: Debug why actual measurments sometimes causes problems. Issue #246. - cpu_mhz_ = MHz(2200); //hw::PIT::CPUFrequency(); + cpu_mhz_ = hw::PIT::CPUFrequency(); INFO2("+--> %f MHz", cpu_mhz_.count()); - + + **/ + MYINFO("Starting %s", Service::name().c_str()); FILLINE('='); @@ -109,7 +116,7 @@ void OS::event_loop() { size_t OS::rsprint(const char* str) { size_t len = 0; - // Measure length + // Measure length while (str[len++]); // Output callback @@ -118,22 +125,12 @@ size_t OS::rsprint(const char* str) { } size_t OS::rsprint(const char* str, const size_t len) { - // Output callback OS::rsprint_handler_(str, len); - return len; -} - -/* STEAL: Print to serial port 0x3F8 */ -void OS::rswrite(const char c) { - /* Wait for the previous character to be sent */ - while ((hw::inb(0x3FD) & 0x20) != 0x20); - - /* Send the character */ - hw::outb(0x3F8, c); + return len; } void OS::default_rsprint(const char* str, size_t len) { for(size_t i = 0; i < len; ++i) - rswrite(str[i]); + com1.write(str[i]); } diff --git a/src/seed/Makefile b/src/seed/Makefile index b467af8fa2..2ec66c6419 100644 --- a/src/seed/Makefile +++ b/src/seed/Makefile @@ -82,7 +82,7 @@ stripped: service # The same, but with debugging symbols (OBS: Dramatically increases binary size) debug: CCOPTS += $(DEBUG_OPTS) debug: CPPOPTS += $(DEBUG_OPTS) -debug: LDOPTS += -M --verbose +#debug: LDOPTS += -M --verbose debug: OBJS += $(LIBG_OBJ) debug: service #Don't wanna call 'all', since it strips debug info From 9b470e39abae5e80e6841567dc29360174ca6cef Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sat, 12 Mar 2016 19:28:34 +0100 Subject: [PATCH 015/311] Unused lambda param cast to void --- api/hw/serial.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/hw/serial.hpp b/api/hw/serial.hpp index a5eba1ebaf..8435eb1bea 100644 --- a/api/hw/serial.hpp +++ b/api/hw/serial.hpp @@ -75,8 +75,8 @@ namespace hw{ uint8_t irq_{4}; std::string buf{}; - on_data_handler on_data_ = [](char c){ debug("Default on_data: %c \n", c); }; - on_string_handler on_readline_ = [](std::string s) { (void)s; }; + on_data_handler on_data_ = [](char c){ debug("Default on_data: %c \n", c); (void)c; }; + on_string_handler on_readline_ {}= [](std::string s) { (void)s; }; void irq_handler_ (); void readline_handler_(char c); From 42097c5dbd9ae1e5f355c7115aa5ea5e136f6664 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Sun, 13 Mar 2016 11:52:15 +0100 Subject: [PATCH 016/311] vga: Working on reproducing bug --- api/kernel/vga.hpp | 2 +- test/vga/run.sh | 2 +- test/vga/test.sh | 2 +- test/vga/vga.cpp | 5 +++++ 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/api/kernel/vga.hpp b/api/kernel/vga.hpp index ff64d37a5d..68ca52896b 100644 --- a/api/kernel/vga.hpp +++ b/api/kernel/vga.hpp @@ -55,7 +55,7 @@ class ConsoleVGA { static const size_t VGA_WIDTH {80}; static const size_t VGA_HEIGHT {25}; -private: +public: void write(char) noexcept; void putEntryAt(const char, const uint8_t, const size_t, const size_t) noexcept; void putEntryAt(const char, const size_t, const size_t) noexcept; diff --git a/test/vga/run.sh b/test/vga/run.sh index 3b2132d2cb..587d9bcf8a 100755 --- a/test/vga/run.sh +++ b/test/vga/run.sh @@ -1,3 +1,3 @@ #! /bin/bash +export DEV_GRAPHICS="-vga std" source ${INCLUDEOS_HOME-$HOME/IncludeOS_install}/etc/run.sh - diff --git a/test/vga/test.sh b/test/vga/test.sh index 6cc38ed71d..abfb1f6c33 100755 --- a/test/vga/test.sh +++ b/test/vga/test.sh @@ -1,7 +1,7 @@ #!/bin/bash source ../test_base -export QEMU_EXTRA="-vga cirrus" +export DEV_GRAPHICS="-vga std" make SERVICE=Test FILES=vga.cpp start Test.img "VGA: Verify that the service starts test" make SERVICE=Test FILES=vga.cpp clean diff --git a/test/vga/vga.cpp b/test/vga/vga.cpp index 43e1425b07..0b115b77e9 100644 --- a/test/vga/vga.cpp +++ b/test/vga/vga.cpp @@ -45,5 +45,10 @@ void Service::start() {{ 10,0,0,1 }}, // Gateway {{ 8,8,8,8 }} ); // DNS + for (int i = 0; i < 10000; i++) + { + printf("0123456789! \t0123456789! \t0123456789! \t0123456789! \t0123456789! \t0123456789! \t0123456789! \t0123456789! \n"); + } + INFO("VGA", "SUCCESS"); } From 2070083c9d63603517d9f77ebd93e4e3716731c2 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Sun, 13 Mar 2016 15:05:27 +0100 Subject: [PATCH 017/311] vga: Initialize and clear entries properly --- api/kernel/vga.hpp | 5 ++++- src/kernel/vga.cpp | 33 ++++++++++++++--------------- test/vga/vga.cpp | 53 +++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 70 insertions(+), 21 deletions(-) diff --git a/api/kernel/vga.hpp b/api/kernel/vga.hpp index 68ca52896b..b04cd285fe 100644 --- a/api/kernel/vga.hpp +++ b/api/kernel/vga.hpp @@ -55,13 +55,16 @@ class ConsoleVGA { static const size_t VGA_WIDTH {80}; static const size_t VGA_HEIGHT {25}; -public: void write(char) noexcept; void putEntryAt(const char, const uint8_t, const size_t, const size_t) noexcept; void putEntryAt(const char, const size_t, const size_t) noexcept; void increment(int) noexcept; void newline() noexcept; +private: + static const uint16_t DEFAULT_ENTRY; + void put(uint16_t, size_t, size_t) noexcept; + size_t row; size_t column; uint8_t color; diff --git a/src/kernel/vga.cpp b/src/kernel/vga.cpp index b54004195d..c2c6ee9988 100644 --- a/src/kernel/vga.cpp +++ b/src/kernel/vga.cpp @@ -15,17 +15,17 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include #include - #include -#include - static uint16_t make_vgaentry(const char c, const uint8_t color) noexcept { - uint16_t c16 {static_cast(c)}; - uint16_t color16 {static_cast(color)}; + uint16_t c16 = c; + uint16_t color16 = color; return c16 | color16 << 8; } +const uint16_t ConsoleVGA::DEFAULT_ENTRY = + make_vgaentry(32, make_color(COLOR_LIGHT_GREY, COLOR_BLACK)); ConsoleVGA::ConsoleVGA() noexcept: row{0}, column{0} @@ -40,13 +40,16 @@ void ConsoleVGA::setColor(const uint8_t color) noexcept { } void ConsoleVGA::putEntryAt(const char c, const uint8_t color, const size_t x, const size_t y) noexcept { - const size_t index {(y * VGA_WIDTH) + x}; - this->buffer[index] = make_vgaentry(c, color); + put(make_vgaentry(c, color), x, y); } void ConsoleVGA::putEntryAt(const char c, const size_t x, const size_t y) noexcept { - const size_t index {(y * VGA_WIDTH) + x}; - this->buffer[index] = make_vgaentry(c, this->color); + put(make_vgaentry(c, this->color), x, y); +} + +inline void ConsoleVGA::put(uint16_t entry, size_t x, size_t y) noexcept { + const size_t index = y * VGA_WIDTH + x; + this->buffer[index] = entry; } void ConsoleVGA::increment(const int step) noexcept { @@ -56,12 +59,9 @@ void ConsoleVGA::increment(const int step) noexcept { } } -void ConsoleVGA::newline() noexcept { - // Use whitespace to force blank the remainder of the line - while (this->column < VGA_WIDTH) { - putEntryAt(32, this->column++, this->row); - } +void ConsoleVGA::newline() noexcept { + // Reset back to left side this->column = 0; @@ -70,7 +70,6 @@ void ConsoleVGA::newline() noexcept { this->row--; unsigned total {VGA_WIDTH * (VGA_HEIGHT - 1)}; - __m128i scan; // Copy rows upwards @@ -80,7 +79,7 @@ void ConsoleVGA::newline() noexcept { } // Clear out the last row - scan = _mm_set1_epi16(32); + scan = _mm_set1_epi16(DEFAULT_ENTRY); for (size_t n {0}; n < VGA_WIDTH; n += 8) { _mm_store_si128(reinterpret_cast<__m128i*>(&buffer[total + n]), scan); @@ -93,7 +92,7 @@ void ConsoleVGA::clear() noexcept { this->column = 0; for (size_t x {0}; x < (VGA_WIDTH * VGA_HEIGHT); ++x) - buffer[x] = 32; + buffer[x] = DEFAULT_ENTRY; } void ConsoleVGA::write(const char c) noexcept { diff --git a/test/vga/vga.cpp b/test/vga/vga.cpp index 0b115b77e9..5f305df7fa 100644 --- a/test/vga/vga.cpp +++ b/test/vga/vga.cpp @@ -26,6 +26,11 @@ std::unique_ptr> inet; #include ConsoleVGA vga; +static char c = '0'; +static int iterations = 0; + +using namespace std::chrono; + void Service::start() { INFO("VGA", "Running tests for VGA"); @@ -45,10 +50,52 @@ void Service::start() {{ 10,0,0,1 }}, // Gateway {{ 8,8,8,8 }} ); // DNS - for (int i = 0; i < 10000; i++) + auto test1 = [](){ + vga.putEntryAt('@',0,0); + vga.putEntryAt('@',0,24); + vga.putEntryAt('@',79,0); + vga.putEntryAt('@',79,24); + + static int row = 0; + static int col = 0; + + vga.putEntryAt(c,col % 80, row % 25); + + if (col++ % 80 == 79){ + row++; + } + + if (row % 25 == 24 and col % 80 == 79) + c++; + }; + auto test1_1 = + [] () -> bool { - printf("0123456789! \t0123456789! \t0123456789! \t0123456789! \t0123456789! \t0123456789! \t0123456789! \t0123456789! \n"); - } + if ( c >= '4') { + hw::PIT::instance().onRepeatedTimeout(5ms, + [] { + vga.newline(); + iterations++; + }, + [] { + return iterations <= 25; + }); + } + return c < '4'; + }; + + hw::PIT::instance().onRepeatedTimeout(500ms, + [] { + const int width = 40; + + char buf[width]; + for (int i = 0; i Date: Sun, 13 Mar 2016 15:08:22 +0100 Subject: [PATCH 018/311] serial: Fix build failure --- api/hw/serial.hpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/api/hw/serial.hpp b/api/hw/serial.hpp index 8435eb1bea..ae82d9440f 100644 --- a/api/hw/serial.hpp +++ b/api/hw/serial.hpp @@ -76,15 +76,12 @@ namespace hw{ std::string buf{}; on_data_handler on_data_ = [](char c){ debug("Default on_data: %c \n", c); (void)c; }; - on_string_handler on_readline_ {}= [](std::string s) { (void)s; }; - + on_string_handler on_readline_ = [](std::string s) { (void)s; }; + void irq_handler_ (); void readline_handler_(char c); }; - - } - #endif From afe14d6f044adf51bd83ec6ed4cf44dae2818a36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Sun, 13 Mar 2016 16:31:41 +0100 Subject: [PATCH 019/311] tcp: added support for options + impl options in RFC 793 --- api/net/tcp.hpp | 149 ++++++++++++++++++++++++++++-- src/net/tcp.cpp | 9 +- src/net/tcp_connection.cpp | 84 ++++++++++++++++- src/net/tcp_connection_states.cpp | 19 +++- 4 files changed, 243 insertions(+), 18 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index dbf9bfdbe8..7a0d49594f 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -38,8 +38,13 @@ class TCP { A Sequence number (SYN/ACK) (32 bits) */ using Seq = uint32_t; + class Packet; using Packet_ptr = std::shared_ptr; + + class TCPException; + class TCPBadOptionException; + class Connection; using Connection_ptr = std::shared_ptr; using IPStack = Inet; @@ -109,6 +114,8 @@ class TCP { static constexpr uint16_t default_window_size = 0xffff; + static constexpr uint16_t default_mss = 536; + /* Flags (Control bits) in the TCP Header. */ @@ -163,7 +170,7 @@ class TCP { uint16_t window_size; // Window size uint16_t checksum; // Checksum uint16_t urgent; // Urgent pointer offset - uint32_t options[0]; // Options + uint8_t options[0]; // Options }__attribute__((packed)); // << struct TCP::Header @@ -195,6 +202,47 @@ class TCP { TCP::Header tcp; }__attribute__((packed)); + /* + TCP Header Option + */ + struct Option { + uint8_t kind; + uint8_t length; + uint8_t data[0]; + + enum Kind { + END = 0x00, // End of option list + NOP = 0x01, // No-Opeartion + MSS = 0x02, // Maximum Segment Size [RFC 793] Rev: [879, 6691] + }; + + static std::string kind_string(Kind kind) { + switch(kind) { + case MSS: + return {"MSS"}; + + default: + return {"Unknown Option"}; + } + } + + struct opt_mss { + uint8_t kind; + uint8_t length; + uint16_t mss; + + opt_mss(uint16_t mss) + : kind(MSS), length(4), mss(htons(mss)) {} + }; + + struct opt_timestamp { + uint8_t kind; + uint8_t length; + uint32_t ts_val; + uint32_t ts_ecr; + }; + }; + /* A Wrapper for a TCP Packet. Is everything as a IP4 Packet, @@ -332,10 +380,33 @@ class TCP { inline uint16_t tcp_length() const { return header_size() + data_length(); } - + template + inline void add_option(Args&&... args) { + // to avoid headache, options need to be added BEFORE any data. + assert(!has_data()); + // option address + auto* addr = options()+options_length(); + new (addr) T(args...); + // update offset + set_offset(offset() + ( ((T*)addr)->length / 4) ); + set_length(); // update + } + + inline void clear_options() { + // clear existing options + // move data (if any) (??) + set_offset(5); + set_length(); // update + } + + inline uint8_t* options() { return (uint8_t*) header().options; } + + inline uint8_t options_length() const { return header_size() - sizeof(TCP::Header); } + + inline bool has_options() const { return options_length() > 0; } // sets the correct length for all the protocols up to IP4 - void set_length(uint16_t newlen) { + void set_length(uint16_t newlen = 0) { // new total packet length set_size( all_headers_len() + newlen ); } @@ -356,7 +427,8 @@ class TCP { inline std::string to_string() { std::ostringstream os; os << "[ S:" << source().to_string() << " D:" << destination().to_string() - << " SEQ:" << seq() << " ACK:" << ack() << " HEAD-LEN:" << (int)header_size() <<" DATA-LEN:" << data_length() + << " SEQ:" << seq() << " ACK:" << ack() + << " HEAD-LEN:" << (int)header_size() << " OPT-LEN:" << (int)options_length() << " DATA-LEN:" << data_length() << " WIN:" << win() << " FLAGS:" << std::bitset<8>{header().offset_flags.flags} << " ]"; return os.str(); } @@ -364,11 +436,26 @@ class TCP { }; // << class TCP::Packet /* - TODO: Implement. + TODO: Does this need to be better? (faster? stronger?) */ class TCPException : public std::runtime_error { public: - TCPException(std::string error) : std::runtime_error(error) {}; + TCPException(const std::string& error) : std::runtime_error(error) {}; + virtual ~TCPException() {}; + }; + + /* + Exception for Bad TCP Header Option (TCP::Option) + */ + class TCPBadOptionException : public TCPException { + public: + TCPBadOptionException(Option::Kind kind, const std::string& error) : + TCPException("Bad Option [" + Option::kind_string(kind) + "]: " + error), + kind_(kind) {}; + + Option::Kind kind(); + private: + Option::Kind kind_; }; /* @@ -604,6 +691,8 @@ class TCP { uint16_t UP; // send urgent pointer TCP::Seq WL1; // segment sequence number used for last window update TCP::Seq WL2; // segment acknowledgment number used for last window update + + uint16_t MSS; // Maximum segment size for outgoing segments. } SND; // << TCP::Seq ISS; // initial send sequence number @@ -616,7 +705,7 @@ class TCP { TCP::Seq IRS; // initial receive sequence number TCB() { - SND = { 0, 0, TCP::default_window_size, 0, 0, 0 }; + SND = { 0, 0, TCP::default_window_size, 0, 0, 0, TCP::default_mss }; ISS = 0; RCV = { 0, TCP::default_window_size, 0 }; IRS = 0; @@ -771,6 +860,7 @@ class TCP { /* Calculates and return bytes transmitted. + TODO: Not sure if this will suffice. */ inline uint32_t bytes_transmitted() const { return control_block.SND.NXT - control_block.ISS; @@ -778,6 +868,7 @@ class TCP { /* Calculates and return bytes received. + TODO: Not sure if this will suffice. */ inline uint32_t bytes_received() const { return control_block.RCV.NXT - control_block.IRS; @@ -1020,11 +1111,37 @@ class TCP { */ //std::chrono::milliseconds RTT() const; std::chrono::milliseconds RTO() const; - + + /* + Start the time wait timeout for 2*MSL + */ void start_time_wait_timeout(); + /* + Tell the host (TCP) to delete this connection. + */ void signal_close(); + + /// OPTIONS /// + /* + Maximum Segment Data Size + (Limit the size for outgoing packets) + */ + inline uint16_t MSDS() const { + return std::min(host_.MSS(), control_block.SND.MSS); + } + + /* + Parse and apply options. + */ + void parse_options(TCP::Packet_ptr); + + /* + Add an option. + */ + void add_option(TCP::Option::Kind, TCP::Packet_ptr); + }; // < class TCP::Connection @@ -1110,6 +1227,22 @@ class TCP { MAX_BUFFER_SIZE = buffer_limit; } + /* + Maximum Segment Size + [RFC 793] [RFC 879] [RFC 6691] + + @NOTE: Currently not supporting MTU bigger than 1482 bytes. + */ + inline uint16_t MSS() const { + /* + VirtulaBox "issue": + MTU > 1498 will break TCP. + MTU > 1482 seems to cause fragmentation: https://www.virtualbox.org/ticket/13967 + */ + const uint16_t VBOX_LIMIT = 1482; + return std::min(inet_.MTU(), VBOX_LIMIT) - sizeof(Full_header::ip4) - sizeof(TCP::Header); + } + /* Show all connections for TCP as a string. */ diff --git a/src/net/tcp.cpp b/src/net/tcp.cpp index af329e5461..adfe3165e5 100644 --- a/src/net/tcp.cpp +++ b/src/net/tcp.cpp @@ -174,8 +174,7 @@ void TCP::bottom(net::Packet_ptr packet_ptr) { // Set remote connection->set_remote(packet->source()); debug(" ... Creating connection: %s \n", connection->to_string().c_str()); - // Change to listening state. - //connection.open(); // already listening + connection->receive(packet); } // No listener found @@ -190,6 +189,8 @@ void TCP::bottom(net::Packet_ptr packet_ptr) { Format: [Protocol][Recv][Send][Local][Remote][State] + + TODO: Make sure Recv, Send, In, Out is correct and add them to output. Also, alignment? */ string TCP::status() const { // Write all connections in a cute list. @@ -203,7 +204,7 @@ string TCP::status() const { auto& c = *(con_it.second); ss << "tcp4\t" << " " << "\t" << " " << "\t" - << c.bytes_received() << "\t" << c.bytes_transmitted() << "\t" + << " " << "\t" << " " << "\t" << c.local().to_string() << "\t\t" << c.remote().to_string() << "\t\t" << c.state().to_string() << "\n"; } @@ -237,4 +238,4 @@ void TCP::transmit(TCP::Packet_ptr packet) { packet->set_checksum(TCP::checksum(packet)); //packet->set_checksum(checksum(packet)); _network_layer_out(packet); -} +} \ No newline at end of file diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index 32e56725bf..c7fc2b70e6 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -137,11 +137,15 @@ size_t Connection::write_to_send_buffer(const char* buffer, size_t n, bool PUSH) size_t remaining{n}; do { auto packet = create_outgoing_packet(); - size_t written = packet->set_seq(control_block.SND.NXT).set_ack(control_block.RCV.NXT).set_flag(ACK).fill(buffer + (n-remaining), remaining); + packet->set_seq(control_block.SND.NXT).set_ack(control_block.RCV.NXT).set_flag(ACK); + // calculate how much the packet can be filled with + auto packet_limit = (uint32_t)MSDS() - packet->header_size(); + size_t written = packet->fill(buffer + (n-remaining), std::min(packet_limit, remaining)); bytes_written += written; remaining -= written; - debug(" Written: %u - Remaining: %u \n", written, remaining); + debug2(" Packet Limit: %u - Written: %u - Remaining: %u\n", + packet_limit, written, remaining); // If last packet, add PUSH. if(!remaining and PUSH) @@ -191,10 +195,22 @@ string Connection::to_string() const { Where the magic happens. */ void Connection::receive(TCP::Packet_ptr incoming) { - // Let state handle what to do when incoming packet arrives, and modify the outgoing packet. + signal_packet_received(incoming); - // Change window accordingly. + + if(incoming->has_options()) { + try { + parse_options(incoming); + } + catch(TCPBadOptionException err) { + printf(" %s \n", err.what()); + } + } + + // Change window accordingly. TODO: Not sure if this is how you do it. control_block.SND.WND = incoming->win(); + + // Let state handle what to do when incoming packet arrives, and modify the outgoing packet. switch(state_->handle(*this, incoming)) { case State::OK: { // Do nothing. @@ -363,3 +379,63 @@ std::string Connection::TCB::to_string() const { << " IRS = " << IRS; return os.str(); } + +void Connection::parse_options(TCP::Packet_ptr packet) { + assert(packet->has_options()); + debug(" Parsing options. Offset: %u, Options: %u \n", + packet->offset(), packet->options_length()); + + auto* opt = packet->options(); + + while((char*)opt < packet->data()) { + + auto* option = (TCP::Option*)opt; + + switch(option->kind) { + + case Option::END: { + return; + } + + case Option::NOP: { + opt++; + break; + } + + case Option::MSS: { + // unlikely + if(option->length != 4) + throw TCPBadOptionException{Option::MSS, "length != 4"}; + // unlikely + if(!packet->isset(SYN)) + throw TCPBadOptionException{Option::MSS, "Non-SYN packet"}; + + auto* opt_mss = (Option::opt_mss*)option; + uint16_t mss = ntohs(opt_mss->mss); + control_block.SND.MSS = mss; + debug2(" MSS: %u \n", mss); + opt += option->length; + break; + } + + default: + return; + } + } +} + +void Connection::add_option(TCP::Option::Kind kind, TCP::Packet_ptr packet) { + + switch(kind) { + + case Option::MSS: { + packet->add_option(host_.MSS()); + debug2(" Packet: %s - MSS: %u\n", + packet->to_string().c_str(), ntohs(*(uint16_t*)(packet->options()+2))); + break; + } + default: + break; + } +} + diff --git a/src/net/tcp_connection_states.cpp b/src/net/tcp_connection_states.cpp index 355a1406dd..532444b064 100644 --- a/src/net/tcp_connection_states.cpp +++ b/src/net/tcp_connection_states.cpp @@ -377,7 +377,14 @@ void Connection::Closed::open(Connection& tcp, bool active) { if(!tcp.remote().is_empty()) { auto& tcb = tcp.tcb(); tcb.ISS = tcp.generate_iss(); - tcp.outgoing_packet()->set_seq(tcb.ISS).set_flag(SYN); + auto packet = tcp.outgoing_packet(); + packet->set_seq(tcb.ISS).set_flag(SYN); + + /* + Add MSS option. + */ + tcp.add_option(Option::MSS, packet); + tcb.SND.UNA = tcb.ISS; tcb.SND.NXT = tcb.ISS+1; tcp.transmit(); @@ -482,7 +489,15 @@ State::Result Connection::Listen::handle(Connection& tcp, TCP::Packet_ptr in) { debug(" Received SYN Packet: %s TCB Updated:\n %s \n", in->to_string().c_str(), tcp.tcb().to_string().c_str()); - tcp.outgoing_packet()->set_seq(tcb.ISS).set_ack(tcb.RCV.NXT).set_flags(SYN | ACK); + auto packet = tcp.outgoing_packet(); + packet->set_seq(tcb.ISS).set_ack(tcb.RCV.NXT).set_flags(SYN | ACK); + + /* + Add MSS option. + TODO: Send even if we havent received MSS option? + */ + tcp.add_option(Option::MSS, packet); + tcp.transmit(); tcp.set_state(SynReceived::instance()); From 6ad59d414f4306d02f06145ac1f1ee6f2afd5058 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Sun, 13 Mar 2016 17:07:10 +0100 Subject: [PATCH 020/311] tcp: fixed logical division error when updating header offset --- api/net/tcp.hpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index 7a0d49594f..8502f11309 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -28,8 +28,13 @@ #include // timer duration #include // enable_shared_from_this -namespace net { +inline unsigned round_up(unsigned n, unsigned div) { + assert(n); + return (n + div - 1) / div; +} +namespace net { + class TCP { public: using Address = IP4::addr; @@ -388,7 +393,7 @@ class TCP { auto* addr = options()+options_length(); new (addr) T(args...); // update offset - set_offset(offset() + ( ((T*)addr)->length / 4) ); + set_offset(offset() + round_up( ((T*)addr)->length, 4 )); set_length(); // update } From 62c6e35e1403cc1901663213457cb867bb85d76b Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sun, 13 Mar 2016 22:23:03 +0100 Subject: [PATCH 021/311] Prettier bootscreen, no BIOS-interrupts --- src/boot/bootloader.asm | 136 +++++++++++++++++++++------------------- 1 file changed, 70 insertions(+), 66 deletions(-) diff --git a/src/boot/bootloader.asm b/src/boot/bootloader.asm index 9fc68ae4f0..9aa760d569 100644 --- a/src/boot/bootloader.asm +++ b/src/boot/bootloader.asm @@ -16,26 +16,27 @@ ;; limitations under the License. USE16 - ;; Memory layout, 16-bit - %define _boot_segment 0x7c0 +;; Memory layout, 16-bit +%define _boot_segment 0x07c0 +%define _vga_segment 0xb800 + +;; Memory layout, 32-bit +%define _mode32_code_segment 0x08 +%define _mode32_data_segment 0x10 - ;; Memory layout, 32-bit - %define _mode32_code_segment 0x08 - %define _mode32_data_segment 0x10 +%define _kernel_loc 0x200000 +%define _kernel_stack 0x200000 - %define _kernel_loc 0x200000 - %define _kernel_stack 0x200000 - - ;; We don't really need a stack, except for calls - %define _stack_segment 0x7000 - %define _stack_pointer 0xfffe ;Within the ss, for 16 bit +;; We don't really need a stack, except for calls +%define _stack_segment 0x7000 +%define _stack_pointer 0xfffe ;Within the ss, for 16 bit - ;; Char helpers - %define _CR 0x0D - %define _LF 0x0A +;; Char helpers +%define _CR 0x0D +%define _LF 0x0A - ;; ELF offset of _start in text section - %define _elf_start 0x34 +; ELF offset of _start in text section +%define _elf_start 0x34 ;;; START ;;; We'll start at the beginning, but jump over some data @@ -45,40 +46,42 @@ _start: ;;; The size of the service on disk, to be loaded at boot. (Convenient to ;;; have it at the beginning, so it remains at a fixed location. ) srv_size: - dd 0 + dd 0 srv_offs: dd 0 ;;; Actual start boot: - ;; Need to set data segment, to access strings mov ax, _boot_segment mov ds, ax + + ; fast a20 enable + in al, 0x92 + or al, 2 + out 0x92, al + + ;; Clear the screen + call fill_screen - mov esi,str_boot + ;; Print the IncludeOS logo + mov esi, str_includeos call printstr - - ; fast a20 enable - in al, 0x92 - or al, 2 - out 0x92, al + mov ax, 0x0800 + mov [color], ax + mov esi, str_literally + call printstr + ; check that it was enabled test al,0 - jz .a20_ok - + jz .a20_ok ;; NOT OK mov esi,str_a20_fail call printstr cli hlt .a20_ok: - mov esi,str_a20_ok - call printstr - - - call protected_mode protected_mode: @@ -90,49 +93,50 @@ protected_mode: mov eax,cr0 or al,1 mov cr0,eax - - ;xchg bx,bx - ;; jmp 0x8:$+3 jmp _mode32_code_segment:mode32+(_boot_segment<<4) -USE16 - - ;; %include "asm/load_os_16bit.asm" - -;;; 16-bit code -USE16 +fill_screen: + mov bx, _vga_segment + mov es, bx + mov bx, 0 + mov al, 0 + mov ah, [color] +.fill: + mov [es:bx], ax + add bx,2 + cmp bx, (25*80*2) + jge .done + jmp .fill +.done: + ret printstr: - mov ah,0eh -.repeat: + mov bx, _vga_segment + mov es, bx + mov bx, [cursor] + mov ah, [color] +.repeat: lodsb cmp al,0 je .done - int 10h + mov [es:bx], al + mov [es:bx + 1], ah + add bx, 2 jmp .repeat .done: + mov [cursor], bx ret -;;; Print the char in %al to serial port, via BIOS int. -;;; OBS: Only works in real mode. -;;; OBS: In Bochs, looks like serial port must be initialized first -print_al_serial: - xor edx,edx - mov ah,1 - int 14h - ret - -print_al_scr: - mov ah,0x0e - int 0x10 - -str_boot: - db `IncludeOS!\n\r`,0 -str_a20_ok: - db `A20 OK!\n\r`,0 -str_a20_fail: - db `A20 NOT OK\n\r`,0 - +str_includeos: + db `#include `,0 +str_literally: + db `\/\/ Literally `,0 +str_a20_fail: + db `A20 Err\n\r`,0 +cursor: + dw (80 * 11 * 2) + 48 +color: + dw 0x0d USE32 ALIGN 32 @@ -206,16 +210,16 @@ mode32: cmp edx, 0 jge .more ;; jump when gequal - ;; Bochs breakpoint + ;; Bochs breakpoint ;;xchg bx,bx ;; GERONIMO! ;; Jump to service mov ecx, [srv_offs+(_boot_segment<<4)] - jmp ecx + jmp ecx %include "boot/disk_read_lba.asm" -;; BOOT SIGNATURE + ;; BOOT SIGNATURE times 510-($-$$) db 0 ; dw 0xAA55 From 7cf9d38ef5f965fccda0cbd73686a507e1c03ef3 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sun, 13 Mar 2016 23:03:22 +0100 Subject: [PATCH 022/311] Color symbol is now 1 byte --- src/boot/bootloader.asm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/boot/bootloader.asm b/src/boot/bootloader.asm index 9aa760d569..f0cdf5fe9d 100644 --- a/src/boot/bootloader.asm +++ b/src/boot/bootloader.asm @@ -67,7 +67,7 @@ boot: ;; Print the IncludeOS logo mov esi, str_includeos call printstr - mov ax, 0x0800 + mov ax, 0x07 mov [color], ax mov esi, str_literally call printstr From 50f68be0666371fc8a6a9c81511c7bca3da5ab95 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Mon, 14 Mar 2016 00:04:40 +0100 Subject: [PATCH 023/311] More thorough (and more fun) VGA test --- api/kernel/vga.hpp | 3 ++ src/kernel/vga.cpp | 5 +++ test/vga/vga.cpp | 83 +++++++++++++++++++++++++++------------------- 3 files changed, 56 insertions(+), 35 deletions(-) diff --git a/api/kernel/vga.hpp b/api/kernel/vga.hpp index b04cd285fe..e807bed8eb 100644 --- a/api/kernel/vga.hpp +++ b/api/kernel/vga.hpp @@ -58,8 +58,11 @@ class ConsoleVGA { void write(char) noexcept; void putEntryAt(const char, const uint8_t, const size_t, const size_t) noexcept; void putEntryAt(const char, const size_t, const size_t) noexcept; + void setCursorAt(const size_t, const size_t) noexcept; void increment(int) noexcept; void newline() noexcept; + inline void set_color(vga_color c) + { color = c; }; private: static const uint16_t DEFAULT_ENTRY; diff --git a/src/kernel/vga.cpp b/src/kernel/vga.cpp index c2c6ee9988..e820fc1328 100644 --- a/src/kernel/vga.cpp +++ b/src/kernel/vga.cpp @@ -47,6 +47,11 @@ void ConsoleVGA::putEntryAt(const char c, const size_t x, const size_t y) noexce put(make_vgaentry(c, this->color), x, y); } +void ConsoleVGA::setCursorAt(const size_t x, const size_t y) noexcept { + this->column = x; + this->row = y; +} + inline void ConsoleVGA::put(uint16_t entry, size_t x, size_t y) noexcept { const size_t index = y * VGA_WIDTH + x; this->buffer[index] = entry; diff --git a/test/vga/vga.cpp b/test/vga/vga.cpp index 5f305df7fa..5de0de44a7 100644 --- a/test/vga/vga.cpp +++ b/test/vga/vga.cpp @@ -18,11 +18,6 @@ #include #include #include - -#include -using namespace net; -std::unique_ptr> inet; - #include ConsoleVGA vga; @@ -31,24 +26,24 @@ static int iterations = 0; using namespace std::chrono; +void write_goodbye(){ + + char msg[] = {0xd,0xe,' ','G','A','M','E',' ','O','V','E','R',' ',0xe,0xd,0}; + vga.setCursorAt(32,24); + vga.setColor(ConsoleVGA::COLOR_LIGHT_BROWN); + vga.write(msg, sizeof(msg)); + +} + void Service::start() { INFO("VGA", "Running tests for VGA"); - OS::set_rsprint( - [] (const char* data, size_t len) - { - vga.write(data, len); - }); - printf("Hello there!\n"); + OS::set_rsprint([] (const char* data, size_t len) { + vga.write(data, len); + }); - hw::Nic& eth0 = hw::Dev::eth<0,VirtioNet>(); - inet = std::make_unique>(eth0); - inet->network_config( - {{ 10,0,0,42 }}, // IP - {{ 255,255,255,0 }}, // Netmask - {{ 10,0,0,1 }}, // Gateway - {{ 8,8,8,8 }} ); // DNS + printf("Hello there!\n"); auto test1 = [](){ vga.putEntryAt('@',0,0); @@ -58,7 +53,8 @@ void Service::start() static int row = 0; static int col = 0; - + + vga.setColor(col % 256); vga.putEntryAt(c,col % 80, row % 25); if (col++ % 80 == 79){ @@ -67,35 +63,52 @@ void Service::start() if (row % 25 == 24 and col % 80 == 79) c++; - }; - auto test1_1 = - [] () -> bool + }; + + + auto test1_1 = [] () -> bool { if ( c >= '4') { - hw::PIT::instance().onRepeatedTimeout(5ms, - [] { - vga.newline(); - iterations++; - }, - [] { - return iterations <= 25; - }); + hw::PIT::instance().onRepeatedTimeout(100ms, [] { + vga.newline(); + iterations++; + if (iterations == 24) + write_goodbye(); + + }, + + [] { + return iterations < 36; + }); } return c < '4'; }; + - hw::PIT::instance().onRepeatedTimeout(500ms, - [] { + auto test2 = [](){ const int width = 40; char buf[width]; for (int i = 0; i Date: Mon, 14 Mar 2016 10:28:58 +0100 Subject: [PATCH 024/311] Custom IRQ handlers can now interact with the eventloop using , to signal that an irq callback should be called later. Also refactor. --- api/kernel/irq_manager.hpp | 19 +++++++++++--- src/kernel/irq_manager.cpp | 54 +++++++++++++++++--------------------- 2 files changed, 40 insertions(+), 33 deletions(-) diff --git a/api/kernel/irq_manager.hpp b/api/kernel/irq_manager.hpp index d712287d91..f6b262f2ea 100644 --- a/api/kernel/irq_manager.hpp +++ b/api/kernel/irq_manager.hpp @@ -86,6 +86,8 @@ class IRQ_manager { public: using irq_delegate = delegate; + static const uint8_t irq_base = 32; + /** * Enable an IRQ line * @@ -148,6 +150,14 @@ class IRQ_manager { */ static void eoi(uint8_t irq); + static inline void register_interrupt(uint8_t i){ + irq_pending_ |= (1 << i); + __sync_fetch_and_add(&irq_counters_[i],1); + debug(" IRQ %i Pending: 0x%ix. Count: %i\n", i, + irq_pending_, irq_counters_[i]); + } + + private: static unsigned int irq_mask; static int timer_interrupts; @@ -158,10 +168,12 @@ class IRQ_manager { /** bit n set means IRQ n has fired since last check */ //static irq_bitfield irq_pending; - static irq_bitfield irq_subscriptions; + static irq_bitfield irq_subscriptions_; - static void(*irq_subscribers[sizeof(irq_bitfield)*8])(); - static irq_delegate irq_delegates[sizeof(irq_bitfield)*8]; + static void(*irq_subscribers_[sizeof(irq_bitfield)*8])(); + static irq_delegate irq_delegates_[sizeof(irq_bitfield)*8]; + static uint32_t irq_counters_[32]; + static uint32_t irq_pending_; /** STI */ static void enable_interrupts(); @@ -188,6 +200,7 @@ class IRQ_manager { /** Notify all delegates waiting for interrupts */ static void notify(); + }; //< IRQ_manager #endif //< KERNEL_IRQ_MANAGER_HPP diff --git a/src/kernel/irq_manager.cpp b/src/kernel/irq_manager.cpp index 63878ee3a6..4dcb0638c7 100644 --- a/src/kernel/irq_manager.cpp +++ b/src/kernel/irq_manager.cpp @@ -16,7 +16,7 @@ // limitations under the License. //#define DEBUG // Enable debugging -// #define DEBUG2 +//#define DEBUG2 #include @@ -26,17 +26,16 @@ #include #include -const int irq_base=32; unsigned int IRQ_manager::irq_mask {0xFFFB}; IDTDescr IRQ_manager::idt[256] {}; bool IRQ_manager::idt_is_set {false}; -irq_bitfield irq_pending {0}; -irq_bitfield IRQ_manager::irq_subscriptions {0}; +irq_bitfield IRQ_manager::irq_pending_ {0}; +irq_bitfield IRQ_manager::irq_subscriptions_ {0}; -void (*IRQ_manager::irq_subscribers[sizeof(irq_bitfield)*8])() {nullptr}; -IRQ_manager::irq_delegate IRQ_manager::irq_delegates[sizeof(irq_bitfield)*8]; +void (*IRQ_manager::irq_subscribers_[sizeof(irq_bitfield)*8])() {nullptr}; +IRQ_manager::irq_delegate IRQ_manager::irq_delegates_[sizeof(irq_bitfield)*8]; void IRQ_manager::enable_interrupts() { __asm__ volatile("sti"); @@ -113,21 +112,14 @@ void exception_handler() * - Set pending flag * - Increment counter */ -static uint32_t __irqueues[256] {0}; +uint32_t IRQ_manager::irq_counters_[32] {0}; + #define IRQ_HANDLER(I) \ void irq_##I##_handler() { \ - irq_pending |= (1 << I); \ - __sync_fetch_and_add(&__irqueues[I],1); \ - debug(" IRQ %i Pending: 0x%ix. Count: %i\n", I, \ - irq_pending, __irqueues[I]); \ + IRQ_manager::register_interrupt(I); \ } -//debug(" IRQ %i. Pending: 0x%lx\n",I,irq_pending); - -// The delegates will handle EOI -// eoi(I-IRQ_BASE); - /* Macro magic to register default gates */ #define REG_DEFAULT_EXCPT(I) create_gate(&(idt[I]),exception_entry, \ default_sel, default_attr ); @@ -282,7 +274,7 @@ void (*IRQ_manager::get_handler(uint8_t irq))() { } IRQ_manager::irq_delegate IRQ_manager::get_subscriber(uint8_t irq) { - return irq_delegates[irq]; + return irq_delegates_[irq]; } void IRQ_manager::enable_irq(uint8_t irq) { @@ -302,14 +294,14 @@ void IRQ_manager::subscribe(uint8_t irq, irq_delegate del) { //void(*notify)() enable_irq(irq); // Mark IRQ as subscribed to - irq_subscriptions |= (1 << irq); + irq_subscriptions_ |= (1 << irq); // Add callback to subscriber list (for now overwriting any previous) //irq_subscribers[irq] = notify; - irq_delegates[irq] = del; + irq_delegates_[irq] = del; eoi(irq); - INFO("IRQ manager", "Updated subscriptions: %#x irq: %i", irq_subscriptions, irq); + INFO("IRQ manager", "Updated subscriptions: %#x irq: %i", irq_subscriptions_, irq); } /** Get most significant bit of b. */ @@ -323,32 +315,34 @@ void IRQ_manager::notify() { //__asm__("cli"); // Get the IRQ's that are both pending and subscribed to - irq_bitfield todo {static_cast(irq_subscriptions & irq_pending)}; + irq_bitfield todo {static_cast(irq_subscriptions_ & irq_pending_)}; int irq {0}; while (todo) { - // Select the first IRQ to notify - irq = bsr(todo); + + // Select the first IRQ to notify - the least significant bit set + // - lowesr bit/IRQ, means higher priority + irq = __builtin_ffs(todo) - 1; // Notify - debug2(" __irqueue %i Count: %i\n", irq, __irqueues[irq]); - irq_delegates[irq](); + debug2(" __irqueue %i Count: %i\n", irq, irq_counters_[irq]); + irq_delegates_[irq](); // Decrement the counter - __sync_fetch_and_sub(&__irqueues[irq], 1); + __sync_fetch_and_sub(&irq_counters_[irq], 1); // Critical section start // Spinlock? Well, we can't lock out the IRQ-handler // ... and we don't have a timer interrupt so we can't do blocking locks. - if (!__irqueues[irq]) { + if (!irq_counters_[irq]) { // Remove the IRQ from pending list - irq_pending &= ~(1 << irq); - //debug(" IRQ's pending: 0x%lx\n",irq_pending); + irq_pending_ &= ~(1 << irq); + //debug(" IRQ's pending: 0x%lx\n",irq_pending_); } // Critical section end // Find remaining IRQ's both pending and subscribed to - todo = (irq_subscriptions & irq_pending); + todo = (irq_subscriptions_ & irq_pending_); } //hlt From d74b4e4ce3c885269dcf9b578d717d0dbc512e8d Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Mon, 14 Mar 2016 13:01:54 +0100 Subject: [PATCH 025/311] Improving PIC-class to get better control --- api/hw/pic.hpp | 40 ++++++++++++++++++++++++------- api/kernel/irq_manager.hpp | 23 ++++-------------- src/hw/pic.cpp | 1 + src/hw/pit.cpp | 5 ++-- src/kernel/irq_manager.cpp | 20 +++++----------- test/IRQ_PIC/service.cpp | 49 +++++++++++++++++++++++++++++--------- 6 files changed, 82 insertions(+), 56 deletions(-) diff --git a/api/hw/pic.hpp b/api/hw/pic.hpp index ef292ffe40..5173d9b140 100644 --- a/api/hw/pic.hpp +++ b/api/hw/pic.hpp @@ -23,7 +23,7 @@ namespace hw { -class PIC { +class PIC { public: static void init() noexcept; @@ -44,10 +44,11 @@ class PIC { } inline static void eoi(const uint8_t irq) noexcept { + if (irq >= 8) { hw::outb(slave_ctrl, eoi_); } - hw::outb(master_ctrl, eoi_); + //hw::outb(master_ctrl, specific_eoi_ | (irq & 0x0f) );*/ } /* Returns the combined value of the cascaded PICs irq request register */ @@ -59,21 +60,37 @@ class PIC { { return get_irq_reg(read_isr); } private: + // ICW1 bits + static constexpr uint8_t icw1 {0x10}; // Bit 5 must always be set + static constexpr uint8_t icw1_icw4_needed {0x1}; // Prepare for cw4 or not + static constexpr uint8_t icw1_single_mode {0x2}; // Not set means cascade + static constexpr uint8_t icw1_addr_interval_4 {0x4}; // Not set means interval 8 + static constexpr uint8_t icw1_level_trigered {0x8}; // Not set means egde triggred + + // ICW2 bits: Interrupt number for first IRQ + // ICW3 bits: Location of slave PIC + // ICW4 bits: + static constexpr uint8_t icw4_8086_mode {0x1}; // Not set means aincient runes + static constexpr uint8_t icw4_auto_eoi {0x2}; // Switch between auto / normal EOI + static constexpr uint8_t icw4_buffered_mode_slave {0x08}; + static constexpr uint8_t icw4_buffered_mode_master {0x12}; + + // Registers addresses static const uint8_t master_ctrl {0x20}; static const uint8_t master_mask {0x21}; static const uint8_t slave_ctrl {0xA0}; static const uint8_t slave_mask {0xA1}; // Master commands - static const uint8_t master_icw1 {0x11}; - static const uint8_t master_icw2 {0x20}; - static const uint8_t master_icw3 {0x04}; - static const uint8_t master_icw4 {0x01}; + static const uint8_t master_icw1 {0x11}; // icw4 needed (bit1), bit5 always on + static const uint8_t master_icw2 {32}; // Remap + static const uint8_t master_icw3 {0x04}; // Location of slave + static const uint8_t master_icw4 {0x03}; // 8086-mode (bit1), Auto-EOI (bit2) // Slave commands static const uint8_t slave_icw1 {0x11}; - static const uint8_t slave_icw2 {0x28}; - static const uint8_t slave_icw3 {0x02}; + static const uint8_t slave_icw2 {40}; + static const uint8_t slave_icw3 {0x02}; // Slave ID static const uint8_t slave_icw4 {0x01}; /* IRQ ready next CMD read */ @@ -81,7 +98,12 @@ class PIC { /* IRQ service next CMD read */ static const uint8_t read_isr {0x0B}; - static const uint8_t eoi_ {0x20}; + + static constexpr uint8_t ocw2_eoi = 0x20; + static constexpr uint8_t ocw2_specific = 0x40; + + static constexpr uint8_t eoi_ { ocw2_eoi }; + static constexpr uint8_t specific_eoi_ { ocw2_eoi | ocw2_specific }; static uint16_t irq_mask_; diff --git a/api/kernel/irq_manager.hpp b/api/kernel/irq_manager.hpp index f6b262f2ea..f733ce9c62 100644 --- a/api/kernel/irq_manager.hpp +++ b/api/kernel/irq_manager.hpp @@ -23,23 +23,6 @@ #include "os.hpp" #include "../hw/pic.hpp" -// IDT Type flags - -// Bits 0-3, "type" (VALUES) -const char TRAP_GATE {0xf}; -const char TASK_GATE {0x5}; -const char INT_GATE {0xe}; - -// Bit 4, "Storage segment" (BIT NUMBER) -const char BIT_STOR_SEG {0x10}; //=0 for trap gates - -//Bits 5-6, "Protection level" (BIT NUMBER) -const char BIT_DPL1 {0x20}; -const char BIT_DPL2 {0x40}; - -//Bit 7, "Present" (BIT NUMBER) -const char BIT_PRESENT {static_cast(0x80)}; - // From osdev struct IDTDescr { uint16_t offset_1; // offset bits 0..15 @@ -86,7 +69,9 @@ class IRQ_manager { public: using irq_delegate = delegate; - static const uint8_t irq_base = 32; + static constexpr uint8_t irq_base = 32; + static constexpr uint8_t irq_lines = 64; + /** * Enable an IRQ line @@ -161,7 +146,7 @@ class IRQ_manager { private: static unsigned int irq_mask; static int timer_interrupts; - static IDTDescr idt[256]; + static IDTDescr idt[irq_lines]; static const char default_attr {static_cast(0x8e)}; static const uint16_t default_sel {0x8}; static bool idt_is_set; diff --git a/src/hw/pic.cpp b/src/hw/pic.cpp index 3df746d7fa..2657b8c7f1 100644 --- a/src/hw/pic.cpp +++ b/src/hw/pic.cpp @@ -35,4 +35,5 @@ void PIC::init() noexcept { set_intr_mask(irq_mask_); } + } //< namespace hw diff --git a/src/hw/pit.cpp b/src/hw/pit.cpp index efbb8ae282..cbb26c65f1 100644 --- a/src/hw/pit.cpp +++ b/src/hw/pit.cpp @@ -175,6 +175,8 @@ uint8_t PIT::read_back(uint8_t){ } void PIT::irq_handler(){ + // All IRQ-handlers has to send EOI + IRQ_manager::eoi(0); IRQ_counter_ ++; @@ -238,9 +240,6 @@ void PIT::irq_handler(){ debug2("\n---------------------------\n\n"); } - // All IRQ-handlers has to send EOI - IRQ_manager::eoi(0); - } void PIT::init(){ diff --git a/src/kernel/irq_manager.cpp b/src/kernel/irq_manager.cpp index 4dcb0638c7..a094de5ae9 100644 --- a/src/kernel/irq_manager.cpp +++ b/src/kernel/irq_manager.cpp @@ -28,7 +28,7 @@ unsigned int IRQ_manager::irq_mask {0xFFFB}; -IDTDescr IRQ_manager::idt[256] {}; +IDTDescr IRQ_manager::idt[irq_lines] {}; bool IRQ_manager::idt_is_set {false}; irq_bitfield IRQ_manager::irq_pending_ {0}; @@ -142,8 +142,6 @@ uint32_t IRQ_manager::irq_counters_[32] {0}; */ extern "C"{ void _irq_20_entry(int i); - //Array of custom IRQ-handlers - void (*custom_handlers[256])(); void irq_default_handler(); void irq_default_entry(); @@ -186,7 +184,7 @@ void IRQ_manager::init() //Create an idt entry for the 'lidt' instruction idt_loc idt_reg; - idt_reg.limit = (256*sizeof(IDTDescr))-1; + idt_reg.limit = (irq_lines*sizeof(IDTDescr))-1; idt_reg.base = (uint32_t)idt; INFO("IRQ manager", "Creating interrupt handlers"); @@ -201,6 +199,7 @@ void IRQ_manager::init() REG_DEFAULT_EXCPT(18) REG_DEFAULT_EXCPT(19) REG_DEFAULT_EXCPT(20) // GATES 21-29 are reserved REG_DEFAULT_EXCPT(30) REG_DEFAULT_EXCPT(31) + INFO2("+ Exception gates set for irq < 32"); //Redirected IRQ 0 - 15 REG_DEFAULT_IRQ(0) REG_DEFAULT_IRQ(1) REG_DEFAULT_IRQ(3) @@ -208,17 +207,13 @@ void IRQ_manager::init() REG_DEFAULT_IRQ(7) REG_DEFAULT_IRQ(8) REG_DEFAULT_IRQ(9) REG_DEFAULT_IRQ(10) REG_DEFAULT_IRQ(11) REG_DEFAULT_IRQ(12) REG_DEFAULT_IRQ(13) REG_DEFAULT_IRQ(14) REG_DEFAULT_IRQ(15) - - // Default gates for "real IRQ lines", 32-64 - INFO2("+ Exception gates set for irq < 32"); - - //Set all irq-gates (>= 44) to the default handler - for(int i=48;i<256;i++){ + + //Set all irq-gates (> 47) to the default handler + for(int i=48;i= 32"); - //Load IDT __asm__ volatile ("lidt %0": :"m"(idt_reg) ); @@ -227,9 +222,6 @@ void IRQ_manager::init() enable_irq(2); //Slave PIC irq enable_interrupts(); - - //Test zero-division exception - //int i=0; float x=1/i; printf("ERROR: 1/0 == %f \n",x); } // A union to be able to extract the lower and upper part of an address diff --git a/test/IRQ_PIC/service.cpp b/test/IRQ_PIC/service.cpp index 310062f86b..5effebd1ff 100644 --- a/test/IRQ_PIC/service.cpp +++ b/test/IRQ_PIC/service.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -37,24 +38,26 @@ std::unique_ptr > inet; **/ void Service::start() { - + + // Serial + auto& com1 = hw::Serial::port<1>(); + + // Timers auto& time = hw::PIT::instance(); - - // Write something in half a second - - // Assign an IP-address, using Hårek-mapping :-) + + // Network auto& eth0 = hw::Dev::eth<0,VirtioNet>(); auto& mac = eth0.mac(); auto& inet = *new net::Inet4(eth0, // Device {{ mac.part[2],mac.part[3],mac.part[4],mac.part[5] }}, // IP {{ 255,255,0,0 }} ); // Netmask - + printf("Service IP address: %s \n", inet.ip_addr().str().c_str()); // UDP UDP::port_t port = 4242; auto& sock = inet.udp().bind(port); - + sock.onRead([] (UDP::Socket& conn, UDP::addr_t addr, UDP::port_t port, const char* data, int len) -> int { printf("Getting UDP data from %s: %i: %s\n", @@ -104,11 +107,35 @@ void Service::start() // Halting could/should be used in this test // asm("hlt"); - + + com1.on_readline([](std::string str){ + cout << "\nGot string: " << str << "\n"; + cout << "But if we get another IRQ, which we don't handle: trouble\n"; + cout << "Now send a UDP-package\n"; + + }); + + /* + IRQ_manager::subscribe(4, [](){ + IRQ_manager::eoi(4); + INFO("IRQ","Serial port IRQ\n"); + }); + */ + + /* + IRQ_manager::subscribe(11,[](){ + // Calling eoi here will turn the IRQ line on and loop forever. + IRQ_manager::eoi(11); + INFO("IRQ","Network IRQ\n"); + }); + */ + // Enabling a timer causes freeze in debug mode, for some reason - time.onTimeout(1s, [](){ printf("One second passed...\n"); }); - time.onTimeout(2s, [](){ printf("Two seconds passed...\n"); }); - time.onTimeout(5s, [](){ printf("Five seconds passed...\n"); }); + time.onRepeatedTimeout(1s, [](){ + printf("Time \n"); + + }); + INFO("IRQ test","Expect IRQ subscribers to get called now "); } From 52e6ff3974866342dfd5a9a7559238bac5829f2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Mon, 14 Mar 2016 14:49:10 +0100 Subject: [PATCH 026/311] build/osx: added warning about missing xcode ctl --- etc/install_osx.sh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/etc/install_osx.sh b/etc/install_osx.sh index ce49a09584..606c8ce08e 100755 --- a/etc/install_osx.sh +++ b/etc/install_osx.sh @@ -25,7 +25,8 @@ echo -e "###################################" echo -e "\n# Prequisites:\n - homebrew (OSX package manager - https://brew.sh) - \`/usr/local\` directory with write access - - \`/usr/local/bin\` added to your PATH" + - \`/usr/local/bin\` added to your PATH + - (Recommended) XCode CTL (Command Line Tools)" ### DEPENDENCIES ### @@ -130,6 +131,12 @@ function install_nasm { echo -e "\n>>> Done installing: nasm" } +## WARN ABOUT XCODE CTL ## +if ! [[ $(xcode-select -p) ]] +then + echo -e "\nWARNING: Command Line Tools don't seem to be installed, installation MAY not complete. + Install with: xcode-select --install" +fi ### INSTALL ### echo From 74763b0b93dbffbe0720f117803541a90133be2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Mon, 14 Mar 2016 15:43:07 +0100 Subject: [PATCH 027/311] tcp: replaced disconnect string with Disconnect object --- api/net/tcp.hpp | 43 ++++++++++++++++++++++++++++--- examples/demo_service/service.cpp | 4 +-- examples/tcp/service.cpp | 9 ++++--- src/net/tcp_connection_states.cpp | 14 +++++----- test/tcp/service.cpp | 4 +-- 5 files changed, 56 insertions(+), 18 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index 8502f11309..de585587be 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -563,7 +563,9 @@ class TCP { On disconnect - When a remote told it wanna close the connection. Connection has received a FIN, currently last thing that will happen before a connection is remoed. */ - using DisconnectCallback = delegate, std::string)>; + struct Disconnect; + + using DisconnectCallback = delegate, Disconnect)>; /* On error - When any of the users request fails. @@ -588,6 +590,41 @@ class TCP { */ using Buffer = PacketBuffer<>; + /* + Reason for disconnect event. + */ + struct Disconnect { + public: + enum Reason { + CLOSING, + REFUSED, + RESET + }; + + Reason reason; + + explicit Disconnect(Reason reason) : reason(reason) {} + + inline operator Reason() const noexcept { return reason; } + + inline operator std::string() const noexcept { return to_string(); } + + inline bool operator ==(const Disconnect& dc) const { return reason == dc.reason; } + + std::string to_string() const { + switch(reason) { + case CLOSING: + return "Connection closing"; + case REFUSED: + return "Conneciton refused"; + case RESET: + return "Connection reset"; + default: + return "Unknown reason"; + } + } + }; // < struct TCP::Connection::Disconnect + /* Interface for one of the many states a Connection can have. */ @@ -994,7 +1031,7 @@ class TCP { }; /* When Connection is CLOSING. */ - DisconnectCallback on_disconnect_ = [](std::shared_ptr, std::string) { + DisconnectCallback on_disconnect_ = [](std::shared_ptr, Disconnect) { //debug2(" Connection disconnect. Reason: %s \n", msg.c_str()); }; @@ -1024,7 +1061,7 @@ class TCP { inline void signal_receive(bool PUSH) { on_receive_(shared_from_this(), PUSH); } - inline void signal_disconnect(std::string message) { on_disconnect_(shared_from_this(), message); } + inline void signal_disconnect(Disconnect::Reason&& reason) { on_disconnect_(shared_from_this(), Disconnect{reason}); } inline void signal_error(TCPException error) { on_error_(shared_from_this(), error); } diff --git a/examples/demo_service/service.cpp b/examples/demo_service/service.cpp index a05b54f26d..9406e3a53a 100644 --- a/examples/demo_service/service.cpp +++ b/examples/demo_service/service.cpp @@ -95,8 +95,8 @@ void Service::start() { std::string output{header + html}; conn->write(output.data(), output.size()); - }).onDisconnect([](auto conn, std::string msg) { - printf(" @onDisconnect - Reason: %s \n", msg.c_str()); + }).onDisconnect([](auto conn, auto reason) { + printf(" @onDisconnect - Reason: %s \n", reason.to_string().c_str()); printf(" TCP STATUS:\n%s \n", conn->host().status().c_str()); }); diff --git a/examples/tcp/service.cpp b/examples/tcp/service.cpp index 48dc5a754c..f944aa6fb2 100644 --- a/examples/tcp/service.cpp +++ b/examples/tcp/service.cpp @@ -32,6 +32,7 @@ #include using Connection_ptr = std::shared_ptr; +using Disconnect = net::TCP::Connection::Disconnect; // An IP-stack object std::unique_ptr > inet; @@ -97,14 +98,14 @@ void Service::start() { }); // When client is disconnecting - client->onDisconnect([python](Connection_ptr, std::string msg) { - printf("Disconnected [Client]: %s\n", msg.c_str()); + client->onDisconnect([python](Connection_ptr, Disconnect reason) { + printf("Disconnected [Client]: %s\n", reason.to_string().c_str()); python->close(); }); // When python is disconnecting - python->onDisconnect([client](Connection_ptr, std::string msg) { - printf("Disconnected [Python]: %s\n", msg.c_str()); + python->onDisconnect([client](Connection_ptr, Disconnect reason) { + printf("Disconnected [Python]: %s\n", reason.to_string().c_str()); client->close(); }); }); // << onConnect (outgoing (python)) diff --git a/src/net/tcp_connection_states.cpp b/src/net/tcp_connection_states.cpp index 532444b064..1df39c391b 100644 --- a/src/net/tcp_connection_states.cpp +++ b/src/net/tcp_connection_states.cpp @@ -162,7 +162,7 @@ void Connection::State::unallowed_syn_reset_connection(Connection& tcp, TCP::Pac // Not sure if this is the correct way to send a "reset response" tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); tcp.transmit(); - tcp.signal_disconnect("Connection reset."); + tcp.signal_disconnect(Disconnect::RESET); } @@ -311,7 +311,7 @@ void Connection::State::process_fin(Connection& tcp, TCP::Packet_ptr in) { debug(" Processing FIN bit in STATE: %s \n", tcp.state().to_string().c_str()); assert(in->isset(FIN)); auto& tcb = tcp.tcb(); - tcp.signal_disconnect("Connection closing."); + tcp.signal_disconnect(Disconnect::CLOSING); // Advance RCV.NXT over the FIN? tcb.RCV.NXT++; //auto fin = in->data_length(); @@ -717,7 +717,7 @@ State::Result Connection::SynReceived::handle(Connection& tcp, TCP::Packet_ptr i // Since we create a new connection when it starts listening, we don't wanna do this, but just delete it. if(tcp.prev_state().to_string() == Connection::SynSent::instance().to_string()) { - tcp.signal_disconnect("Connection refused."); + tcp.signal_disconnect(Disconnect::REFUSED); } return CLOSED; @@ -832,7 +832,7 @@ State::Result Connection::Established::handle(Connection& tcp, TCP::Packet_ptr i // 2. check RST if( in->isset(RST) ) { - tcp.signal_disconnect("Connection reset."); + tcp.signal_disconnect(Disconnect::RESET); return CLOSED; // close } @@ -892,7 +892,7 @@ State::Result Connection::FinWait1::handle(Connection& tcp, TCP::Packet_ptr in) // 2. check RST if( in->isset(RST) ) { - tcp.signal_disconnect("Connection reset."); + tcp.signal_disconnect(Disconnect::RESET); return CLOSED; // close } @@ -971,7 +971,7 @@ State::Result Connection::FinWait2::handle(Connection& tcp, TCP::Packet_ptr in) // 2. check RST if( in->isset(RST) ) { - tcp.signal_disconnect("Connection reset."); + tcp.signal_disconnect(Disconnect::RESET); return CLOSED; // close } @@ -1045,7 +1045,7 @@ State::Result Connection::CloseWait::handle(Connection& tcp, TCP::Packet_ptr in) // 2. check RST if( in->isset(RST) ) { - tcp.signal_disconnect("Connection reset."); + tcp.signal_disconnect(Disconnect::RESET); return CLOSED; // close } diff --git a/test/tcp/service.cpp b/test/tcp/service.cpp index 1a43754e8c..4ac4564be8 100644 --- a/test/tcp/service.cpp +++ b/test/tcp/service.cpp @@ -103,7 +103,7 @@ void OUTGOING_TEST(TCP::Socket outgoing) { .onReceive([](Connection_ptr conn, bool) { CHECK(conn->read() == small, "conn->read() == small"); }) - .onDisconnect([](Connection_ptr, std::string) { + .onDisconnect([](Connection_ptr, TCP::Connection::Disconnect) { CHECK(true, "Connection closed by server"); OUTGOING_TEST_INTERNET(TEST_ADDR_TIME); @@ -236,7 +236,7 @@ void Service::start() CHECK(!conn->is_writable(), "!conn->is_writable()"); CHECK(conn->is_state({"FIN-WAIT-1"}), "conn.is_state(FIN-WAIT-1)"); }) - .onDisconnect([](Connection_ptr conn, std::string) { + .onDisconnect([](Connection_ptr conn, TCP::Connection::Disconnect) { CHECK(conn->is_state({"FIN-WAIT-2"}), "conn.is_state(FIN-WAIT-2)"); hw::PIT::instance().onTimeout(1s,[conn]{ CHECK(conn->is_state({"TIME-WAIT"}), "conn.is_state(TIME-WAIT)"); From d235a7fcfb8fbb1957900f5030c708334142ec79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Mon, 14 Mar 2016 15:45:15 +0100 Subject: [PATCH 028/311] minor cleanup --- src/debug/test_tcp.cpp | 43 +++----------- test/timers/Makefile | 127 ++--------------------------------------- 2 files changed, 13 insertions(+), 157 deletions(-) diff --git a/src/debug/test_tcp.cpp b/src/debug/test_tcp.cpp index 215c18aa3f..4318d649f4 100644 --- a/src/debug/test_tcp.cpp +++ b/src/debug/test_tcp.cpp @@ -44,44 +44,15 @@ void Service::start() { printf("Server is running: %s \n", server.to_string().c_str()); }); - server.onAccept([](auto conn)->bool { - printf(" onAccept \n"); - return true; - - }).onConnect([](auto conn) { - printf(" onConnect \n"); - - }).onReceive([](auto conn, bool) { - printf(" onReceive \n"); - - }).onDisconnect([](auto conn, std::string msg) { - printf(" onDisconnect \n"); - - }).onError([](auto conn, auto err) { - printf(" Error: %s \n", err.what()); - - }).onPacketReceived([](auto conn, auto packet) { - printf(" Received. \n"); + server.onPacketReceived([](auto conn, auto packet) { + printf(" Received: %s\n", packet->to_string().c_str()); }).onPacketDropped([](auto packet, std::string reason) { - printf(" Dropped. \n"); + printf(" Dropped: %s - Reason: %s \n", packet->to_string().c_str(), reason.c_str()); - }); - - inet->dhclient()->on_config([server](auto&) { - printf(" Trying to connect to server. \n"); - auto conn = inet->tcp().connect({50,63,202,26}); - printf(" Connection: %s \n", conn->to_string().c_str()); - conn->onConnect([](auto conn) { - printf(" onConnect \n"); - conn->write("GET / HTTP/1.0"); - - }).onReceive([](auto conn, bool) { - printf(" onReceive:\n%s \n", conn->read(3000).c_str()); - - }).onPacketReceived([](auto conn, auto packet) { - printf(" Received: %s \n", packet->to_string().c_str()); - - }); + }).onReceive([](auto conn, bool) { + conn->write("Hey"); + }).onConnect([](auto conn) { + printf(" Connected.\n"); }); } diff --git a/test/timers/Makefile b/test/timers/Makefile index 00349c6380..0df8981c38 100644 --- a/test/timers/Makefile +++ b/test/timers/Makefile @@ -3,132 +3,17 @@ ################################################# # The name of your service -SERVICE = Test_timers +SERVICE = "Test_timers" +SERVICE_NAME = "Timers\ Test\ Service" # Your service parts FILES = service.cpp +# Your disk image +DISK= # IncludeOS location ifndef INCLUDEOS_INSTALL - INCLUDEOS_INSTALL=$(HOME)/IncludeOS_install +INCLUDEOS_INSTALL=$(HOME)/IncludeOS_install endif -# Shorter name -INSTALL = $(INCLUDEOS_INSTALL) - -# Compiler/Linker -################################################### - -OPTIONS = -Ofast -msse3 -Wall -Wextra -mstackrealign - -# External Libraries -################################################### -LIBC_OBJ = $(INSTALL)/newlib/libc.a -LIBG_OBJ = $(INSTALL)/newlib/libg.a -LIBM_OBJ = $(INSTALL)/newlib/libm.a - -LIBGCC = $(INSTALL)/libgcc/libgcc.a -LIBCXX = $(INSTALL)/libcxx/libc++.a $(INSTALL)/libcxx/libc++abi.a - - -INC_NEWLIB=$(INSTALL)/newlib/include -INC_LIBCXX=$(INSTALL)/libcxx/include - -DEBUG_OPTS = -ggdb3 -v - -CPP = clang++-3.6 -target i686-elf -LD = ld - -INCLUDES = -I$(INC_LIBCXX) -I$(INSTALL)/api/sys -I$(INC_NEWLIB) -I$(INSTALL)/api - -CAPABS_COMMON = -msse3 -mstackrealign # Needed for 16-byte stack alignment (SSE) - -all: CAPABS = $(CAPABS_COMMON) -O2 -debug: CAPABS = $(CAPABS_COMMON) -O0 -stripped: CAPABS = $(CAPABS_COMMON) -Oz - -WARNS = -Wall -Wextra #-pedantic -CPPOPTS = $(CAPABS) $(WARNS) -c -m32 -std=c++14 -fno-stack-protector $(INCLUDES) -D_LIBCPP_HAS_NO_THREADS=1 #-flto -fno-exceptions - -LDOPTS = -nostdlib -melf_i386 -N --script=$(INSTALL)/linker.ld -flto - - -# Objects -################################################### - -CRTBEGIN_OBJ = $(INSTALL)/crt/crtbegin.o -CRTEND_OBJ = $(INSTALL)/crt/crtend.o -CRTI_OBJ = $(INSTALL)/crt/crti.o -CRTN_OBJ = $(INSTALL)/crt/crtn.o - -# Full link list -OBJS = $(FILES:.cpp=.o) .service_name.o -LIBS = $(INSTALL)/os.a $(LIBCXX) $(INSTALL)/os.a $(LIBC_OBJ) $(LIBM_OBJ) $(LIBGCC) - -OS_PRE = $(CRTBEGIN_OBJ) $(CRTI_OBJ) -OS_POST = $(CRTEND_OBJ) $(CRTN_OBJ) - -DEPS = $(OBJS:.o=.d) - -# Complete bulid -################################################### -# A complete build includes: -# - a "service", to be linked with OS-objects (OS included) - -all: service - -stripped: LDOPTS += -S #strip all -stripped: CPPOPTS += -Oz -stripped: service - - -# The same, but with debugging symbols (OBS: Dramatically increases binary size) -debug: CCOPTS += $(DEBUG_OPTS) -debug: CPPOPTS += $(DEBUG_OPTS) -debug: LDOPTS += -M --verbose - -debug: OBJS += $(LIBG_OBJ) - -debug: service #Don't wanna call 'all', since it strips debug info - -# Service -################################################### -service.o: service.cpp - @echo "\n>> Compiling the service" - $(CPP) $(CPPOPTS) -o $@ $< - -.service_name.o: $(INSTALL)/service_name.cpp - $(CPP) $(CPPOPTS) -DSERVICE_NAME="\"$(SERVICE)\"" -o $@ $< - -# Link the service with the os -service: $(OBJS) $(LIBS) - @echo "\n>> Linking service with OS" - $(LD) $(LDOPTS) $(OS_PRE) $(OBJS) $(LIBS) $(OS_POST) -o $(SERVICE) - @echo "\n>> Building image " $(SERVICE).img - $(INSTALL)/vmbuild $(INSTALL)/bootloader $(SERVICE) - -# Object files -################################################### - -# Runtime -crt%.o: $(INSTALL)/crt/crt%.s - @echo "\n>> Assembling C runtime:" $@ - $(CPP) $(CPPOPTS) -x assembler-with-cpp $< - -# General C++-files to object files -%.o: %.cpp - @echo "\n>> Compiling OS object without header" - $(CPP) $(CPPOPTS) -o $@ $< - -# AS-assembled object files -%.o: %.s - @echo "\n>> Assembling GNU 'as' files" - $(CPP) $(CPPOPTS) -x assembler-with-cpp $< - -# Cleanup -################################################### -clean: - $(RM) $(OBJS) $(DEPS) $(SERVICE) - $(RM) $(SERVICE).img - --include $(DEPS) +include $(INCLUDEOS_INSTALL)/Makeseed From f1613399f92f67bee5ee639c7f718f8c27aaca65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Mon, 14 Mar 2016 16:00:10 +0100 Subject: [PATCH 029/311] test: tcp - script to run locally on vbox --- test/tcp/vbox.sh | 2 ++ 1 file changed, 2 insertions(+) create mode 100755 test/tcp/vbox.sh diff --git a/test/tcp/vbox.sh b/test/tcp/vbox.sh new file mode 100755 index 0000000000..d51622d5f7 --- /dev/null +++ b/test/tcp/vbox.sh @@ -0,0 +1,2 @@ +#!/bin/bash +../../etc/vboxrun.sh IncludeOS_TCP_Test.img TCP_test \ No newline at end of file From 0278582c5d971ae271b5933d51aab279cf2293d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Mon, 14 Mar 2016 16:04:36 +0100 Subject: [PATCH 030/311] examples: using new Makefile + reduced output spam --- examples/demo_service/Makefile | 132 +++--------------------------- examples/demo_service/service.cpp | 16 ++-- examples/tcp/Makefile | 132 +++--------------------------- 3 files changed, 29 insertions(+), 251 deletions(-) diff --git a/examples/demo_service/Makefile b/examples/demo_service/Makefile index 4af7bc3582..8c04f9c522 100644 --- a/examples/demo_service/Makefile +++ b/examples/demo_service/Makefile @@ -4,133 +4,21 @@ # The name of your service SERVICE = IncludeOS_Demo_Service +SERVICE_NAME = IncludeOS Demo Service # Your service parts FILES = service.cpp -# IncludeOS location -ifndef INCLUDEOS_INSTALL - INCLUDEOS_INSTALL=$(HOME)/IncludeOS_install -endif - -# Shorter name -INSTALL = $(INCLUDEOS_INSTALL) - -# Compiler/Linker -################################################### - -OPTIONS = -Ofast -msse3 -Wall -Wextra -mstackrealign - -# External Libraries -################################################### -LIBC_OBJ = $(INSTALL)/newlib/libc.a -LIBG_OBJ = $(INSTALL)/newlib/libg.a -LIBM_OBJ = $(INSTALL)/newlib/libm.a - -LIBGCC = $(INSTALL)/libgcc/libgcc.a -LIBCXX = $(INSTALL)/libcxx/libc++.a $(INSTALL)/libcxx/libc++abi.a - - -INC_NEWLIB=$(INSTALL)/newlib/include -INC_LIBCXX=$(INSTALL)/libcxx/include +# Your disk image +DISK= -DEBUG_OPTS = -ggdb3 -v +# Your own include-path +LOCAL_INCLUDES= -CPP = clang++-3.6 -target i686-elf -ifndef LD_INC - LD_INC = ld +# IncludeOS location +ifndef INCLUDEOS_INSTALL +INCLUDEOS_INSTALL=$(HOME)/IncludeOS_install endif -INCLUDES = -I$(INC_LIBCXX) -I$(INSTALL)/api/sys -I$(INC_NEWLIB) -I$(INSTALL)/api - -CAPABS_COMMON = -msse3 -mstackrealign # Needed for 16-byte stack alignment (SSE) - -all: CAPABS = $(CAPABS_COMMON) -O2 -debug: CAPABS = $(CAPABS_COMMON) -O0 -stripped: CAPABS = $(CAPABS_COMMON) -Oz - -WARNS = -Wall -Wextra #-pedantic -CPPOPTS = $(CAPABS) $(WARNS) -c -m32 -std=c++14 -fno-stack-protector $(INCLUDES) -D_LIBCPP_HAS_NO_THREADS=1 #-flto -fno-exceptions - -LDOPTS = -nostdlib -melf_i386 -N --script=$(INSTALL)/linker.ld -flto - - -# Objects -################################################### - -CRTBEGIN_OBJ = $(INSTALL)/crt/crtbegin.o -CRTEND_OBJ = $(INSTALL)/crt/crtend.o -CRTI_OBJ = $(INSTALL)/crt/crti.o -CRTN_OBJ = $(INSTALL)/crt/crtn.o - -# Full link list -OBJS = $(FILES:.cpp=.o) .service_name.o -LIBS = $(INSTALL)/os.a $(LIBCXX) $(INSTALL)/os.a $(LIBC_OBJ) $(LIBM_OBJ) $(LIBGCC) - -OS_PRE = $(CRTBEGIN_OBJ) $(CRTI_OBJ) -OS_POST = $(CRTEND_OBJ) $(CRTN_OBJ) - -DEPS = $(OBJS:.o=.d) - -# Complete bulid -################################################### -# A complete build includes: -# - a "service", to be linked with OS-objects (OS included) - -all: service - -stripped: LDOPTS += -S #strip all -stripped: CPPOPTS += -Oz -stripped: service - - -# The same, but with debugging symbols (OBS: Dramatically increases binary size) -debug: CCOPTS += $(DEBUG_OPTS) -debug: CPPOPTS += $(DEBUG_OPTS) -debug: LDOPTS += -M --verbose - -debug: OBJS += $(LIBG_OBJ) - -debug: service #Don't wanna call 'all', since it strips debug info - -# Service -################################################### -service.o: service.cpp - @echo "\n>> Compiling the service" - $(CPP) $(CPPOPTS) -o $@ $< - -.service_name.o: $(INSTALL)/service_name.cpp - $(CPP) $(CPPOPTS) -DSERVICE_NAME="\"$(SERVICE)\"" -o $@ $< - -# Link the service with the os -service: $(OBJS) $(LIBS) - @echo "\n>> Linking service with OS" - $(LD_INC) $(LDOPTS) $(OS_PRE) $(OBJS) $(LIBS) $(OS_POST) -o $(SERVICE) - @echo "\n>> Building image " $(SERVICE).img - $(INSTALL)/vmbuild $(INSTALL)/bootloader $(SERVICE) - -# Object files -################################################### - -# Runtime -crt%.o: $(INSTALL)/crt/crt%.s - @echo "\n>> Assembling C runtime:" $@ - $(CPP) $(CPPOPTS) -x assembler-with-cpp $< - -# General C++-files to object files -%.o: %.cpp - @echo "\n>> Compiling OS object without header" - $(CPP) $(CPPOPTS) -o $@ $< - -# AS-assembled object files -%.o: %.s - @echo "\n>> Assembling GNU 'as' files" - $(CPP) $(CPPOPTS) -x assembler-with-cpp $< - -# Cleanup -################################################### -clean: - $(RM) $(OBJS) $(DEPS) $(SERVICE) - $(RM) $(SERVICE).img - --include $(DEPS) +# Include the installed seed makefile +include $(INCLUDEOS_INSTALL)/Makeseed diff --git a/examples/demo_service/service.cpp b/examples/demo_service/service.cpp index 9406e3a53a..7acabb6e33 100644 --- a/examples/demo_service/service.cpp +++ b/examples/demo_service/service.cpp @@ -24,6 +24,8 @@ // An IP-stack object std::unique_ptr > inet; +using namespace std::chrono; + void Service::start() { // Assign a driver (VirtioNet) to a network interface (eth0) // @note: We could determine the appropirate driver dynamically, but then we'd @@ -45,22 +47,23 @@ void Service::start() { // Set up a TCP server on port 80 auto& server = inet->tcp().bind(80); + + hw::PIT::instance().onRepeatedTimeout(30s, []{ + printf(" TCP STATUS:\n%s \n", inet->tcp().status().c_str()); + }); // Add a TCP connection handler - here a hardcoded HTTP-service server.onAccept([](auto conn) -> bool { printf(" @onAccept - Connection attempt from: %s \n", conn->to_string().c_str()); - printf(" Status: %s \n", conn->to_string().c_str()); return true; // allow all connections - }).onConnect([](auto conn) { - printf(" @onConnect - Connection successfully established. \n"); - printf(" TCP STATUS:\n%s \n", conn->host().status().c_str()); + }).onConnect([](auto) { + printf(" @onConnect - Connection successfully established.\n"); }).onReceive([](auto conn, bool push) { std::string data = conn->read(1024); printf(" @onData - PUSH: %d, Data read: \n%s\n", push, data.c_str()); - printf(" Status: %s \n", conn->to_string().c_str()); int color = rand(); std::stringstream stream; @@ -95,9 +98,8 @@ void Service::start() { std::string output{header + html}; conn->write(output.data(), output.size()); - }).onDisconnect([](auto conn, auto reason) { + }).onDisconnect([](auto, auto reason) { printf(" @onDisconnect - Reason: %s \n", reason.to_string().c_str()); - printf(" TCP STATUS:\n%s \n", conn->host().status().c_str()); }); printf("*** TEST SERVICE STARTED *** \n"); diff --git a/examples/tcp/Makefile b/examples/tcp/Makefile index 035017a6f7..4e9eb8ef0c 100644 --- a/examples/tcp/Makefile +++ b/examples/tcp/Makefile @@ -4,133 +4,21 @@ # The name of your service SERVICE = tcp_demo +SERVICE_NAME = IncludeOS TCP Demo # Your service parts FILES = service.cpp -# IncludeOS location -ifndef INCLUDEOS_INSTALL - INCLUDEOS_INSTALL=$(HOME)/IncludeOS_install -endif - -# Shorter name -INSTALL = $(INCLUDEOS_INSTALL) - -# Compiler/Linker -################################################### - -OPTIONS = -Ofast -msse3 -Wall -Wextra -mstackrealign - -# External Libraries -################################################### -LIBC_OBJ = $(INSTALL)/newlib/libc.a -LIBG_OBJ = $(INSTALL)/newlib/libg.a -LIBM_OBJ = $(INSTALL)/newlib/libm.a - -LIBGCC = $(INSTALL)/libgcc/libgcc.a -LIBCXX = $(INSTALL)/libcxx/libc++.a $(INSTALL)/libcxx/libc++abi.a - - -INC_NEWLIB=$(INSTALL)/newlib/include -INC_LIBCXX=$(INSTALL)/libcxx/include +# Your disk image +DISK= -DEBUG_OPTS = -ggdb3 -v +# Your own include-path +LOCAL_INCLUDES= -CPP = clang++-3.6 -target i686-elf -ifndef LD_INC - LD_INC = ld +# IncludeOS location +ifndef INCLUDEOS_INSTALL +INCLUDEOS_INSTALL=$(HOME)/IncludeOS_install endif -INCLUDES = -I$(INC_LIBCXX) -I$(INSTALL)/api/sys -I$(INC_NEWLIB) -I$(INSTALL)/api - -CAPABS_COMMON = -msse3 -mstackrealign # Needed for 16-byte stack alignment (SSE) - -all: CAPABS = $(CAPABS_COMMON) -O2 -debug: CAPABS = $(CAPABS_COMMON) -O0 -stripped: CAPABS = $(CAPABS_COMMON) -Oz - -WARNS = -Wall -Wextra #-pedantic -CPPOPTS = $(CAPABS) $(WARNS) -c -m32 -std=c++14 -fno-stack-protector $(INCLUDES) -D_LIBCPP_HAS_NO_THREADS=1 #-flto -fno-exceptions - -LDOPTS = -nostdlib -melf_i386 -N --script=$(INSTALL)/linker.ld -flto - - -# Objects -################################################### - -CRTBEGIN_OBJ = $(INSTALL)/crt/crtbegin.o -CRTEND_OBJ = $(INSTALL)/crt/crtend.o -CRTI_OBJ = $(INSTALL)/crt/crti.o -CRTN_OBJ = $(INSTALL)/crt/crtn.o - -# Full link list -OBJS = $(FILES:.cpp=.o) .service_name.o -LIBS = $(INSTALL)/os.a $(LIBCXX) $(INSTALL)/os.a $(LIBC_OBJ) $(LIBM_OBJ) $(LIBGCC) - -OS_PRE = $(CRTBEGIN_OBJ) $(CRTI_OBJ) -OS_POST = $(CRTEND_OBJ) $(CRTN_OBJ) - -DEPS = $(OBJS:.o=.d) - -# Complete bulid -################################################### -# A complete build includes: -# - a "service", to be linked with OS-objects (OS included) - -all: service - -stripped: LDOPTS += -S #strip all -stripped: CPPOPTS += -Oz -stripped: service - - -# The same, but with debugging symbols (OBS: Dramatically increases binary size) -debug: CCOPTS += $(DEBUG_OPTS) -debug: CPPOPTS += $(DEBUG_OPTS) -debug: LDOPTS += -M --verbose - -debug: OBJS += $(LIBG_OBJ) - -debug: service #Don't wanna call 'all', since it strips debug info - -# Service -################################################### -service.o: service.cpp - @echo "\n>> Compiling the service" - $(CPP) $(CPPOPTS) -o $@ $< - -.service_name.o: $(INSTALL)/service_name.cpp - $(CPP) $(CPPOPTS) -DSERVICE_NAME="\"$(SERVICE)\"" -o $@ $< - -# Link the service with the os -service: $(OBJS) $(LIBS) - @echo "\n>> Linking service with OS" - $(LD_INC) $(LDOPTS) $(OS_PRE) $(OBJS) $(LIBS) $(OS_POST) -o $(SERVICE) - @echo "\n>> Building image " $(SERVICE).img - $(INSTALL)/vmbuild $(INSTALL)/bootloader $(SERVICE) - -# Object files -################################################### - -# Runtime -crt%.o: $(INSTALL)/crt/crt%.s - @echo "\n>> Assembling C runtime:" $@ - $(CPP) $(CPPOPTS) -x assembler-with-cpp $< - -# General C++-files to object files -%.o: %.cpp - @echo "\n>> Compiling OS object without header" - $(CPP) $(CPPOPTS) -o $@ $< - -# AS-assembled object files -%.o: %.s - @echo "\n>> Assembling GNU 'as' files" - $(CPP) $(CPPOPTS) -x assembler-with-cpp $< - -# Cleanup -################################################### -clean: - $(RM) $(OBJS) $(DEPS) $(SERVICE) - $(RM) $(SERVICE).img - --include $(DEPS) +# Include the installed seed makefile +include $(INCLUDEOS_INSTALL)/Makeseed From ea37ca27e8ebc1e1d507d7576f362cde8fe80753 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Mon, 14 Mar 2016 23:02:55 +0100 Subject: [PATCH 031/311] term: Barebones --- api/kernel/terminal.hpp | 41 ++++++++++++++++++++++++++++++++++++++ api/serial | 6 ++++++ api/term | 6 ++++++ src/Makefile | 2 +- src/debug/test_service.cpp | 8 ++++++++ 5 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 api/kernel/terminal.hpp create mode 100644 api/serial create mode 100644 api/term diff --git a/api/kernel/terminal.hpp b/api/kernel/terminal.hpp new file mode 100644 index 0000000000..2c6e8d20d5 --- /dev/null +++ b/api/kernel/terminal.hpp @@ -0,0 +1,41 @@ +#ifndef KERNEL_BTERM_HPP +#define KERNEL_BTERM_HPP + +#include +#include + +// some bidirectional communication interface +struct IBidirectional +{ + using on_read_func = std::function; + using on_write_func = std::function; + + virtual void set_on_read(on_read_func) = 0; + virtual void write(char, on_write_func) = 0; + + on_read_func read_callback; +}; + +// communication using serial port +struct SerialComm : public IBidirectional +{ + SerialComm(hw::Serial& s); + + virtual void set_on_read(on_read_func) override; + virtual void write(char) override; + + hw::Serial& serial; +}; + +class Terminal +{ +public: + Terminal(IBidirectional& iface) + : comm(iface) {} + + + + IBidirectional& comm; +}; + +#endif diff --git a/api/serial b/api/serial new file mode 100644 index 0000000000..622f4d6160 --- /dev/null +++ b/api/serial @@ -0,0 +1,6 @@ +#ifndef SERIAL_HEADER +#define SERIAL_HEADER + +#include "hw/serial.hpp" + +#endif diff --git a/api/term b/api/term new file mode 100644 index 0000000000..ba47990615 --- /dev/null +++ b/api/term @@ -0,0 +1,6 @@ +#ifndef TERM_HEADER +#define TERM_HEADER + +#include "kernel/terminal.hpp" + +#endif diff --git a/src/Makefile b/src/Makefile index d6a93bc9bd..f05938150f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -60,7 +60,7 @@ CXXABI_OBJ = $(CXXABI:.cpp=.o) OS_OBJECTS = kernel/kernel_start.o kernel/syscalls.o kernel/vga.o \ kernel/interrupts.o kernel/os.o kernel/cpuid.o \ - kernel/irq_manager.o kernel/pci_manager.o \ + kernel/irq_manager.o kernel/pci_manager.o kernel/terminal.o \ crt/c_abi.o crt/string.o crt/quick_exit.o crt/cxx_abi.o crt/mman.o \ util/memstream.o \ hw/ide.o hw/pit.o hw/pic.o hw/pci_device.o hw/cpu_freq_sampling.o hw/serial.o\ diff --git a/src/debug/test_service.cpp b/src/debug/test_service.cpp index b9d86ed653..0d961e86a8 100644 --- a/src/debug/test_service.cpp +++ b/src/debug/test_service.cpp @@ -18,8 +18,12 @@ #include #include #include +#include #include "ircd.hpp" +SerialComm scomm(hw::Serial::port<1>()); +Terminal term(scomm); + using namespace std::chrono; // An IP-stack object @@ -70,5 +74,9 @@ void Service::start() });*/ }); + /// terminal /// + + + printf("*** TEST SERVICE STARTED *** \n"); } From a39db7a9f0a606f9f6ec674adfb785e0dd10d043 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 15 Mar 2016 18:44:12 +0100 Subject: [PATCH 032/311] Using PIC command words properly --- api/hw/pic.hpp | 63 +++++++++++++++++++++++++++++++------------------- src/hw/pic.cpp | 24 ++++++++++++------- 2 files changed, 55 insertions(+), 32 deletions(-) diff --git a/api/hw/pic.hpp b/api/hw/pic.hpp index 5173d9b140..acb0da5d5e 100644 --- a/api/hw/pic.hpp +++ b/api/hw/pic.hpp @@ -46,6 +46,7 @@ class PIC { inline static void eoi(const uint8_t irq) noexcept { if (irq >= 8) { + //hw::outb(slave_ctrl, eoi_); hw::outb(slave_ctrl, eoi_); } //hw::outb(master_ctrl, specific_eoi_ | (irq & 0x0f) );*/ @@ -53,50 +54,64 @@ class PIC { /* Returns the combined value of the cascaded PICs irq request register */ inline static uint16_t get_irr() noexcept - { return get_irq_reg(read_irr); } + { return get_irq_reg(ocw3_read_irr); } /* Returns the combined value of the cascaded PICs in-service register */ inline static uint16_t get_isr() noexcept - { return get_irq_reg(read_isr); } + { return get_irq_reg(ocw3_read_isr); } private: // ICW1 bits - static constexpr uint8_t icw1 {0x10}; // Bit 5 must always be set + static constexpr uint8_t icw1 {0x10}; // Bit 5 compulsory static constexpr uint8_t icw1_icw4_needed {0x1}; // Prepare for cw4 or not - static constexpr uint8_t icw1_single_mode {0x2}; // Not set means cascade - static constexpr uint8_t icw1_addr_interval_4 {0x4}; // Not set means interval 8 - static constexpr uint8_t icw1_level_trigered {0x8}; // Not set means egde triggred + static constexpr uint8_t icw1_single_mode {0x2}; // 0: cascade + static constexpr uint8_t icw1_addr_interval_4 {0x4}; // 0: interval 8 + static constexpr uint8_t icw1_level_trigered {0x8}; // 0: egde triggred // ICW2 bits: Interrupt number for first IRQ - // ICW3 bits: Location of slave PIC + static constexpr uint8_t icw2_irq_base_master {32}; + static constexpr uint8_t icw2_irq_base_slave {40}; + + // ICW3 bits: Location and ID of slave PIC + static constexpr uint8_t icw3_slave_location {0x04}; + static constexpr uint8_t icw3_slave_id {0x02}; + // ICW4 bits: - static constexpr uint8_t icw4_8086_mode {0x1}; // Not set means aincient runes - static constexpr uint8_t icw4_auto_eoi {0x2}; // Switch between auto / normal EOI + static constexpr uint8_t icw4 {0x0}; // No bits by default + static constexpr uint8_t icw4_8086_mode {0x1}; // 0: aincient runes + static constexpr uint8_t icw4_auto_eoi {0x2}; // auto vs. normal EOI static constexpr uint8_t icw4_buffered_mode_slave {0x08}; static constexpr uint8_t icw4_buffered_mode_master {0x12}; + // Registers addresses static const uint8_t master_ctrl {0x20}; static const uint8_t master_mask {0x21}; static const uint8_t slave_ctrl {0xA0}; static const uint8_t slave_mask {0xA1}; - // Master commands - static const uint8_t master_icw1 {0x11}; // icw4 needed (bit1), bit5 always on - static const uint8_t master_icw2 {32}; // Remap - static const uint8_t master_icw3 {0x04}; // Location of slave - static const uint8_t master_icw4 {0x03}; // 8086-mode (bit1), Auto-EOI (bit2) - - // Slave commands - static const uint8_t slave_icw1 {0x11}; - static const uint8_t slave_icw2 {40}; - static const uint8_t slave_icw3 {0x02}; // Slave ID - static const uint8_t slave_icw4 {0x01}; + + // Operational command words + // OCW1: Interrupt mask + // OCW2: + static constexpr uint8_t ocw2 {0x0}; // No default bits + static constexpr uint8_t ocw2_nonspecific_eoi {0x20}; + static constexpr uint8_t ocw2_specific_eoi {0x60}; + static constexpr uint8_t ocw2_rotate_on_non_specific_eoi {0xA0}; + static constexpr uint8_t ocw2_rotate_on_auto_eoi_set {0x80}; // 0x0 to clear + static constexpr uint8_t ocw2_rotate_on_specific_eoi {0xE0}; + static constexpr uint8_t ocw2_set_priority_cmd {0xC0}; + static constexpr uint8_t ocw2_nop {0x40}; + + static constexpr uint8_t ocw3 {0x08}; // Default bits + static constexpr uint8_t ocw3_read_irr {0x02}; + static constexpr uint8_t ocw3_read_isr {0x03}; + static constexpr uint8_t ocw3_poll_cmd {0x04}; // 0 to disable + static constexpr uint8_t ocw3_set_special_mask {0x60}; + static constexpr uint8_t ocw3_reset_special_mask {0x40}; + + - /* IRQ ready next CMD read */ - static const uint8_t read_irr {0x0A}; - /* IRQ service next CMD read */ - static const uint8_t read_isr {0x0B}; static constexpr uint8_t ocw2_eoi = 0x20; diff --git a/src/hw/pic.cpp b/src/hw/pic.cpp index 2657b8c7f1..4d5529469e 100644 --- a/src/hw/pic.cpp +++ b/src/hw/pic.cpp @@ -23,14 +23,22 @@ namespace hw { uint16_t PIC::irq_mask_ {0xFFFF}; void PIC::init() noexcept { - hw::outb(master_ctrl, master_icw1); - hw::outb(slave_ctrl, slave_icw1); - hw::outb(master_mask, master_icw2); - hw::outb(slave_mask, slave_icw2); - hw::outb(master_mask, master_icw3); - hw::outb(slave_mask, slave_icw3); - hw::outb(master_mask, master_icw4); - hw::outb(slave_mask, slave_icw4); + // Master commands + static const uint8_t master_icw3 {0x04}; // Location of slave + static const uint8_t master_icw4 {0x03}; // 8086-mode (bit1), Auto-EOI (bit2) + + // Slave commands + static const uint8_t slave_icw3 {0x02}; // Slave ID + static const uint8_t slave_icw4 {0x01}; + + hw::outb(master_ctrl, icw1 | icw1_icw4_needed); + hw::outb(slave_ctrl, icw1 | icw1_icw4_needed); + hw::outb(master_mask, icw2_irq_base_master); + hw::outb(slave_mask, icw2_irq_base_slave); + hw::outb(master_mask, icw3_slave_location); + hw::outb(slave_mask, icw3_slave_id); + hw::outb(master_mask, icw4_8086_mode | icw4_auto_eoi); + hw::outb(slave_mask, icw4_8086_mode); set_intr_mask(irq_mask_); } From 4dfe8823aeac0548463780d004a551162255c8bf Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 15 Mar 2016 22:56:59 +0100 Subject: [PATCH 033/311] A woman of no importance would appreciate the importance of being earnest. This test should fail. --- api/kernel/os.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/kernel/os.hpp b/api/kernel/os.hpp index 7f64e49f4b..2cc2c2c79c 100644 --- a/api/kernel/os.hpp +++ b/api/kernel/os.hpp @@ -34,7 +34,7 @@ namespace hw{ class Serial; } * * @note For device access, see Dev */ -class OS { +class OSCAR WILDE ISN'T A VALID CLASS NAME IS IT? { public: using rsprint_func = delegate; From 8b1e86aa0c35167d01d75ce8611f83fadeac4405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Wed, 16 Mar 2016 10:09:17 +0100 Subject: [PATCH 034/311] whitespace changes --- api/net/tcp.hpp | 146 ++++++++++++++++++++++++------------------------ 1 file changed, 73 insertions(+), 73 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index de585587be..d96a7040c4 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -34,7 +34,7 @@ inline unsigned round_up(unsigned n, unsigned div) { } namespace net { - + class TCP { public: using Address = IP4::addr; @@ -43,7 +43,7 @@ class TCP { A Sequence number (SYN/ACK) (32 bits) */ using Seq = uint32_t; - + class Packet; using Packet_ptr = std::shared_ptr; @@ -95,7 +95,7 @@ class TCP { Comparator used for vector. */ inline bool operator ==(const Socket &s2) const { - return address().whole == s2.address().whole + return address().whole == s2.address().whole and port() == s2.port(); } @@ -116,12 +116,12 @@ class TCP { /////// TCP Stuff - Relevant to the protocol ///// - + static constexpr uint16_t default_window_size = 0xffff; static constexpr uint16_t default_mss = 536; - /* + /* Flags (Control bits) in the TCP Header. */ enum Flag { @@ -140,8 +140,8 @@ class TCP { Representation of the TCP Header. RFC 793, (p.15): - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source Port | Destination Port | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -179,7 +179,7 @@ class TCP { }__attribute__((packed)); // << struct TCP::Header - /* + /* TCP Pseudo header, for checksum calculation */ struct Pseudo_header { @@ -189,7 +189,7 @@ class TCP { uint8_t proto; uint16_t tcp_length; }__attribute__((packed)); - + /* TCP Checksum-header (TCP-header + pseudo-header) */ @@ -204,7 +204,7 @@ class TCP { struct Full_header { Ethernet::header ethernet; IP4::ip_header ip4; - TCP::Header tcp; + TCP::Header tcp; }__attribute__((packed)); /* @@ -223,10 +223,10 @@ class TCP { static std::string kind_string(Kind kind) { switch(kind) { - case MSS: + case MSS: return {"MSS"}; - default: + default: return {"Unknown Option"}; } } @@ -236,7 +236,7 @@ class TCP { uint8_t length; uint16_t mss; - opt_mss(uint16_t mss) + opt_mss(uint16_t mss) : kind(MSS), length(4), mss(htons(mss)) {} }; @@ -248,25 +248,25 @@ class TCP { }; }; - + /* - A Wrapper for a TCP Packet. Is everything as a IP4 Packet, + A Wrapper for a TCP Packet. Is everything as a IP4 Packet, in addition to the TCP Header and functions to modify this and the control bits (FLAGS). */ class Packet : public PacketIP4 { public: - + inline TCP::Header& header() const { return ((TCP::Full_header*) buffer())->tcp; } - + static const size_t HEADERS_SIZE = sizeof(TCP::Full_header); - + //! initializes to a default, empty TCP packet, given //! a valid MTU-sized buffer void init() - { + { // Erase all headers (smart? necessary? ...well, convenient) memset(buffer(), 0, HEADERS_SIZE); PacketIP4::init(); @@ -295,27 +295,27 @@ class TCP { inline TCP::Socket destination() const { return TCP::Socket{dst(), dst_port()}; } // SETTERS - inline TCP::Packet& set_src_port(TCP::Port p) { + inline TCP::Packet& set_src_port(TCP::Port p) { header().source_port = htons(p); return *this; } - inline TCP::Packet& set_dst_port(TCP::Port p) { + inline TCP::Packet& set_dst_port(TCP::Port p) { header().destination_port = htons(p); return *this; } - inline TCP::Packet& set_seq(TCP::Seq n) { + inline TCP::Packet& set_seq(TCP::Seq n) { header().seq_nr = htonl(n); return *this; } - inline TCP::Packet& set_ack(TCP::Seq n) { + inline TCP::Packet& set_ack(TCP::Seq n) { header().ack_nr = htonl(n); return *this; } - inline TCP::Packet& set_win_size(uint16_t size) { + inline TCP::Packet& set_win_size(uint16_t size) { header().window_size = htons(size); return *this; } @@ -339,12 +339,12 @@ class TCP { /// FLAGS / CONTROL BITS /// - inline TCP::Packet& set_flag(TCP::Flag f) { + inline TCP::Packet& set_flag(TCP::Flag f) { header().offset_flags.whole |= htons(f); return *this; } - inline TCP::Packet& set_flags(uint16_t f) { + inline TCP::Packet& set_flags(uint16_t f) { header().offset_flags.whole |= htons(f); return *this; } @@ -378,7 +378,7 @@ class TCP { // Where data starts inline char* data() { return (char*) (buffer() + all_headers_len()); } - + inline uint16_t data_length() const { return size() - all_headers_len(); } inline bool has_data() const { return data_length() > 0; } @@ -432,8 +432,8 @@ class TCP { inline std::string to_string() { std::ostringstream os; os << "[ S:" << source().to_string() << " D:" << destination().to_string() - << " SEQ:" << seq() << " ACK:" << ack() - << " HEAD-LEN:" << (int)header_size() << " OPT-LEN:" << (int)options_length() << " DATA-LEN:" << data_length() + << " SEQ:" << seq() << " ACK:" << ack() + << " HEAD-LEN:" << (int)header_size() << " OPT-LEN:" << (int)options_length() << " DATA-LEN:" << data_length() << " WIN:" << win() << " FLAGS:" << std::bitset<8>{header().offset_flags.flags} << " ]"; return os.str(); } @@ -454,7 +454,7 @@ class TCP { */ class TCPBadOptionException : public TCPException { public: - TCPBadOptionException(Option::Kind kind, const std::string& error) : + TCPBadOptionException(Option::Kind kind, const std::string& error) : TCPException("Bad Option [" + Option::kind_string(kind) + "]: " + error), kind_(kind) {}; @@ -469,7 +469,7 @@ class TCP { template> class PacketBuffer { public: - + PacketBuffer(typename Buffer::size_type limit) : buffer_(), data_length_(0), data_offset_(0), limit_(limit) @@ -478,7 +478,7 @@ class TCP { } /* Number of packets */ inline auto size() const { return buffer_.size(); } - + /* Amount of data */ inline size_t data_size() const { return data_length_; } @@ -546,13 +546,13 @@ class TCP { First thing that will happen. */ using AcceptCallback = delegate)>; - + /* On connected - When both hosts exchanged sequence numbers (handshake is done). Now in ESTABLISHED state - it's allowed to write and read to/from the remote. */ using ConnectCallback = delegate)>; - + /* On receiving data - When there is data to read in the receive buffer. Either when remote PUSH, or buffer is full. @@ -598,7 +598,7 @@ class TCP { enum Reason { CLOSING, REFUSED, - RESET + RESET }; Reason reason; @@ -613,7 +613,7 @@ class TCP { std::string to_string() const { switch(reason) { - case CLOSING: + case CLOSING: return "Connection closing"; case REFUSED: return "Conneciton refused"; @@ -652,19 +652,19 @@ class TCP { RECEIVE */ virtual size_t receive(Connection&, char* buffer, size_t n); - + /* Close a Connection. CLOSE */ virtual void close(Connection&); - + /* Terminate a Connection. ABORT */ virtual void abort(Connection&); - + /* Handle a Packet SEGMENT ARRIVES @@ -677,7 +677,7 @@ class TCP { */ virtual std::string to_string() const = 0; - protected: + protected: /* Helper functions TODO: Clean up names. @@ -715,7 +715,7 @@ class TCP { /* Transmission Control Block. Keep tracks of all the data for a connection. - + RFC 793: Page 19 Among the variables stored in the TCB are the local and remote socket numbers, the security and @@ -959,7 +959,7 @@ class TCP { /* Helper function for state checks. */ - inline bool is_state(const State& state) const { + inline bool is_state(const State& state) const { return state_ == &state; } @@ -975,31 +975,31 @@ class TCP { ~Connection(); private: - /* + /* "Parent" for Connection. */ TCP& host_; // 4 B - /* + /* End points. */ TCP::Port local_port_; // 2 B TCP::Socket remote_; // 8~ B - /* - The current state the Connection is in. - Handles most of the logic. + /* + The current state the Connection is in. + Handles most of the logic. */ State* state_; // 4 B // Previous state. Used to keep track of state transitions. State* prev_state_; // 4 B - - /* + + /* Keep tracks of all sequence variables. */ TCB control_block; // 36 B - /* + /* Buffers */ Buffer receive_buffer_; @@ -1010,9 +1010,9 @@ class TCP { */ uint64_t time_wait_started; - + /// CALLBACK HANDLING /// - + /* When a Connection is initiated. */ AcceptCallback on_accept_ = AcceptCallback::from(this); inline bool default_on_accept(std::shared_ptr) { @@ -1024,7 +1024,7 @@ class TCP { ConnectCallback on_connect_ = [](std::shared_ptr) { debug2(" Connected.\n"); }; - + /* When data is received */ ReceiveCallback on_receive_ = [](std::shared_ptr, bool) { debug2(" Connection received data. \n"); @@ -1037,8 +1037,8 @@ class TCP { /* When error occcured. */ ErrorCallback on_error_ = ErrorCallback::from(this); - inline void default_on_error(std::shared_ptr, TCPException) { - //debug2(" TCPException: %s \n", error.what()); + inline void default_on_error(std::shared_ptr, TCPException) { + //debug2(" TCPException: %s \n", error.what()); } /* When packet is received */ @@ -1047,8 +1047,8 @@ class TCP { }; /* When a packet is dropped. */ - PacketDroppedCallback on_packet_dropped_ = [](TCP::Packet_ptr, std::string) { - //debug(" Packet dropped. %s | Reason: %s \n", + PacketDroppedCallback on_packet_dropped_ = [](TCP::Packet_ptr, std::string) { + //debug(" Packet dropped. %s | Reason: %s \n", // packet->to_string().c_str(), reason.c_str()); }; @@ -1107,7 +1107,7 @@ class TCP { Add(queue) a packet to the receive buffer. */ bool add_to_receive_buffer(TCP::Packet_ptr packet); - + /* Write to the send buffer. Segmentize into packets. */ @@ -1132,14 +1132,14 @@ class TCP { Returns the packet in the back of the send buffer. If the send buffer is empty, it creates a new packet and adds it. */ - TCP::Packet_ptr outgoing_packet(); + TCP::Packet_ptr outgoing_packet(); + - /// RETRANSMISSION /// /* Starts a retransmission timer that retransmits the packet when RTO has passed. - + // TODO: Calculate RTO, currently hardcoded to 1 second (1000ms). */ void add_retransmission(TCP::Packet_ptr); @@ -1153,7 +1153,7 @@ class TCP { */ //std::chrono::milliseconds RTT() const; std::chrono::milliseconds RTO() const; - + /* Start the time wait timeout for 2*MSL */ @@ -1193,9 +1193,9 @@ class TCP { Constructor */ TCP(IPStack&); - + /* - Bind a new listener to a given Port. + Bind a new listener to a given Port. */ TCP::Connection& bind(Port port); @@ -1207,8 +1207,8 @@ class TCP { /* Active open a new connection to the given remote. */ - inline auto connect(TCP::Address address, Port port = 80) { - return connect({address, port}); + inline auto connect(TCP::Address address, Port port = 80) { + return connect({address, port}); } /* @@ -1221,7 +1221,7 @@ class TCP { */ void bottom(net::Packet_ptr); - /* + /* Delegate output to network layer */ inline void set_network_out(downstream del) { _network_layer_out = del; } @@ -1253,7 +1253,7 @@ class TCP { /* Set Maximum Segment Lifetime */ - inline void set_MSL(const std::chrono::milliseconds msl) { + inline void set_MSL(const std::chrono::milliseconds msl) { MAX_SEG_LIFETIME = msl; } @@ -1282,7 +1282,7 @@ class TCP { MTU > 1482 seems to cause fragmentation: https://www.virtualbox.org/ticket/13967 */ const uint16_t VBOX_LIMIT = 1482; - return std::min(inet_.MTU(), VBOX_LIMIT) - sizeof(Full_header::ip4) - sizeof(TCP::Header); + return std::min(inet_.MTU(), VBOX_LIMIT) - sizeof(Full_header::ip4) - sizeof(TCP::Header); } /* @@ -1298,7 +1298,7 @@ class TCP { downstream _network_layer_out; - /* + /* Settings */ TCP::Port current_ephemeral_ = 1024; @@ -1310,7 +1310,7 @@ class TCP { Connection buffer size in bytes = buffers * BUFFER_LIMIT * MTU. */ size_t MAX_BUFFER_SIZE = 10; - + /* Transmit packet to network layer (IP). */ From 76423b8e49dc70ff0d90f82f4eb5fcb32dd17e59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Wed, 16 Mar 2016 22:53:06 +0100 Subject: [PATCH 035/311] tcp: cleaned up, reformatted and restructured state impl for easier reading --- src/net/tcp_connection_states.cpp | 1688 +++++++++++++++-------------- 1 file changed, 854 insertions(+), 834 deletions(-) diff --git a/src/net/tcp_connection_states.cpp b/src/net/tcp_connection_states.cpp index 1df39c391b..79eadc9e7f 100644 --- a/src/net/tcp_connection_states.cpp +++ b/src/net/tcp_connection_states.cpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -19,78 +19,82 @@ using namespace std; - ///////////////////////////////////////////////////////////////////// /* COMMON STATE FUNCTIONS + + These functions are helper functions and used by more than one state. */ ///////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////// /* - 1. Check Sequence -*/ -/* + 1. Check Sequence number. + + Used for checking if the sequence number is acceptable. + + [RFC 793]: + SYN-RECEIVED STATE - ESTABLISHED STATE - FIN-WAIT-1 STATE - FIN-WAIT-2 STATE - CLOSE-WAIT STATE - CLOSING STATE - LAST-ACK STATE - TIME-WAIT STATE + ESTABLISHED STATE + FIN-WAIT-1 STATE + FIN-WAIT-2 STATE + CLOSE-WAIT STATE + CLOSING STATE + LAST-ACK STATE + TIME-WAIT STATE - Segments are processed in sequence. Initial tests on arrival - are used to discard old duplicates, but further processing is - done in SEG.SEQ order. If a segment's contents straddle the - boundary between old and new, only the new parts should be - processed. + Segments are processed in sequence. Initial tests on arrival + are used to discard old duplicates, but further processing is + done in SEG.SEQ order. If a segment's contents straddle the + boundary between old and new, only the new parts should be + processed. - There are four cases for the acceptability test for an incoming - segment: + There are four cases for the acceptability test for an incoming + segment: - Segment Receive Test - Length Window - ------- ------- ------------------------------------------- + Segment Receive Test + Length Window + ------- ------- ------------------------------------------- - 0 0 SEG.SEQ = RCV.NXT + 0 0 SEG.SEQ = RCV.NXT - 0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND + 0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND - >0 0 not acceptable + >0 0 not acceptable - >0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND - or RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND + >0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND + or RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND - If the RCV.WND is zero, no segments will be acceptable, but - special allowance should be made to accept valid ACKs, URGs and - RSTs. + If the RCV.WND is zero, no segments will be acceptable, but + special allowance should be made to accept valid ACKs, URGs and + RSTs. - If an incoming segment is not acceptable, an acknowledgment - should be sent in reply (unless the RST bit is set, if so drop - the segment and return): + If an incoming segment is not acceptable, an acknowledgment + should be sent in reply (unless the RST bit is set, if so drop + the segment and return): - + - After sending the acknowledgment, drop the unacceptable segment - and return. + After sending the acknowledgment, drop the unacceptable segment + and return. - In the following it is assumed that the segment is the idealized - segment that begins at RCV.NXT and does not exceed the window. - One could tailor actual segments to fit this assumption by - trimming off any portions that lie outside the window (including - SYN and FIN), and only processing further if the segment then - begins at RCV.NXT. Segments with higher begining sequence - numbers may be held for later processing. + In the following it is assumed that the segment is the idealized + segment that begins at RCV.NXT and does not exceed the window. + One could tailor actual segments to fit this assumption by + trimming off any portions that lie outside the window (including + SYN and FIN), and only processing further if the segment then + begins at RCV.NXT. Segments with higher begining sequence + numbers may be held for later processing. */ +///////////////////////////////////////////////////////////////////// -/* - TODO: Optimize this one. It checks for the same things. -*/ +// TODO: Optimize this one. It checks for the same things. bool Connection::State::check_seq(Connection& tcp, TCP::Packet_ptr in) { auto& tcb = tcp.tcb(); bool acceptable = false; debug2(" TCB: %s \n",tcb.to_string().c_str()); - // #1 + // #1 if( in->seq() == tcb.RCV.NXT ) { acceptable = true; } @@ -129,13 +133,17 @@ bool Connection::State::check_seq(Connection& tcp, TCP::Packet_ptr in) { // is acceptable. return true; } +///////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////// /* 4. Check SYN -*/ -/* + Used to filter out packets carrying SYN-flag when they're not supposed to. + + [RFC 793]: + SYN-RECEIVED ESTABLISHED STATE FIN-WAIT STATE-1 @@ -145,19 +153,21 @@ bool Connection::State::check_seq(Connection& tcp, TCP::Packet_ptr in) { LAST-ACK STATE TIME-WAIT STATE - If the SYN is in the window it is an error, send a reset, any - outstanding RECEIVEs and SEND should receive "reset" responses, - all segment queues should be flushed, the user should also - receive an unsolicited general "connection reset" signal, enter - the CLOSED state, delete the TCB, and return. + If the SYN is in the window it is an error, send a reset, any + outstanding RECEIVEs and SEND should receive "reset" responses, + all segment queues should be flushed, the user should also + receive an unsolicited general "connection reset" signal, enter + the CLOSED state, delete the TCB, and return. - If the SYN is not in the window this step would not be reached - and an ack would have been sent in the first step (sequence - number check). + If the SYN is not in the window this step would not be reached + and an ack would have been sent in the first step (sequence + number check). */ +///////////////////////////////////////////////////////////////////// + void Connection::State::unallowed_syn_reset_connection(Connection& tcp, TCP::Packet_ptr in) { assert(in->isset(SYN)); - debug(" Unallowed SYN for STATE: %s, reseting connection.\n", + debug(" Unallowed SYN for STATE: %s, reseting connection.\n", tcp.state().to_string().c_str()); // Not sure if this is the correct way to send a "reset response" tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); @@ -165,63 +175,70 @@ void Connection::State::unallowed_syn_reset_connection(Connection& tcp, TCP::Pac tcp.signal_disconnect(Disconnect::RESET); } +///////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////// /* 5. Check ACK + + "Process" the packet if ACK is present. If not, drop the packet. + + [RFC 793] Page 72-73. */ +///////////////////////////////////////////////////////////////////// + bool Connection::State::check_ack(Connection& tcp, TCP::Packet_ptr in) { - // 5. ACK bit debug2(" Checking for ACK in STATE: %s \n", tcp.state().to_string().c_str()); if( in->isset(ACK) ) { auto& tcb = tcp.tcb(); /* - If SND.UNA < SEG.ACK =< SND.NXT then, set SND.UNA <- SEG.ACK. - Any segments on the retransmission queue which are thereby - entirely acknowledged are removed. Users should receive - positive acknowledgments for buffers which have been SENT and - fully acknowledged (i.e., SEND buffer should be returned with - "ok" response). If the ACK is a duplicate - (SEG.ACK < SND.UNA), it can be ignored. If the ACK acks - something not yet sent (SEG.ACK > SND.NXT) then send an ACK, - drop the segment, and return. + If SND.UNA < SEG.ACK =< SND.NXT then, set SND.UNA <- SEG.ACK. + Any segments on the retransmission queue which are thereby + entirely acknowledged are removed. Users should receive + positive acknowledgments for buffers which have been SENT and + fully acknowledged (i.e., SEND buffer should be returned with + "ok" response). If the ACK is a duplicate + (SEG.ACK < SND.UNA), it can be ignored. If the ACK acks + something not yet sent (SEG.ACK > SND.NXT) then send an ACK, + drop the segment, and return. */ - if( tcb.SND.UNA < in->ack() and in->ack() <= tcb.SND.NXT ) { - tcb.SND.UNA = in->ack(); - // tcp.signal_sent(); - // return that buffer has been SENT - currently no support to receipt sent buffer. - - /* - If SND.UNA < SEG.ACK =< SND.NXT, the send window should be - updated. If (SND.WL1 < SEG.SEQ or (SND.WL1 = SEG.SEQ and - SND.WL2 =< SEG.ACK)), set SND.WND <- SEG.WND, set - SND.WL1 <- SEG.SEQ, and set SND.WL2 <- SEG.ACK. - */ - if( tcb.SND.WL1 < in->seq() or ( tcb.SND.WL1 = in->seq() and tcb.SND.WL2 <= in->ack() ) ) { - tcb.SND.WND = in->win(); - tcb.SND.WL1 = in->seq(); - tcb.SND.WL2 = in->ack(); - } - /* - Note that SND.WND is an offset from SND.UNA, that SND.WL1 - records the sequence number of the last segment used to update - SND.WND, and that SND.WL2 records the acknowledgment number of - the last segment used to update SND.WND. The check here - prevents using old segments to update the window. - */ - - } - /* If the ACK acks something not yet sent (SEG.ACK > SND.NXT) then send an ACK, drop the segment, and return. */ - else if( in->ack() > tcb.SND.NXT ) { - tcp.outgoing_packet()->set_flag(ACK); - tcp.transmit(); - tcp.drop(in, "ACK > SND.NXT"); - return false; - } - /* If the ACK is a duplicate (SEG.ACK < SND.UNA), it can be ignored. */ - /*else if( in->ack() < tcb.SND.UNA ) { - // ignore. - }*/ - return true; + if( tcb.SND.UNA < in->ack() and in->ack() <= tcb.SND.NXT ) { + tcb.SND.UNA = in->ack(); + // tcp.signal_sent(); + // return that buffer has been SENT - currently no support to receipt sent buffer. + + /* + If SND.UNA < SEG.ACK =< SND.NXT, the send window should be + updated. If (SND.WL1 < SEG.SEQ or (SND.WL1 = SEG.SEQ and + SND.WL2 =< SEG.ACK)), set SND.WND <- SEG.WND, set + SND.WL1 <- SEG.SEQ, and set SND.WL2 <- SEG.ACK. + */ + if( tcb.SND.WL1 < in->seq() or ( tcb.SND.WL1 = in->seq() and tcb.SND.WL2 <= in->ack() ) ) { + tcb.SND.WND = in->win(); + tcb.SND.WL1 = in->seq(); + tcb.SND.WL2 = in->ack(); + } + /* + Note that SND.WND is an offset from SND.UNA, that SND.WL1 + records the sequence number of the last segment used to update + SND.WND, and that SND.WL2 records the acknowledgment number of + the last segment used to update SND.WND. The check here + prevents using old segments to update the window. + */ + } + /* If the ACK acks something not yet sent (SEG.ACK > SND.NXT) then send an ACK, drop the segment, and return. */ + else if( in->ack() > tcb.SND.NXT ) { + tcp.outgoing_packet()->set_flag(ACK); + tcp.transmit(); + tcp.drop(in, "ACK > SND.NXT"); + return false; + } + /* If the ACK is a duplicate (SEG.ACK < SND.UNA), it can be ignored. */ + /*else if( in->ack() < tcb.SND.UNA ) { + // ignore. + }*/ + return true; } // ACK not set. else { @@ -230,37 +247,42 @@ bool Connection::State::check_ack(Connection& tcp, TCP::Packet_ptr in) { } } - +///////////////////////////////////////////////////////////////////// /* 7. Process the segment text -*/ -/* + + If a packet has data, process the data. + + [RFC 793] Page 74: + Once in the ESTABLISHED state, it is possible to deliver segment - text to user RECEIVE buffers. Text from segments can be moved - into buffers until either the buffer is full or the segment is - empty. If the segment empties and carries an PUSH flag, then - the user is informed, when the buffer is returned, that a PUSH - has been received. + text to user RECEIVE buffers. Text from segments can be moved + into buffers until either the buffer is full or the segment is + empty. If the segment empties and carries an PUSH flag, then + the user is informed, when the buffer is returned, that a PUSH + has been received. - When the TCP takes responsibility for delivering the data to the - user it must also acknowledge the receipt of the data. + When the TCP takes responsibility for delivering the data to the + user it must also acknowledge the receipt of the data. - Once the TCP takes responsibility for the data it advances - RCV.NXT over the data accepted, and adjusts RCV.WND as - apporopriate to the current buffer availability. The total of - RCV.NXT and RCV.WND should not be reduced. + Once the TCP takes responsibility for the data it advances + RCV.NXT over the data accepted, and adjusts RCV.WND as + apporopriate to the current buffer availability. The total of + RCV.NXT and RCV.WND should not be reduced. - Please note the window management suggestions in section 3.7. + Please note the window management suggestions in section 3.7. - Send an acknowledgment of the form: + Send an acknowledgment of the form: - + - This acknowledgment should be piggybacked on a segment being - transmitted if possible without incurring undue delay. + This acknowledgment should be piggybacked on a segment being + transmitted if possible without incurring undue delay. */ +///////////////////////////////////////////////////////////////////// + void Connection::State::process_segment(Connection& tcp, TCP::Packet_ptr in) { - assert(in->has_data()); + assert(in->has_data()); auto& tcb = tcp.tcb(); int length = in->data_length(); @@ -282,35 +304,39 @@ void Connection::State::process_segment(Connection& tcp, TCP::Packet_ptr in) { } /* Once the TCP takes responsibility for the data it advances - RCV.NXT over the data accepted, and adjusts RCV.WND as - apporopriate to the current buffer availability. The total of - RCV.NXT and RCV.WND should not be reduced. - */ + RCV.NXT over the data accepted, and adjusts RCV.WND as + apporopriate to the current buffer availability. The total of + RCV.NXT and RCV.WND should not be reduced. + */ if(tcb.SND.NXT == snd_nxt) { tcp.outgoing_packet()->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); tcp.transmit(); } else { debug2(" SND.NXT > snd_nxt, this packet has already been acknowledged. \n"); } - } +///////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////// /* - 8. Check FIN -*/ + 8. Process FIN + + Process a packet with FIN, by signal disconnect, reply with ACK etc. + + [RFC 793] Page 75: -/* If the FIN bit is set, signal the user "connection closing" and return any pending RECEIVEs with same message, advance RCV.NXT over the FIN, and send an acknowledgment for the FIN. Note that FIN implies PUSH for any segment text not yet delivered to the user. */ +///////////////////////////////////////////////////////////////////// void Connection::State::process_fin(Connection& tcp, TCP::Packet_ptr in) { - debug(" Processing FIN bit in STATE: %s \n", tcp.state().to_string().c_str()); - assert(in->isset(FIN)); - auto& tcb = tcp.tcb(); + debug(" Processing FIN bit in STATE: %s \n", tcp.state().to_string().c_str()); + assert(in->isset(FIN)); + auto& tcb = tcp.tcb(); tcp.signal_disconnect(Disconnect::CLOSING); // Advance RCV.NXT over the FIN? tcb.RCV.NXT++; @@ -322,8 +348,13 @@ void Connection::State::process_fin(Connection& tcp, TCP::Packet_ptr in) { tcp.signal_receive(true); } } +///////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////// /* + Send a reset segment. Used when aborting a connection. + + [RFC 793]: Send a reset segment: @@ -333,874 +364,863 @@ void Connection::State::process_fin(Connection& tcp, TCP::Packet_ptr in) { RST formed above) or retransmission should be flushed, delete the TCB, enter CLOSED state, and return. */ +///////////////////////////////////////////////////////////////////// + void Connection::State::send_reset(Connection& tcp) { tcp.send_buffer_.clear(); tcp.outgoing_packet()->set_seq(tcp.tcb().SND.NXT).set_ack(0).set_flag(RST); tcp.transmit(); } +///////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////// /* - Fallback. + STATE IMPLEMENTATION + + Here follows the implementation for all the different State-Event combinations. + + The implemenation is ordered in the following structure: + 1. Function + 2. State + + Function order: + OPEN + SEND + RECEIVE + CLOSE + ABORT + HANDLE (SEGMENT ARRIVES) + + State order: + State - this is the base state, works as fallback. + Closed + Listen + SynSent + SynReceived + Established + FinWait1 + FinWait2 + CloseWait + Closing + LastAck + TimeWait */ - -void Connection::State::open(Connection&, bool) { - throw TCPException{"Connection already exists."}; -} - -size_t Connection::State::send(Connection&, const char*, size_t, bool) { - throw TCPException{"Connection closing."}; -} - -size_t Connection::State::receive(Connection&, char*, size_t) { - throw TCPException{"Connection closing."}; -} - -void Connection::State::close(Connection&) { - throw TCPException{"Connection closing."}; -} - -void Connection::State::abort(Connection&) { - // Do nothing. -} ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /* - CLOSED + OPEN */ ///////////////////////////////////////////////////////////////////// -void Connection::Closed::open(Connection& tcp, bool active) { - if(active) { - // There is a remote host - if(!tcp.remote().is_empty()) { - auto& tcb = tcp.tcb(); - tcb.ISS = tcp.generate_iss(); - auto packet = tcp.outgoing_packet(); - packet->set_seq(tcb.ISS).set_flag(SYN); - - /* - Add MSS option. - */ - tcp.add_option(Option::MSS, packet); - - tcb.SND.UNA = tcb.ISS; - tcb.SND.NXT = tcb.ISS+1; - tcp.transmit(); - tcp.set_state(SynSent::instance()); - } else { - throw TCPException{"No remote host set."}; - } - } else { - tcp.set_state(Connection::Listen::instance()); - } +void Connection::State::open(Connection&, bool) { + throw TCPException{"Connection already exists."}; } -size_t Connection::Closed::send(Connection&, const char*, size_t, bool) { - throw TCPException{"Connection does not exist."}; +void Connection::Closed::open(Connection& tcp, bool active) { + if(active) { + // There is a remote host + if(!tcp.remote().is_empty()) { + auto& tcb = tcp.tcb(); + tcb.ISS = tcp.generate_iss(); + auto packet = tcp.outgoing_packet(); + packet->set_seq(tcb.ISS).set_flag(SYN); + + /* + Add MSS option. + */ + tcp.add_option(Option::MSS, packet); + + tcb.SND.UNA = tcb.ISS; + tcb.SND.NXT = tcb.ISS+1; + tcp.transmit(); + tcp.set_state(SynSent::instance()); + } else { + throw TCPException{"No remote host set."}; + } + } else { + tcp.set_state(Connection::Listen::instance()); + } } -State::Result Connection::Closed::handle(Connection& tcp, TCP::Packet_ptr in) { - if(in->isset(RST)) { - return OK; - } - if(!in->isset(ACK)) { - tcp.outgoing_packet()->set_seq(0).set_ack(in->seq() + in->data_length()).set_flags(RST | ACK); - } else { - tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); - } - tcp.transmit(); - return OK; +void Connection::Listen::open(Connection& tcp, bool) { + if(!tcp.remote().is_empty()) { + auto& tcb = tcp.tcb(); + tcb.ISS = tcp.generate_iss(); + tcp.outgoing_packet()->set_seq(tcb.ISS).set_flag(SYN); + tcb.SND.UNA = tcb.ISS; + tcb.SND.NXT = tcb.ISS+1; + tcp.transmit(); + tcp.set_state(SynSent::instance()); + } else { + throw TCPException{"No remote host set."}; + } } + + ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /* - LISTEN + SEND */ ///////////////////////////////////////////////////////////////////// -void Connection::Listen::open(Connection& tcp, bool) { - if(!tcp.remote().is_empty()) { - auto& tcb = tcp.tcb(); - tcb.ISS = tcp.generate_iss(); - tcp.outgoing_packet()->set_seq(tcb.ISS).set_flag(SYN); - tcb.SND.UNA = tcb.ISS; - tcb.SND.NXT = tcb.ISS+1; - tcp.transmit(); - tcp.set_state(SynSent::instance()); - } else { - throw TCPException{"No remote host set."}; - } +size_t Connection::State::send(Connection&, const char*, size_t, bool) { + throw TCPException{"Connection closing."}; } -size_t Connection::Listen::send(Connection&, const char*, size_t, bool) { - // TODO: Skip this? - /* - If the foreign socket is specified, then change the connection - from passive to active, select an ISS. Send a SYN segment, set - SND.UNA to ISS, SND.NXT to ISS+1. Enter SYN-SENT state. Data - associated with SEND may be sent with SYN segment or queued for - transmission after entering ESTABLISHED state. The urgent bit if - requested in the command must be sent with the data segments sent - as a result of this command. If there is no room to queue the - request, respond with "error: insufficient resources". If - Foreign socket was not specified, then return "error: foreign - socket unspecified". - */ - - return 0; +size_t Connection::Closed::send(Connection&, const char*, size_t, bool) { + throw TCPException{"Connection does not exist."}; } -void Connection::Listen::close(Connection& tcp) { - /* - Any outstanding RECEIVEs are returned with "error: closing" - responses. Delete TCB, enter CLOSED state, and return. - */ +size_t Connection::Listen::send(Connection&, const char*, size_t, bool) { + // TODO: Skip this? + /* + If the foreign socket is specified, then change the connection + from passive to active, select an ISS. Send a SYN segment, set + SND.UNA to ISS, SND.NXT to ISS+1. Enter SYN-SENT state. Data + associated with SEND may be sent with SYN segment or queued for + transmission after entering ESTABLISHED state. The urgent bit if + requested in the command must be sent with the data segments sent + as a result of this command. If there is no room to queue the + request, respond with "error: insufficient resources". If + Foreign socket was not specified, then return "error: foreign + socket unspecified". + */ + return 0; +} - // tcp.signal_disconnect("Closing") - tcp.set_state(Closed::instance()); +size_t Connection::SynSent::send(Connection& tcp, const char* buffer, size_t n, bool push) { + /* + Queue the data for transmission after entering ESTABLISHED state. + If no space to queue, respond with "error: insufficient + resources". + */ + //return tcp.write_to_send_buffer(buffer, n, push); + return 0; } +size_t Connection::SynReceived::send(Connection& tcp, const char* buffer, size_t n, bool push) { + /* + Queue the data for transmission after entering ESTABLISHED state. + If no space to queue, respond with "error: insufficient + resources". + */ + return tcp.write_to_send_buffer(buffer, n, push); +} -State::Result Connection::Listen::handle(Connection& tcp, TCP::Packet_ptr in) { - if(in->isset(RST)) { - // ignore - return OK; - } - if(in->isset(ACK)) { - tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); - tcp.transmit(); - return OK; - } - if(in->isset(SYN)) { - if(!tcp.signal_accept()) { - // TODO: Reject more gracefully? - return CLOSED; - } - auto& tcb = tcp.tcb(); - tcb.RCV.NXT = in->seq()+1; - tcb.IRS = in->seq(); - tcb.ISS = tcp.generate_iss(); - tcb.SND.NXT = tcb.ISS+1; - tcb.SND.UNA = tcb.ISS; - debug(" Received SYN Packet: %s TCB Updated:\n %s \n", - in->to_string().c_str(), tcp.tcb().to_string().c_str()); - - auto packet = tcp.outgoing_packet(); - packet->set_seq(tcb.ISS).set_ack(tcb.RCV.NXT).set_flags(SYN | ACK); - - /* - Add MSS option. - TODO: Send even if we havent received MSS option? - */ - tcp.add_option(Option::MSS, packet); - - tcp.transmit(); - tcp.set_state(SynReceived::instance()); +size_t Connection::Established::send(Connection& tcp, const char* buffer, size_t n, bool push) { + debug(" Sending data with the length of %u. PUSH: %d \n", n, push); + auto bytes_written = tcp.write_to_send_buffer(buffer, n, push); + tcp.transmit(); + return bytes_written; +} - return OK; - } - return OK; +size_t Connection::CloseWait::send(Connection& tcp, const char* buffer, size_t n, bool push) { + debug(" Sending data with the length of %u. PUSH: %d \n", n, push); + auto bytes_written = tcp.write_to_send_buffer(buffer, n, push); + tcp.transmit(); + return bytes_written; } + ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// -/* - SYN-SENT +/* + RECEIVE */ ///////////////////////////////////////////////////////////////////// -size_t Connection::SynSent::send(Connection& tcp, const char* buffer, size_t n, bool push) { - /* - Queue the data for transmission after entering ESTABLISHED state. - If no space to queue, respond with "error: insufficient - resources". - */ - return tcp.write_to_send_buffer(buffer, n, push); +size_t Connection::State::receive(Connection&, char*, size_t) { + throw TCPException{"Connection closing."}; } -void Connection::SynSent::close(Connection& tcp) { - /* - Delete the TCB and return "error: closing" responses to any - queued SENDs, or RECEIVEs. - */ - - // tcp.signal_disconnect("Closing") - tcp.set_state(Closed::instance()); +size_t Connection::Established::receive(Connection& tcp, char* buffer, size_t n) { + return tcp.read_from_receive_buffer(buffer, n); } +size_t Connection::FinWait1::receive(Connection& tcp, char* buffer, size_t n) { + return tcp.read_from_receive_buffer(buffer, n); +} -State::Result Connection::SynSent::handle(Connection& tcp, TCP::Packet_ptr in) { - auto& tcb = tcp.tcb(); - // 1. check ACK - if(in->isset(ACK)) { - // If SEG.ACK =< ISS, or SEG.ACK > SND.NXT - if(in->ack() <= tcb.ISS or in->ack() > tcb.SND.NXT) { - // send a reset - if(!in->isset(RST)) { - tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); - tcp.transmit(); - return OK; - } - // (unless the RST bit is set, if so drop the segment and return) - else { - tcp.drop(in, "RST"); - return OK; - } - // If SND.UNA =< SEG.ACK =< SND.NXT then the ACK is acceptable. - } - } - // 2. check RST - if(in->isset(RST)) { - if(in->isset(ACK)) { - tcp.signal_error(TCPException{"Connection reset."}); - tcp.drop(in, "RST with acceptable ACK"); - return CLOSED; - } else { - tcp.drop(in, "RST"); - return OK; - } - /* - If the ACK was acceptable then signal the user "error: - connection reset", drop the segment, enter CLOSED state, - delete TCB, and return. Otherwise (no ACK) drop the segment - and return. - */ - - } - // 3. Check security - - // 4. check SYN - /* - This step should be reached only if the ACK is ok, or there is - no ACK, and it the segment did not contain a RST. - - If the SYN bit is on and the security/compartment and precedence - are acceptable then, RCV.NXT is set to SEG.SEQ+1, IRS is set to - SEG.SEQ. SND.UNA should be advanced to equal SEG.ACK (if there - is an ACK), and any segments on the retransmission queue which - are thereby acknowledged should be removed. - - If SND.UNA > ISS (our SYN has been ACKed), change the connection - state to ESTABLISHED, form an ACK segment - - - - and send it. Data or controls which were queued for - transmission may be included. If there are other controls or - text in the segment then continue processing at the sixth step - below where the URG bit is checked, otherwise return. - - Otherwise enter SYN-RECEIVED, form a SYN,ACK segment - - +size_t Connection::FinWait2::receive(Connection& tcp, char* buffer, size_t n) { + return tcp.read_from_receive_buffer(buffer, n); +} - and send it. If there are other controls or text in the - segment, queue them for processing after the ESTABLISHED state - has been reached, return. - */ - /* - TODO: Fix this one according to the text above. - */ - if(in->isset(SYN)) { - tcb.RCV.NXT = in->seq()+1; - tcb.IRS = in->seq(); - tcb.SND.UNA = in->ack(); - - // (our SYN has been ACKed) - if(tcb.SND.UNA > tcb.ISS) { - tcp.set_state(Connection::Established::instance()); - TCP::Seq snd_nxt = tcb.SND.NXT; - tcp.signal_connect(); // NOTE: User callback - if(tcb.SND.NXT == snd_nxt) { - tcp.outgoing_packet()->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); - tcp.transmit(); - } - // State is now ESTABLISHED. - // Experimental, also makes unessecary process. - //in->clear_flag(SYN); - //tcp.state().handle(tcp, in); - - // 7. process segment text - if(in->has_data()) { - process_segment(tcp, in); - } - - // 8. check FIN bit - if(in->isset(FIN)) { - process_fin(tcp, in); - tcp.set_state(Connection::CloseWait::instance()); - return OK; - } - return OK; - } - // Otherwise enter SYN-RECEIVED, form a SYN,ACK segment - else { - tcp.outgoing_packet()->set_seq(tcb.ISS).set_ack(tcb.RCV.NXT).set_flags(SYN | ACK); - tcp.transmit(); - tcp.set_state(Connection::SynReceived::instance()); - if(in->has_data()) { - tcp.add_to_receive_buffer(in); - // Advance RCV.NXT ?? - tcb.RCV.NXT += in->data_length(); - } - return OK; - /* - If there are other controls or text in the - segment, queue them for processing after the ESTABLISHED state - has been reached, return. - - HOW? return tcp.receive(in); ? - */ - } - } - tcp.drop(in); - return OK; +size_t Connection::CloseWait::receive(Connection& tcp, char* buffer, size_t n) { + return tcp.read_from_receive_buffer(buffer, n); } + ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /* - SYN-RECEIVED + CLOSE */ ///////////////////////////////////////////////////////////////////// -size_t Connection::SynReceived::send(Connection& tcp, const char* buffer, size_t n, bool push) { - /* - Queue the data for transmission after entering ESTABLISHED state. - If no space to queue, respond with "error: insufficient - resources". - */ - return tcp.write_to_send_buffer(buffer, n, push); +void Connection::State::close(Connection&) { + throw TCPException{"Connection closing."}; +} + +void Connection::Listen::close(Connection& tcp) { + /* + Any outstanding RECEIVEs are returned with "error: closing" + responses. Delete TCB, enter CLOSED state, and return. + */ + // tcp.signal_disconnect("Closing") + tcp.set_state(Closed::instance()); +} + +void Connection::SynSent::close(Connection& tcp) { + /* + Delete the TCB and return "error: closing" responses to any + queued SENDs, or RECEIVEs. + */ + // tcp.signal_disconnect("Closing") + tcp.set_state(Closed::instance()); } void Connection::SynReceived::close(Connection& tcp) { - /* - If no SENDs have been issued and there is no pending data to send, + /* + If no SENDs have been issued and there is no pending data to send, then form a FIN segment and send it, and enter FIN-WAIT-1 state; otherwise queue for processing after entering ESTABLISHED state. - */ - // Dont know how to queue for close for processing... - auto& tcb = tcp.tcb(); - tcp.outgoing_packet()->set_seq(tcb.SND.NXT++).set_ack(tcb.RCV.NXT).set_flags(ACK | FIN); - tcp.transmit(); - tcp.set_state(Connection::FinWait1::instance()); + */ + // Dont know how to queue for close for processing... + auto& tcb = tcp.tcb(); + tcp.outgoing_packet()->set_seq(tcb.SND.NXT++).set_ack(tcb.RCV.NXT).set_flags(ACK | FIN); + tcp.transmit(); + tcp.set_state(Connection::FinWait1::instance()); } void Connection::SynReceived::abort(Connection& tcp) { - send_reset(tcp); + send_reset(tcp); } -State::Result Connection::SynReceived::handle(Connection& tcp, TCP::Packet_ptr in) { - // 1. check sequence - if(! check_seq(tcp, in) ) { - return OK; - } - // 2. check RST - if(in->isset(RST)) { - /* - If this connection was initiated with a passive OPEN (i.e., - came from the LISTEN state), then return this connection to - LISTEN state and return. The user need not be informed. If - this connection was initiated with an active OPEN (i.e., came - from SYN-SENT state) then the connection was refused, signal - the user "connection refused". In either case, all segments - on the retransmission queue should be removed. And in the - active OPEN case, enter the CLOSED state and delete the TCB, - and return. - */ - // Since we create a new connection when it starts listening, we don't wanna do this, but just delete it. - - if(tcp.prev_state().to_string() == Connection::SynSent::instance().to_string()) { - tcp.signal_disconnect(Disconnect::REFUSED); - } - - return CLOSED; - } - // 3. check security +void Connection::Established::close(Connection& tcp) { + auto& tcb = tcp.tcb(); + tcp.outgoing_packet()->set_seq(tcb.SND.NXT++).set_ack(tcb.RCV.NXT).set_flags(ACK | FIN); + tcp.transmit(); + tcp.set_state(Connection::FinWait1::instance()); +} - // 4. check SYN - if( in->isset(SYN) ) { - unallowed_syn_reset_connection(tcp, in); - return CLOSED; - } +void Connection::FinWait1::close(Connection&) { + /* + Strictly speaking, this is an error and should receive a "error: + connection closing" response. An "ok" response would be + acceptable, too, as long as a second FIN is not emitted (the first + FIN may be retransmitted though). + */ +} - // 5. check ACK - if(in->isset(ACK)) { - auto& tcb = tcp.tcb(); - /* - If SND.UNA =< SEG.ACK =< SND.NXT then enter ESTABLISHED state - and continue processing. - */ - if(tcb.SND.UNA <= in->ack() and in->ack() <= tcb.SND.NXT) { - debug(" SND.UNA =< SEG.ACK =< SND.NXT, continue in ESTABLISHED. \n"); - tcp.set_state(Connection::Established::instance()); - tcp.signal_connect(); // NOTE: User callback - return tcp.state().handle(tcp,in); // TODO: Fix. This is kinda bad, need to make the above steps again. - } - /* - If the segment acknowledgment is not acceptable, form a - reset segment, and send it. - */ - else { - tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); - tcp.transmit(); - } - } - // ACK is missing - else { - tcp.drop(in, "SYN-RCV: !ACK"); - return OK; - } +void Connection::FinWait2::close(Connection&) { + /* + Strictly speaking, this is an error and should receive a "error: + connection closing" response. An "ok" response would be + acceptable, too, as long as a second FIN is not emitted (the first + FIN may be retransmitted though). + */ +} - // 8. check FIN - if(in->isset(FIN)) { - process_fin(tcp, in); - tcp.set_state(Connection::CloseWait::instance()); - return OK; - } - return OK; +void Connection::CloseWait::close(Connection& tcp) { + /* + Queue this request until all preceding SENDs have been + segmentized; then send a FIN segment, enter CLOSING state. + */ + auto& tcb = tcp.tcb(); + tcp.outgoing_packet()->set_seq(tcb.SND.NXT++).set_ack(tcb.RCV.NXT).set_flags(ACK | FIN); + tcp.transmit(); + tcp.set_state(Connection::Closing::instance()); } + ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /* - ESTABLISHED + ABORT */ ///////////////////////////////////////////////////////////////////// -/* - Segmentize the buffer and send it with a piggybacked - acknowledgment (acknowledgment value = RCV.NXT). If there is - insufficient space to remember this buffer, simply return "error: - insufficient resources". +void Connection::State::abort(Connection&) { + // Do nothing. +} - If the urgent flag is set, then SND.UP <- SND.NXT-1 and set the - urgent pointer in the outgoing segments. -*/ -size_t Connection::Established::send(Connection& tcp, const char* buffer, size_t n, bool push) { - debug(" Sending data with the length of %u. PUSH: %d \n", n, push); - auto bytes_written = tcp.write_to_send_buffer(buffer, n, push); - tcp.transmit(); - return bytes_written; - /* - 3.7 Data Communication - The sender of data keeps track of the next sequence number to use in - the variable SND.NXT. The receiver of data keeps track of the next - sequence number to expect in the variable RCV.NXT. The sender of data - keeps track of the oldest unacknowledged sequence number in the - variable SND.UNA. If the data flow is momentarily idle and all data - sent has been acknowledged then the three variables will be equal. - - When the sender creates a segment and transmits it the sender advances - SND.NXT. When the receiver accepts a segment it advances RCV.NXT and - sends an acknowledgment. When the data sender receives an - acknowledgment it advances SND.UNA. The extent to which the values of - these variables differ is a measure of the delay in the communication. - The amount by which the variables are advanced is the length of the - data in the segment. Note that once in the ESTABLISHED state all - segments must carry current acknowledgment information. - */ +void Connection::Established::abort(Connection& tcp) { + send_reset(tcp); } -size_t Connection::Established::receive(Connection& tcp, char* buffer, size_t n) { - return tcp.read_from_receive_buffer(buffer, n); +void Connection::FinWait1::abort(Connection& tcp) { + send_reset(tcp); } -void Connection::Established::close(Connection& tcp) { - auto& tcb = tcp.tcb(); - tcp.outgoing_packet()->set_seq(tcb.SND.NXT++).set_ack(tcb.RCV.NXT).set_flags(ACK | FIN); - tcp.transmit(); - tcp.set_state(Connection::FinWait1::instance()); +void Connection::FinWait2::abort(Connection& tcp) { + send_reset(tcp); } -void Connection::Established::abort(Connection& tcp) { - send_reset(tcp); +void Connection::CloseWait::abort(Connection& tcp) { + send_reset(tcp); } -State::Result Connection::Established::handle(Connection& tcp, TCP::Packet_ptr in) { - // 1. check SEQ - if(! check_seq(tcp, in) ) { - return OK; - } +///////////////////////////////////////////////////////////////////// - // 2. check RST - if( in->isset(RST) ) { - tcp.signal_disconnect(Disconnect::RESET); - return CLOSED; // close - } - // 3. check security +///////////////////////////////////////////////////////////////////// +/* + HANDLE (SEGMENT ARRIVES) +*/ +///////////////////////////////////////////////////////////////////// - // 4. check SYN - if( in->isset(SYN) ) { - unallowed_syn_reset_connection(tcp, in); - return CLOSED; - } +State::Result Connection::Closed::handle(Connection& tcp, TCP::Packet_ptr in) { + if(in->isset(RST)) { + return OK; + } + if(!in->isset(ACK)) { + tcp.outgoing_packet()->set_seq(0).set_ack(in->seq() + in->data_length()).set_flags(RST | ACK); + } else { + tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); + } + tcp.transmit(); + return OK; +} - // 5. check ACK - if( ! check_ack(tcp, in) ) { - return OK; - } - // 6. check URG - DEPRECATED - // 7. proccess the segment text - if(in->has_data()) { - process_segment(tcp, in); +State::Result Connection::Listen::handle(Connection& tcp, TCP::Packet_ptr in) { + if(in->isset(RST)) { + // ignore + return OK; + } + if(in->isset(ACK)) { + tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); + tcp.transmit(); + return OK; + } + if(in->isset(SYN)) { + if(!tcp.signal_accept()) { + // TODO: Reject more gracefully? + return CLOSED; } + auto& tcb = tcp.tcb(); + tcb.RCV.NXT = in->seq()+1; + tcb.IRS = in->seq(); + tcb.ISS = tcp.generate_iss(); + tcb.SND.NXT = tcb.ISS+1; + tcb.SND.UNA = tcb.ISS; + debug(" Received SYN Packet: %s TCB Updated:\n %s \n", + in->to_string().c_str(), tcp.tcb().to_string().c_str()); - // 8. check FIN bit - if(in->isset(FIN)) { - process_fin(tcp, in); - tcp.set_state(Connection::CloseWait::instance()); - return CLOSE; - } - return OK; -} -///////////////////////////////////////////////////////////////////// + auto packet = tcp.outgoing_packet(); + packet->set_seq(tcb.ISS).set_ack(tcb.RCV.NXT).set_flags(SYN | ACK); + /* + Add MSS option. + TODO: Send even if we havent received MSS option? + */ + tcp.add_option(Option::MSS, packet); -///////////////////////////////////////////////////////////////////// -/* - FIN-WAIT-1 -*/ -///////////////////////////////////////////////////////////////////// + tcp.transmit(); + tcp.set_state(SynReceived::instance()); -size_t Connection::FinWait1::receive(Connection& tcp, char* buffer, size_t n) { - return tcp.read_from_receive_buffer(buffer, n); + return OK; + } + return OK; } -void Connection::FinWait1::close(Connection&) { -} +State::Result Connection::SynSent::handle(Connection& tcp, TCP::Packet_ptr in) { + // 1. check ACK + if(in->isset(ACK)) { + auto& tcb = tcp.tcb(); + // If SEG.ACK =< ISS, or SEG.ACK > SND.NXT + if(in->ack() <= tcb.ISS or in->ack() > tcb.SND.NXT) { + // send a reset + if(!in->isset(RST)) { + tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); + tcp.transmit(); + return OK; + } + // (unless the RST bit is set, if so drop the segment and return) + else { + tcp.drop(in, "RST"); + return OK; + } + // If SND.UNA =< SEG.ACK =< SND.NXT then the ACK is acceptable. + } + } + + // 2. check RST + if(in->isset(RST)) { + if(in->isset(ACK)) { + tcp.signal_error(TCPException{"Connection reset."}); + tcp.drop(in, "RST with acceptable ACK"); + return CLOSED; + } else { + tcp.drop(in, "RST"); + return OK; + } + /* + If the ACK was acceptable then signal the user "error: + connection reset", drop the segment, enter CLOSED state, + delete TCB, and return. Otherwise (no ACK) drop the segment + and return. + */ + } + // 3. Check security -void Connection::FinWait1::abort(Connection& tcp) { - send_reset(tcp); -} + // 4. check SYN + /* + This step should be reached only if the ACK is ok, or there is + no ACK, and it the segment did not contain a RST. -State::Result Connection::FinWait1::handle(Connection& tcp, TCP::Packet_ptr in) { - // 1. Check sequence number - if(! check_seq(tcp, in) ) { - return OK; + If the SYN bit is on and the security/compartment and precedence + are acceptable then, RCV.NXT is set to SEG.SEQ+1, IRS is set to + SEG.SEQ. SND.UNA should be advanced to equal SEG.ACK (if there + is an ACK), and any segments on the retransmission queue which + are thereby acknowledged should be removed. + + If SND.UNA > ISS (our SYN has been ACKed), change the connection + state to ESTABLISHED, form an ACK segment + + + + and send it. Data or controls which were queued for + transmission may be included. If there are other controls or + text in the segment then continue processing at the sixth step + below where the URG bit is checked, otherwise return. + + Otherwise enter SYN-RECEIVED, form a SYN,ACK segment + + + + and send it. If there are other controls or text in the + segment, queue them for processing after the ESTABLISHED state + has been reached, return. + */ + + // TODO: Fix this one according to the text above. + if(in->isset(SYN)) { + tcb.RCV.NXT = in->seq()+1; + tcb.IRS = in->seq(); + tcb.SND.UNA = in->ack(); + + // (our SYN has been ACKed) + if(tcb.SND.UNA > tcb.ISS) { + tcp.set_state(Connection::Established::instance()); + TCP::Seq snd_nxt = tcb.SND.NXT; + tcp.signal_connect(); // NOTE: User callback + + if(tcb.SND.NXT == snd_nxt) { + tcp.outgoing_packet()->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); + tcp.transmit(); + } + // State is now ESTABLISHED. + // Experimental, also makes unessecary process. + //in->clear_flag(SYN); + //tcp.state().handle(tcp, in); + + // 7. process segment text + if(in->has_data()) { + process_segment(tcp, in); + } + + // 8. check FIN bit + if(in->isset(FIN)) { + process_fin(tcp, in); + tcp.set_state(Connection::CloseWait::instance()); + return OK; + } + return OK; } + // Otherwise enter SYN-RECEIVED, form a SYN,ACK segment + else { + tcp.outgoing_packet()->set_seq(tcb.ISS).set_ack(tcb.RCV.NXT).set_flags(SYN | ACK); + tcp.transmit(); + tcp.set_state(Connection::SynReceived::instance()); + if(in->has_data()) { + tcp.add_to_receive_buffer(in); + // Advance RCV.NXT ?? + tcb.RCV.NXT += in->data_length(); + } + return OK; + /* + If there are other controls or text in the + segment, queue them for processing after the ESTABLISHED state + has been reached, return. - // 2. check RST - if( in->isset(RST) ) { - tcp.signal_disconnect(Disconnect::RESET); - return CLOSED; // close + HOW? return tcp.receive(in); ? + */ } + } + tcp.drop(in); + return OK; +} - // 4. check SYN - if( in->isset(SYN) ) { - unallowed_syn_reset_connection(tcp, in); - return CLOSED; - } - // 5. check ACK - if( ! check_ack(tcp, in) ) { - return OK; - } +State::Result Connection::SynReceived::handle(Connection& tcp, TCP::Packet_ptr in) { + // 1. check sequence + if(! check_seq(tcp, in) ) { + return OK; + } + // 2. check RST + if(in->isset(RST)) { /* - In addition to the processing for the ESTABLISHED state, if - our FIN is now acknowledged then enter FIN-WAIT-2 and continue - processing in that state. + If this connection was initiated with a passive OPEN (i.e., + came from the LISTEN state), then return this connection to + LISTEN state and return. The user need not be informed. If + this connection was initiated with an active OPEN (i.e., came + from SYN-SENT state) then the connection was refused, signal + the user "connection refused". In either case, all segments + on the retransmission queue should be removed. And in the + active OPEN case, enter the CLOSED state and delete the TCB, + and return. */ - debug2(" Current TCB:\n %s \n", tcp.tcb().to_string().c_str()); - if(in->ack() == tcp.tcb().SND.NXT) { - // TODO: I guess or FIN is ACK'ed..? - tcp.set_state(Connection::FinWait2::instance()); - return tcp.state().handle(tcp, in); // TODO: Is this OK? - } + // Since we create a new connection when it starts listening, we don't wanna do this, but just delete it. - // 7. proccess the segment text - if(in->has_data()) { - process_segment(tcp, in); + if(tcp.prev_state().to_string() == Connection::SynSent::instance().to_string()) { + tcp.signal_disconnect(Disconnect::REFUSED); } - // 8. check FIN - if(in->isset(FIN)) { - process_fin(tcp, in); - debug2(" FIN isset. TCB:\n %s \n", tcp.tcb().to_string().c_str()); - /* - If our FIN has been ACKed (perhaps in this segment), then - enter TIME-WAIT, start the time-wait timer, turn off the other - timers; otherwise enter the CLOSING state. - */ - if(in->ack() == tcp.tcb().SND.NXT) { - // TODO: I guess or FIN is ACK'ed..? - tcp.set_state(TimeWait::instance()); - tcp.start_time_wait_timeout(); - } else { - tcp.set_state(Closing::instance()); - } + return CLOSED; + } + // 3. check security + + // 4. check SYN + if( in->isset(SYN) ) { + unallowed_syn_reset_connection(tcp, in); + return CLOSED; + } + + // 5. check ACK + if(in->isset(ACK)) { + auto& tcb = tcp.tcb(); + /* + If SND.UNA =< SEG.ACK =< SND.NXT then enter ESTABLISHED state + and continue processing. + */ + if(tcb.SND.UNA <= in->ack() and in->ack() <= tcb.SND.NXT) { + debug(" SND.UNA =< SEG.ACK =< SND.NXT, continue in ESTABLISHED. \n"); + tcp.set_state(Connection::Established::instance()); + tcp.signal_connect(); // NOTE: User callback + return tcp.state().handle(tcp,in); // TODO: Fix. This is kinda bad, need to make the above steps again. } + /* + If the segment acknowledgment is not acceptable, form a + reset segment, and send it. + */ + else { + tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); + tcp.transmit(); + } + } + // ACK is missing + else { + tcp.drop(in, "SYN-RCV: !ACK"); return OK; -} -///////////////////////////////////////////////////////////////////// + } + // 8. check FIN + if(in->isset(FIN)) { + process_fin(tcp, in); + tcp.set_state(Connection::CloseWait::instance()); + return OK; + } + return OK; +} -///////////////////////////////////////////////////////////////////// -/* - FIN-WAIT-2 -*/ -///////////////////////////////////////////////////////////////////// -size_t Connection::FinWait2::receive(Connection& tcp, char* buffer, size_t n) { - return tcp.read_from_receive_buffer(buffer, n); -} +State::Result Connection::Established::handle(Connection& tcp, TCP::Packet_ptr in) { + // 1. check SEQ + if(! check_seq(tcp, in) ) { + return OK; + } -void Connection::FinWait2::close(Connection&) { - -} + // 2. check RST + if( in->isset(RST) ) { + tcp.signal_disconnect(Disconnect::RESET); + return CLOSED; // close + } -void Connection::FinWait2::abort(Connection& tcp) { - send_reset(tcp); -} + // 3. check security -State::Result Connection::FinWait2::handle(Connection& tcp, TCP::Packet_ptr in) { - // 1. check SEQ - if(! check_seq(tcp, in) ) { - return OK; - } + // 4. check SYN + if( in->isset(SYN) ) { + unallowed_syn_reset_connection(tcp, in); + return CLOSED; + } - // 2. check RST - if( in->isset(RST) ) { - tcp.signal_disconnect(Disconnect::RESET); - return CLOSED; // close - } + // 5. check ACK + if( ! check_ack(tcp, in) ) { + return OK; + } + // 6. check URG - DEPRECATED + + // 7. proccess the segment text + if(in->has_data()) { + process_segment(tcp, in); + } + + // 8. check FIN bit + if(in->isset(FIN)) { + process_fin(tcp, in); + tcp.set_state(Connection::CloseWait::instance()); + return CLOSE; + } + return OK; +} - // 4. check SYN - if( in->isset(SYN) ) { - unallowed_syn_reset_connection(tcp, in); - return CLOSED; - } - // 5. check ACK - if( ! check_ack(tcp, in) ) { - return OK; +State::Result Connection::FinWait1::handle(Connection& tcp, TCP::Packet_ptr in) { + // 1. Check sequence number + if(! check_seq(tcp, in) ) { + return OK; + } + + // 2. check RST + if( in->isset(RST) ) { + tcp.signal_disconnect(Disconnect::RESET); + return CLOSED; // close + } + + // 4. check SYN + if( in->isset(SYN) ) { + unallowed_syn_reset_connection(tcp, in); + return CLOSED; + } + + // 5. check ACK + if( ! check_ack(tcp, in) ) { + return OK; + } + /* + In addition to the processing for the ESTABLISHED state, if + our FIN is now acknowledged then enter FIN-WAIT-2 and continue + processing in that state. + */ + debug2(" Current TCB:\n %s \n", tcp.tcb().to_string().c_str()); + if(in->ack() == tcp.tcb().SND.NXT) { + // TODO: I guess or FIN is ACK'ed..? + tcp.set_state(Connection::FinWait2::instance()); + return tcp.state().handle(tcp, in); // TODO: Is this OK? + } + + // 7. proccess the segment text + if(in->has_data()) { + process_segment(tcp, in); + } + + // 8. check FIN + if(in->isset(FIN)) { + process_fin(tcp, in); + debug2(" FIN isset. TCB:\n %s \n", tcp.tcb().to_string().c_str()); + /* + If our FIN has been ACKed (perhaps in this segment), then + enter TIME-WAIT, start the time-wait timer, turn off the other + timers; otherwise enter the CLOSING state. + */ + if(in->ack() == tcp.tcb().SND.NXT) { + // TODO: I guess or FIN is ACK'ed..? + tcp.set_state(TimeWait::instance()); + tcp.start_time_wait_timeout(); + } else { + tcp.set_state(Closing::instance()); } + } + return OK; +} - // 7. proccess the segment text - if(in->has_data()) { - process_segment(tcp, in); - } - // 8. check FIN - if(in->isset(FIN)) { - process_fin(tcp, in); - /* - Enter the TIME-WAIT state. Start the time-wait timer, turn off the other timers. - */ - tcp.set_state(Connection::TimeWait::instance()); - tcp.start_time_wait_timeout(); - } +State::Result Connection::FinWait2::handle(Connection& tcp, TCP::Packet_ptr in) { + // 1. check SEQ + if(! check_seq(tcp, in) ) { return OK; -} -///////////////////////////////////////////////////////////////////// + } + // 2. check RST + if( in->isset(RST) ) { + tcp.signal_disconnect(Disconnect::RESET); + return CLOSED; // close + } -///////////////////////////////////////////////////////////////////// -/* - CLOSE-WAIT -*/ -///////////////////////////////////////////////////////////////////// + // 4. check SYN + if( in->isset(SYN) ) { + unallowed_syn_reset_connection(tcp, in); + return CLOSED; + } -size_t Connection::CloseWait::send(Connection& tcp, const char* buffer, size_t n, bool push) { - debug(" Sending data with the length of %u. PUSH: %d \n", n, push); - auto bytes_written = tcp.write_to_send_buffer(buffer, n, push); - tcp.transmit(); - return bytes_written; -} + // 5. check ACK + if( ! check_ack(tcp, in) ) { + return OK; + } -size_t Connection::CloseWait::receive(Connection& tcp, char* buffer, size_t n) { - return tcp.read_from_receive_buffer(buffer, n); -} + // 7. proccess the segment text + if(in->has_data()) { + process_segment(tcp, in); + } -void Connection::CloseWait::close(Connection& tcp) { - /* - Queue this request until all preceding SENDs have been - segmentized; then send a FIN segment, enter CLOSING state. - */ - auto& tcb = tcp.tcb(); - tcp.outgoing_packet()->set_seq(tcb.SND.NXT++).set_ack(tcb.RCV.NXT).set_flags(ACK | FIN); - tcp.transmit(); - tcp.set_state(Connection::Closing::instance()); + // 8. check FIN + if(in->isset(FIN)) { + process_fin(tcp, in); + /* + Enter the TIME-WAIT state. + Start the time-wait timer, turn off the other timers. + */ + tcp.set_state(Connection::TimeWait::instance()); + tcp.start_time_wait_timeout(); + } + return OK; } -void Connection::CloseWait::abort(Connection& tcp) { - send_reset(tcp); -} State::Result Connection::CloseWait::handle(Connection& tcp, TCP::Packet_ptr in) { - // 1. check SEQ - if(! check_seq(tcp, in) ) { - return OK; - } + // 1. check SEQ + if(! check_seq(tcp, in) ) { + return OK; + } - // 2. check RST - if( in->isset(RST) ) { - tcp.signal_disconnect(Disconnect::RESET); - return CLOSED; // close - } + // 2. check RST + if( in->isset(RST) ) { + tcp.signal_disconnect(Disconnect::RESET); + return CLOSED; // close + } // 4. check SYN - if( in->isset(SYN) ) { - unallowed_syn_reset_connection(tcp, in); - return CLOSED; - } + if( in->isset(SYN) ) { + unallowed_syn_reset_connection(tcp, in); + return CLOSED; + } - // 5. check ACK - if( ! check_ack(tcp, in) ) { - return OK; - } + // 5. check ACK + if( ! check_ack(tcp, in) ) { + return OK; + } - // 7. proccess the segment text - // This should not occur, since a FIN has been received from the remote side. Ignore the segment text. + // 7. proccess the segment text + // This should not occur, since a FIN has been received from the remote side. Ignore the segment text. - // 8. check FIN - if(in->isset(FIN)) { - process_fin(tcp, in); - // Remain in state - return OK; - } + // 8. check FIN + if(in->isset(FIN)) { + process_fin(tcp, in); + // Remain in state return OK; + } + return OK; } -///////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////// -/* - CLOSING -*/ -///////////////////////////////////////////////////////////////////// - State::Result Connection::Closing::handle(Connection& tcp, TCP::Packet_ptr in) { // 1. Check sequence number - if(! check_seq(tcp, in) ) { - return OK; - } - - // 2. check RST - if( in->isset(RST) ) { - return CLOSED; // close - } - - // 4. check SYN - if( in->isset(SYN) ) { - unallowed_syn_reset_connection(tcp, in); - return CLOSED; + if(! check_seq(tcp, in) ) { + return OK; + } + + // 2. check RST + if( in->isset(RST) ) { + return CLOSED; // close + } + + // 4. check SYN + if( in->isset(SYN) ) { + unallowed_syn_reset_connection(tcp, in); + return CLOSED; } // 5. check ACK if( ! check_ack(tcp, in)) { return CLOSED; } + /* In addition to the processing for the ESTABLISHED state, if - the ACK acknowledges our FIN then enter the TIME-WAIT state, - otherwise ignore the segment. + the ACK acknowledges our FIN then enter the TIME-WAIT state, + otherwise ignore the segment. */ - if(in->ack() == tcp.tcb().SND.NXT) { - // TODO: I guess or FIN is ACK'ed..? - tcp.set_state(TimeWait::instance()); - tcp.start_time_wait_timeout(); - } - - - // 7. proccess the segment text - // This should not occur, since a FIN has been received from the remote side. Ignore the segment text. - - // 8. check FIN - if(in->isset(FIN)) { - process_fin(tcp, in); - // Remain in state - return OK; - } - return OK; + if(in->ack() == tcp.tcb().SND.NXT) { + // TODO: I guess or FIN is ACK'ed..? + tcp.set_state(TimeWait::instance()); + tcp.start_time_wait_timeout(); + } + + // 7. proccess the segment text + // This should not occur, since a FIN has been received from the remote side. Ignore the segment text. + + // 8. check FIN + if(in->isset(FIN)) { + process_fin(tcp, in); + // Remain in state + return OK; + } + return OK; } -///////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////// -/* - LAST-ACK -*/ -///////////////////////////////////////////////////////////////////// - State::Result Connection::LastAck::handle(Connection& tcp, TCP::Packet_ptr in) { - // 1. Check sequence number - if(! check_seq(tcp, in) ) { - return OK; - } - - // 2. check RST - if( in->isset(RST) ) { - return CLOSED; // close - } - - // 4. check SYN - if( in->isset(SYN) ) { - unallowed_syn_reset_connection(tcp, in); - return CLOSED; - } - - if( ! check_ack(tcp, in)) { - return CLOSED; - } - - // 7. proccess the segment text - // This should not occur, since a FIN has been received from the remote side. Ignore the segment text. - - // 8. check FIN - if(in->isset(FIN)) { - process_fin(tcp, in); - // Remain in state - return OK; - } + // 1. Check sequence number + if(! check_seq(tcp, in) ) { return OK; + } + + // 2. check RST + if( in->isset(RST) ) { + return CLOSED; // close + } + + // 4. check SYN + if( in->isset(SYN) ) { + unallowed_syn_reset_connection(tcp, in); + return CLOSED; + } + + if( ! check_ack(tcp, in)) { + return CLOSED; + } + + // 7. proccess the segment text + // This should not occur, since a FIN has been received from the remote side. Ignore the segment text. + + // 8. check FIN + if(in->isset(FIN)) { + process_fin(tcp, in); + // Remain in state + return OK; + } + return OK; } -///////////////////////////////////////////////////////////////////// - -///////////////////////////////////////////////////////////////////// -/* - TIME-WAIT -*/ -///////////////////////////////////////////////////////////////////// State::Result Connection::TimeWait::handle(Connection& tcp, TCP::Packet_ptr in) { - // 1. Check sequence number - if(! check_seq(tcp, in) ) { - return OK; - } - - // 2. check RST - if( in->isset(RST) ) { - return CLOSED; // close - } - - // 4. check SYN - if( in->isset(SYN) ) { - unallowed_syn_reset_connection(tcp, in); - return CLOSED; - } - - // 7. proccess the segment text - // This should not occur, since a FIN has been received from the remote side. Ignore the segment text. - - // 8. check FIN - if(in->isset(FIN)) { - process_fin(tcp, in); - // Remain in state - tcp.start_time_wait_timeout(); - return OK; - } + // 1. Check sequence number + if(! check_seq(tcp, in) ) { + return OK; + } + + // 2. check RST + if( in->isset(RST) ) { + return CLOSED; // close + } + + // 4. check SYN + if( in->isset(SYN) ) { + unallowed_syn_reset_connection(tcp, in); + return CLOSED; + } + + // 7. proccess the segment text + // This should not occur, since a FIN has been received from the remote side. Ignore the segment text. + + // 8. check FIN + if(in->isset(FIN)) { + process_fin(tcp, in); + // Remain in state + tcp.start_time_wait_timeout(); return OK; + } + return OK; } ///////////////////////////////////////////////////////////////////// From 9f482222702dd230944003f26daa7a9f4e8a1e05 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Thu, 17 Mar 2016 13:56:18 +0100 Subject: [PATCH 036/311] term: Telnet parsing, custom commands --- api/hw/serial.hpp | 1 + api/kernel/terminal.hpp | 77 +++++++++++++------ src/Makefile | 2 +- src/debug/test_service.cpp | 35 +++++++-- src/hw/serial.cpp | 9 +-- src/kernel/terminal.cpp | 147 +++++++++++++++++++++++++++++++++++++ 6 files changed, 235 insertions(+), 36 deletions(-) create mode 100644 src/kernel/terminal.cpp diff --git a/api/hw/serial.hpp b/api/hw/serial.hpp index ae82d9440f..1bdc4bdda0 100644 --- a/api/hw/serial.hpp +++ b/api/hw/serial.hpp @@ -23,6 +23,7 @@ #include #include #include +#include namespace hw{ diff --git a/api/kernel/terminal.hpp b/api/kernel/terminal.hpp index 2c6e8d20d5..74ca54583a 100644 --- a/api/kernel/terminal.hpp +++ b/api/kernel/terminal.hpp @@ -2,40 +2,73 @@ #define KERNEL_BTERM_HPP #include -#include +#include +#include +#include -// some bidirectional communication interface -struct IBidirectional +struct Command { - using on_read_func = std::function; - using on_write_func = std::function; + using main_func = std::function&)>; - virtual void set_on_read(on_read_func) = 0; - virtual void write(char, on_write_func) = 0; + Command(main_func func) : main(func) {} - on_read_func read_callback; -}; - -// communication using serial port -struct SerialComm : public IBidirectional -{ - SerialComm(hw::Serial& s); - - virtual void set_on_read(on_read_func) override; - virtual void write(char) override; - - hw::Serial& serial; + main_func main; }; class Terminal { public: - Terminal(IBidirectional& iface) - : comm(iface) {} + using Connection_ptr = std::shared_ptr; + enum + { + NUL = 0, + BELL = 7, + BS = 8, + HTAB = 9, + LF = 10, + VTAB = 11, + FF = 12, + CR = 13 + }; + + using on_read_func = std::function; + using on_write_func = std::function; + + Terminal(Connection_ptr); + + void set_on_read(on_read_func callback) + { + on_read = callback; + } + + template + void add_cmd(const std::string& command, Args&&... args) + { + commands.emplace(std::piecewise_construct, + std::forward_as_tuple(command), + std::forward_as_tuple(args...)); + } + + template + void write(const char* str, Args&&... args) + { + char buffer[1024]; + int bytes = snprintf(buffer, 1024, str, args...); + + on_write(buffer, bytes); + } +private: + void command(uint8_t cmd); + void read(const char* buf, size_t len); + void run(const std::string& cmd); + on_read_func on_read; + on_write_func on_write; - IBidirectional& comm; + bool iac; + std::string buffer; + std::map commands; }; #endif diff --git a/src/Makefile b/src/Makefile index f05938150f..a96dd8843e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -114,7 +114,7 @@ LIBS_OBJ = os.a $(LIBCXX) os.a $(LIBC_OBJ) $(LIBM_OBJ) $(LIBGCC) CRTBEGIN_OBJ = $(CRTI_OBJ) $(INSTALL)/crt/crtbegin.o CRTEND_OBJ = $(INSTALL)/crt/crtend.o $(CRTN_OBJ) -TEST_OBJ = debug/test_service.o debug/ircd.o util/service_name.o +TEST_OBJ = debug/test_service.o util/service_name.o test_service: CPPOPTS += -DSERVICE_NAME="\"Test Service\"" test_service: $(TEST_OBJ) $(CRTI_OBJ) $(CRTN_OBJ) diff --git a/src/debug/test_service.cpp b/src/debug/test_service.cpp index 0d961e86a8..6122bdac1f 100644 --- a/src/debug/test_service.cpp +++ b/src/debug/test_service.cpp @@ -21,14 +21,13 @@ #include #include "ircd.hpp" -SerialComm scomm(hw::Serial::port<1>()); -Terminal term(scomm); - using namespace std::chrono; // An IP-stack object std::unique_ptr > inet; +std::unique_ptr term; + void Service::start() { // boilerplate @@ -40,6 +39,7 @@ void Service::start() {{ 10,0,0,1 }}, // Gateway {{ 8,8,8,8 }} ); // DNS + /* auto& tcp = inet->tcp(); auto& server = tcp.bind(6667); // IRCd default port server.onConnect( @@ -64,19 +64,38 @@ void Service::start() client.read(buffer, bytes); }); - /*.onDisconnect( + + .onDisconnect( [&client] (auto conn, std::string) { // remove client from various lists client.remove(); /// inform others about disconnect //client.bcast(TK_QUIT, "Disconnected"); - });*/ - }); + }); + });*/ /// terminal /// - - + auto& tcp = inet->tcp(); + auto& server = tcp.bind(23); // TELNET port + server.onConnect( + [] (auto csock) + { + printf("term.write('')\n"); + term = std::make_unique (csock); + + term->add_cmd( + "ifconfig", + [csock] (const std::vector& args) -> int + { + printf("ifconfig called! argc = %u\n", args.size()); + + term->write("ifconfig - %s WutFace 4Head\r\n", csock->remote().to_string().c_str()); + return 1; + }); + + //term->write("hello\n"); + }); printf("*** TEST SERVICE STARTED *** \n"); } diff --git a/src/hw/serial.cpp b/src/hw/serial.cpp index be904e5205..cd8b9d7b9d 100644 --- a/src/hw/serial.cpp +++ b/src/hw/serial.cpp @@ -21,9 +21,9 @@ void Serial::init(){ Serial::Serial(int port) : nr_{port}, port_{ port < 5 ? ports_[port -1] : 0 } - { - //init(); - } +{ + //init(); +} void Serial::on_data(on_data_handler del){ enable_interrupt(); @@ -92,5 +92,4 @@ void Serial::readline_handler_ (char c) { // Call the event handler on_readline_(buf); buf.clear(); - -}; +} diff --git a/src/kernel/terminal.cpp b/src/kernel/terminal.cpp new file mode 100644 index 0000000000..ac1a86c4f0 --- /dev/null +++ b/src/kernel/terminal.cpp @@ -0,0 +1,147 @@ +#include + +#include +#include +#include + +Terminal::Terminal(Connection_ptr csock) + : iac(false) +{ + csock->onReceive( + [this] (auto conn, bool) + { + char buffer[1024]; + size_t bytes = conn->read(buffer, sizeof(buffer)); + + this->read(buffer, bytes); + }); + + on_write = + [csock] (const char* buffer, size_t len) + { + csock->write(buffer, len); + }; +} + +void Terminal::read(const char* buf, size_t len) +{ + while (len) + { + if (this->iac) + { + command(*(uint8_t*) buf); + this->iac = false; + } + else if (*buf == 13 || *buf == 10) + { + // parse message + if (buffer.size()) + { + run(buffer); + buffer.clear(); + } + } + else if (*buf == 0) + { + // NOP + } + else if (*buf == -128) + { + // Interpret as Command + this->iac = true; + } + else + { + buffer.append(buf, 1); + } + buf++; len--; + } +} + +void Terminal::command(uint8_t cmd) +{ + printf("Command: 0x%x\n", cmd); + switch (cmd) + { + case 247: // erase char + printf("CMD: Erase char\n"); + break; + case 248: // erase line + printf("CMD: Erase line\n"); + break; + + } +} + +std::vector +split(const std::string& text, std::string& command) +{ + std::vector retv; + size_t x = 0; + size_t p = 0; + // ignore empty messages + if (text.empty()) return retv; + // extract command + { + x = text.find(" "); + // early return for cmd-only msg + if (x == std::string::npos) + { + command = text; + return retv; + } + // command is substring + command = text.substr(x); + p = x+1; + } + // parse remainder + do + { + x = text.find(" ", p+1); + size_t y = text.find(":", x+1); // find last param + + if (y == x+1) + { + // single argument + retv.push_back(text.substr(p, x-p)); + // ending text argument + retv.push_back(text.substr(y+1)); + break; + } + else if (x != std::string::npos) + { + // single argument + retv.push_back(text.substr(p, x-p)); + } + else + { + // last argument + retv.push_back(text.substr(p)); + } + p = x+1; + + } while (x != std::string::npos); + + return retv; +} + +void Terminal::run(const std::string& cmd_string) +{ + std::string cmd_name; + auto cmd_vec = split(cmd_string, cmd_name); + if (cmd_name.empty()) return; + + printf("Terminal::run(): %s\n", cmd_name.c_str()); + + auto it = commands.find(cmd_name); + if (it != commands.end()) + { + int retv = it->second.main(cmd_vec); + if (!retv) write("%s returned failure\r\n", cmd_name.c_str()); + } + else + { + write("No such command: %s\r\n", cmd_name.c_str()); + } + +} From 145e44d1c169d335f10d066786d8346a6aa8bdb4 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Thu, 17 Mar 2016 14:18:22 +0100 Subject: [PATCH 037/311] You now have to build for 'production' to supress all debugging info --- src/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index d6a93bc9bd..43954f11ea 100644 --- a/src/Makefile +++ b/src/Makefile @@ -12,7 +12,7 @@ INSTALL = $(INCLUDEOS_INSTALL) # stackrealign is needed to guarantee 16-byte stack alignment for SSE # the compiler seems to be really dumb in this regard, creating a misaligned stack left and right CAPABS_COMMON = -mstackrealign -msse3 -CAPABS = $(CAPABS_COMMON) -O2 -DNO_DEBUG=1 +CAPABS = $(CAPABS_COMMON) -O2 #-DNO_DEBUG=1 WARNS = -Wall -Wextra #-pedantic DEBUG_OPTS = -ggdb3 @@ -96,6 +96,9 @@ all: bootloader libc++abi.a os.a stripped: CAPABS += -Oz stripped: all test +production: CAPABS += -DNO_DEBUG=1 +production: all test + # The same, but with debugging symbols (OBS: Dramatically increases binary size) debug: CCOPTS += $(DEBUG_OPTS) debug: CPPOPTS += $(DEBUG_OPTS) From a8dfb16a4ab84bb88690b54ec4cea2a48b63c045 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Thu, 17 Mar 2016 14:53:30 +0100 Subject: [PATCH 038/311] PIC/IRQ facelift --- api/hw/pic.hpp | 244 ++++++++++++++++++++----------------- api/kernel/irq_manager.hpp | 13 +- src/hw/pic.cpp | 32 ++--- src/kernel/irq_manager.cpp | 6 +- test/IRQ_PIC/README.md | 13 +- test/IRQ_PIC/service.cpp | 67 +++++----- 6 files changed, 197 insertions(+), 178 deletions(-) diff --git a/api/hw/pic.hpp b/api/hw/pic.hpp index acb0da5d5e..392e7f6600 100644 --- a/api/hw/pic.hpp +++ b/api/hw/pic.hpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,124 +20,138 @@ #include "../kernel/os.hpp" #include "ioport.hpp" +#include namespace hw { -class PIC { -public: - static void init() noexcept; - - inline static void enable_irq(uint8_t irq) noexcept { - irq_mask_ &= ~(1 << irq); - if (irq >= 8) irq_mask_ &= ~(1 << 2); - set_intr_mask(irq_mask_); - INFO2("+ Enabling IRQ %i, mask: 0x%x", irq, irq_mask_); - } - - inline static void disable_irq(const uint8_t irq) noexcept { - irq_mask_ |= (1 << irq); - if ((irq_mask_ & 0xFF00) == 0xFF00) { - irq_mask_ |= (1 << 2); + /** + Programmable Interrupt Controller + implementation according to Intel 8259A / 8259A-2 1988 whitepaper + */ + class PIC { + public: + static void init() noexcept; + + inline static void enable_irq(uint8_t irq) noexcept { + irq_mask_ &= ~(1 << irq); + if (irq >= 8) irq_mask_ &= ~(1 << 2); + set_intr_mask(irq_mask_); + INFO2("+ Enabling IRQ %i, mask: 0x%x", irq, irq_mask_); + } + + inline static void disable_irq(const uint8_t irq) noexcept { + irq_mask_ |= (1 << irq); + if ((irq_mask_ & 0xFF00) == 0xFF00) { + irq_mask_ |= (1 << 2); + } + set_intr_mask(irq_mask_); + INFO2("- Disabling IRQ %i, mask: 0x%x", irq, irq_mask_); + } + + /** + @brief End of Interrupt. Master IRQ-lines (0-7) currently use Auto EOI, + but the user should assume that IRQ-specific EOI's are necessary. + + @note: + According to Intel 8259A / 8259A-2 whitepaper p. 15 + "The AEOI mode can only be used in a master 8259A and not a slave. + 8259As with a copyright date of 1985 or later will operate in the AEOI + mode as a master or a slave" + + If I enable auto-eoi for slave, everything seems to freeze in Qemu, + the moment I get the first network interrupt (IRQ 11). + + I'm assuming this means that I have an old chip :-) + */ + inline static void eoi(const uint8_t irq) noexcept { + + // We're using auto-EOI-mode for IRQ < 8, IRQ >= 16 are soft-irq's + if (irq >= 8 && irq < 16) { + hw::outb(slave_ctrl, ocw2_specific_eoi | (irq - 8)); + } + + // If we switch off auto-EOI, we need to re-enable this + // I'm disabling it in order to save VM-exits + //hw::outb(master_ctrl, specific_eoi_ | irq );*/ } - set_intr_mask(irq_mask_); - INFO2("- Disabling IRQ %i, mask: 0x%x", irq, irq_mask_); - } - - inline static void eoi(const uint8_t irq) noexcept { - - if (irq >= 8) { - //hw::outb(slave_ctrl, eoi_); - hw::outb(slave_ctrl, eoi_); + + /* Returns the combined value of the cascaded PICs irq request register */ + inline static uint16_t get_irr() noexcept + { return get_irq_reg(ocw3_read_irr); } + + /* Returns the combined value of the cascaded PICs in-service register */ + inline static uint16_t get_isr() noexcept + { return get_irq_reg(ocw3_read_isr); } + + private: + // ICW1 bits + static constexpr uint8_t icw1 {0x10}; // Bit 5 compulsory + static constexpr uint8_t icw1_icw4_needed {0x1}; // Prepare for cw4 or not + static constexpr uint8_t icw1_single_mode {0x2}; // 0: cascade + static constexpr uint8_t icw1_addr_interval_4 {0x4}; // 0: interval 8 + static constexpr uint8_t icw1_level_trigered {0x8}; // 0: egde triggred + + // ICW2 bits: Interrupt number for first IRQ + static constexpr uint8_t icw2_irq_base_master {32}; + static constexpr uint8_t icw2_irq_base_slave {40}; + + // ICW3 bits: Location and ID of slave PIC + static constexpr uint8_t icw3_slave_location {0x04}; + static constexpr uint8_t icw3_slave_id {0x02}; + + // ICW4 bits: + static constexpr uint8_t icw4 {0x0}; // No bits by default + static constexpr uint8_t icw4_8086_mode {0x1}; // 0: aincient runes + static constexpr uint8_t icw4_auto_eoi {0x2}; // auto vs. normal EOI + static constexpr uint8_t icw4_buffered_mode_slave {0x08}; + static constexpr uint8_t icw4_buffered_mode_master {0x12}; + + + // Registers addresses + static const uint8_t master_ctrl {0x20}; + static const uint8_t master_mask {0x21}; + static const uint8_t slave_ctrl {0xA0}; + static const uint8_t slave_mask {0xA1}; + + + // Operational command words + // OCW1: Interrupt mask + // OCW2: + static constexpr uint8_t ocw2 {0x0}; // No default bits + static constexpr uint8_t ocw2_nonspecific_eoi {0x20}; + static constexpr uint8_t ocw2_specific_eoi {0x60}; + static constexpr uint8_t ocw2_rotate_on_non_specific_eoi {0xA0}; + static constexpr uint8_t ocw2_rotate_on_auto_eoi_set {0x80}; // 0x0 to clear + static constexpr uint8_t ocw2_rotate_on_specific_eoi {0xE0}; + static constexpr uint8_t ocw2_set_priority_cmd {0xC0}; + static constexpr uint8_t ocw2_nop {0x40}; + + // OCW3: + static constexpr uint8_t ocw3 {0x08}; // Default bits + static constexpr uint8_t ocw3_read_irr {0x02}; + static constexpr uint8_t ocw3_read_isr {0x03}; + static constexpr uint8_t ocw3_poll_cmd {0x04}; // 0 to disable + static constexpr uint8_t ocw3_set_special_mask {0x60}; + static constexpr uint8_t ocw3_reset_special_mask {0x40}; + + static uint16_t irq_mask_; + + inline static void set_intr_mask(uint32_t mask) noexcept { + hw::outb(master_mask, static_cast(mask)); + hw::outb(slave_mask, static_cast(mask >> 8)); + } + + /* Helper func */ + inline static uint16_t get_irq_reg(const int ocw3) noexcept { + /* + * OCW3 to PIC CMD to get the register values. PIC2 is chained, and + * represents IRQs 8-15. PIC1 is IRQs 0-7, with 2 being the chain + */ + hw::outb(master_ctrl, ocw3); + hw::outb(master_ctrl, ocw3); + return (hw::inb(slave_ctrl) << 8) | hw::inb(master_ctrl); } - //hw::outb(master_ctrl, specific_eoi_ | (irq & 0x0f) );*/ - } - - /* Returns the combined value of the cascaded PICs irq request register */ - inline static uint16_t get_irr() noexcept - { return get_irq_reg(ocw3_read_irr); } - - /* Returns the combined value of the cascaded PICs in-service register */ - inline static uint16_t get_isr() noexcept - { return get_irq_reg(ocw3_read_isr); } - -private: - // ICW1 bits - static constexpr uint8_t icw1 {0x10}; // Bit 5 compulsory - static constexpr uint8_t icw1_icw4_needed {0x1}; // Prepare for cw4 or not - static constexpr uint8_t icw1_single_mode {0x2}; // 0: cascade - static constexpr uint8_t icw1_addr_interval_4 {0x4}; // 0: interval 8 - static constexpr uint8_t icw1_level_trigered {0x8}; // 0: egde triggred - - // ICW2 bits: Interrupt number for first IRQ - static constexpr uint8_t icw2_irq_base_master {32}; - static constexpr uint8_t icw2_irq_base_slave {40}; - - // ICW3 bits: Location and ID of slave PIC - static constexpr uint8_t icw3_slave_location {0x04}; - static constexpr uint8_t icw3_slave_id {0x02}; - - // ICW4 bits: - static constexpr uint8_t icw4 {0x0}; // No bits by default - static constexpr uint8_t icw4_8086_mode {0x1}; // 0: aincient runes - static constexpr uint8_t icw4_auto_eoi {0x2}; // auto vs. normal EOI - static constexpr uint8_t icw4_buffered_mode_slave {0x08}; - static constexpr uint8_t icw4_buffered_mode_master {0x12}; - - - // Registers addresses - static const uint8_t master_ctrl {0x20}; - static const uint8_t master_mask {0x21}; - static const uint8_t slave_ctrl {0xA0}; - static const uint8_t slave_mask {0xA1}; - - - // Operational command words - // OCW1: Interrupt mask - // OCW2: - static constexpr uint8_t ocw2 {0x0}; // No default bits - static constexpr uint8_t ocw2_nonspecific_eoi {0x20}; - static constexpr uint8_t ocw2_specific_eoi {0x60}; - static constexpr uint8_t ocw2_rotate_on_non_specific_eoi {0xA0}; - static constexpr uint8_t ocw2_rotate_on_auto_eoi_set {0x80}; // 0x0 to clear - static constexpr uint8_t ocw2_rotate_on_specific_eoi {0xE0}; - static constexpr uint8_t ocw2_set_priority_cmd {0xC0}; - static constexpr uint8_t ocw2_nop {0x40}; - - static constexpr uint8_t ocw3 {0x08}; // Default bits - static constexpr uint8_t ocw3_read_irr {0x02}; - static constexpr uint8_t ocw3_read_isr {0x03}; - static constexpr uint8_t ocw3_poll_cmd {0x04}; // 0 to disable - static constexpr uint8_t ocw3_set_special_mask {0x60}; - static constexpr uint8_t ocw3_reset_special_mask {0x40}; - - - - - - static constexpr uint8_t ocw2_eoi = 0x20; - static constexpr uint8_t ocw2_specific = 0x40; - - static constexpr uint8_t eoi_ { ocw2_eoi }; - static constexpr uint8_t specific_eoi_ { ocw2_eoi | ocw2_specific }; - - static uint16_t irq_mask_; - - inline static void set_intr_mask(uint32_t mask) noexcept { - hw::outb(master_mask, static_cast(mask)); - hw::outb(slave_mask, static_cast(mask >> 8)); - } - - /* Helper func */ - inline static uint16_t get_irq_reg(const int ocw3) noexcept { - /* - * OCW3 to PIC CMD to get the register values. PIC2 is chained, and - * represents IRQs 8-15. PIC1 is IRQs 0-7, with 2 being the chain - */ - hw::outb(master_ctrl, ocw3); - hw::outb(master_ctrl, ocw3); - return (hw::inb(slave_ctrl) << 8) | hw::inb(master_ctrl); - } -}; //< class PIC + }; //< class PIC } //< namespace hw diff --git a/api/kernel/irq_manager.hpp b/api/kernel/irq_manager.hpp index f733ce9c62..77b4911b6d 100644 --- a/api/kernel/irq_manager.hpp +++ b/api/kernel/irq_manager.hpp @@ -60,10 +60,7 @@ extern "C" { * IRQ-numbering: 0 or 32? - @TODO: Remove all dependencies on old SanOS code. In particular, eoi is now in global scope - - */ class IRQ_manager { public: @@ -72,7 +69,7 @@ class IRQ_manager { static constexpr uint8_t irq_base = 32; static constexpr uint8_t irq_lines = 64; - + /** * Enable an IRQ line * @@ -139,10 +136,10 @@ class IRQ_manager { irq_pending_ |= (1 << i); __sync_fetch_and_add(&irq_counters_[i],1); debug(" IRQ %i Pending: 0x%ix. Count: %i\n", i, - irq_pending_, irq_counters_[i]); + irq_pending_, irq_counters_[i]); } - - + + private: static unsigned int irq_mask; static int timer_interrupts; @@ -185,7 +182,7 @@ class IRQ_manager { /** Notify all delegates waiting for interrupts */ static void notify(); - + }; //< IRQ_manager #endif //< KERNEL_IRQ_MANAGER_HPP diff --git a/src/hw/pic.cpp b/src/hw/pic.cpp index 4d5529469e..c10adaf9e0 100644 --- a/src/hw/pic.cpp +++ b/src/hw/pic.cpp @@ -20,28 +20,20 @@ namespace hw { -uint16_t PIC::irq_mask_ {0xFFFF}; + uint16_t PIC::irq_mask_ {0xFFFF}; -void PIC::init() noexcept { - // Master commands - static const uint8_t master_icw3 {0x04}; // Location of slave - static const uint8_t master_icw4 {0x03}; // 8086-mode (bit1), Auto-EOI (bit2) + void PIC::init() noexcept { - // Slave commands - static const uint8_t slave_icw3 {0x02}; // Slave ID - static const uint8_t slave_icw4 {0x01}; - - hw::outb(master_ctrl, icw1 | icw1_icw4_needed); - hw::outb(slave_ctrl, icw1 | icw1_icw4_needed); - hw::outb(master_mask, icw2_irq_base_master); - hw::outb(slave_mask, icw2_irq_base_slave); - hw::outb(master_mask, icw3_slave_location); - hw::outb(slave_mask, icw3_slave_id); - hw::outb(master_mask, icw4_8086_mode | icw4_auto_eoi); - hw::outb(slave_mask, icw4_8086_mode); - - set_intr_mask(irq_mask_); -} + hw::outb(master_ctrl, icw1 | icw1_icw4_needed); + hw::outb(slave_ctrl, icw1 | icw1_icw4_needed); + hw::outb(master_mask, icw2_irq_base_master); + hw::outb(slave_mask, icw2_irq_base_slave); + hw::outb(master_mask, icw3_slave_location); + hw::outb(slave_mask, icw3_slave_id); + hw::outb(master_mask, icw4_8086_mode | icw4_auto_eoi); + hw::outb(slave_mask, icw4_8086_mode); // AEOI-mode only works for master + set_intr_mask(irq_mask_); + } } //< namespace hw diff --git a/src/kernel/irq_manager.cpp b/src/kernel/irq_manager.cpp index a094de5ae9..376b4ef331 100644 --- a/src/kernel/irq_manager.cpp +++ b/src/kernel/irq_manager.cpp @@ -207,7 +207,7 @@ void IRQ_manager::init() REG_DEFAULT_IRQ(7) REG_DEFAULT_IRQ(8) REG_DEFAULT_IRQ(9) REG_DEFAULT_IRQ(10) REG_DEFAULT_IRQ(11) REG_DEFAULT_IRQ(12) REG_DEFAULT_IRQ(13) REG_DEFAULT_IRQ(14) REG_DEFAULT_IRQ(15) - + //Set all irq-gates (> 47) to the default handler for(int i=48;i Done. OS going to sleep.\n"); + debug2(" Done. OS going to sleep.\n"); //__asm__("sti"); __asm__ volatile("hlt;"); } diff --git a/test/IRQ_PIC/README.md b/test/IRQ_PIC/README.md index d41d3536df..878c6eb7eb 100644 --- a/test/IRQ_PIC/README.md +++ b/test/IRQ_PIC/README.md @@ -1,5 +1,16 @@ # Test basic PIC / IRQ functionality -For now we test that IRQ subscription works by soft-triggering interrupts. There's also a UDP server set up, making it possible to test IRQ 11 (currently) and e.g. keyboard IRQ 1 in connection with eachother. +Test of the following: + +1. Soft-triggering IRQ's will call interrupt-handlers, and in turn delegates +2. Serial port, IRQ 4: the service will read from serial port. With Qemu `-nographic` this will automatically be connected to stdin. Any character written to the serial port should result in a checkbox'ed receipt e.g. `[x] Serial port (IRQ 4) received 'a'` +3. UDP, IRQ 11: There's a UDP server set up, making it possible to test IRQ 11. Any data written to IP 10.0.0.42, UDP port 4242, should result in a checkbox'ed receipt, e.g. +``` +$ echo "asdf" | nc -u 10.0.0.42 4242 +-> [x] UDP received: 'asdf' +``` +4. A 1-second interval timer is continously running (IRQ 0). Each second it should output a chekced receipt with an incremented counter. + +For this setup it's expected that no combination of IRQ's should prevent other IRQ's from triggering. No automation yet. diff --git a/test/IRQ_PIC/service.cpp b/test/IRQ_PIC/service.cpp index 5effebd1ff..47740ca8b8 100644 --- a/test/IRQ_PIC/service.cpp +++ b/test/IRQ_PIC/service.cpp @@ -38,30 +38,31 @@ std::unique_ptr > inet; **/ void Service::start() { - + // Serial auto& com1 = hw::Serial::port<1>(); - + // Timers auto& time = hw::PIT::instance(); - + // Network auto& eth0 = hw::Dev::eth<0,VirtioNet>(); auto& mac = eth0.mac(); auto& inet = *new net::Inet4(eth0, // Device {{ mac.part[2],mac.part[3],mac.part[4],mac.part[5] }}, // IP {{ 255,255,0,0 }} ); // Netmask - + printf("Service IP address: %s \n", inet.ip_addr().str().c_str()); // UDP UDP::port_t port = 4242; auto& sock = inet.udp().bind(port); - + sock.onRead([] (UDP::Socket& conn, UDP::addr_t addr, UDP::port_t port, const char* data, int len) -> int { - printf("Getting UDP data from %s: %i: %s\n", - addr.str().c_str(), port, data); + auto str = std::string(data,len); + str[len -1] = 0; + CHECK(1,"UDP received '%s'", str.c_str()); // send the same thing right back! conn.sendto(addr, port, data, len); return 0; @@ -105,37 +106,41 @@ void Service::start() asm("int $48"); // Expect "unexpected IRQ" asm("int $49"); // Expect "unexpected IRQ" - // Halting could/should be used in this test - // asm("hlt"); - - com1.on_readline([](std::string str){ - cout << "\nGot string: " << str << "\n"; - cout << "But if we get another IRQ, which we don't handle: trouble\n"; - cout << "Now send a UDP-package\n"; - - }); - /* - IRQ_manager::subscribe(4, [](){ - IRQ_manager::eoi(4); - INFO("IRQ","Serial port IRQ\n"); + com1.enable_interrupt(); + + + /** + A custom IRQ-handler for the serial port + It doesn't send eoi, but it should work anyway + since we're using auto-EOI-mode for IRQ < 8 (master) + */ + IRQ_manager::subscribe(4, [](){ + uint16_t serial_port1 = 0x3F8; + //IRQ_manager::eoi(4); + char byte = 0; + while (hw::inb(serial_port1 + 5) & 1) + byte = hw::inb(serial_port1); + + CHECK(1,"Serial port (IRQ 4) received '%c'", byte); }); - */ - + + /* - IRQ_manager::subscribe(11,[](){ + IRQ_manager::subscribe(11,[](){ // Calling eoi here will turn the IRQ line on and loop forever. IRQ_manager::eoi(11); - INFO("IRQ","Network IRQ\n"); - }); - */ - + INFO("IRQ","Network IRQ\n"); + });*/ + + // Enabling a timer causes freeze in debug mode, for some reason - time.onRepeatedTimeout(1s, [](){ - printf("Time \n"); - + time.onRepeatedTimeout(1s, [](){ + static int time_counter = 0; + CHECK(1,"Time %i", ++time_counter); + }); - + INFO("IRQ test","Expect IRQ subscribers to get called now "); } From 59537ca21617e4058b98f15e7dc8f54a160da60e Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Thu, 17 Mar 2016 16:26:20 +0100 Subject: [PATCH 039/311] term: Fixed parsing problems --- api/kernel/terminal.hpp | 19 ++++- src/debug/test_service.cpp | 4 +- src/kernel/terminal.cpp | 153 ++++++++++++++++++++++++++++++------- 3 files changed, 142 insertions(+), 34 deletions(-) diff --git a/api/kernel/terminal.hpp b/api/kernel/terminal.hpp index 74ca54583a..405a9da695 100644 --- a/api/kernel/terminal.hpp +++ b/api/kernel/terminal.hpp @@ -10,9 +10,11 @@ struct Command { using main_func = std::function&)>; - Command(main_func func) : main(func) {} + Command(const std::string& descr, main_func func) + : desc(descr), main(func) {} - main_func main; + std::string desc; + main_func main; }; class Terminal @@ -42,7 +44,8 @@ class Terminal } template - void add_cmd(const std::string& command, Args&&... args) + void add(const std::string& command, + Args&&... args) { commands.emplace(std::piecewise_construct, std::forward_as_tuple(command), @@ -58,15 +61,23 @@ class Terminal on_write(buffer, bytes); } + std::function on_exit { [] {} }; + private: void command(uint8_t cmd); + void option(uint8_t option, uint8_t cmd); void read(const char* buf, size_t len); void run(const std::string& cmd); + void add_basic_commands(); + void intro(); + void prompt(); on_read_func on_read; on_write_func on_write; - bool iac; + bool iac; + bool newline; + uint8_t subcmd; std::string buffer; std::map commands; }; diff --git a/src/debug/test_service.cpp b/src/debug/test_service.cpp index 6122bdac1f..5056ab966f 100644 --- a/src/debug/test_service.cpp +++ b/src/debug/test_service.cpp @@ -84,8 +84,8 @@ void Service::start() printf("term.write('')\n"); term = std::make_unique (csock); - term->add_cmd( - "ifconfig", + term->add( + "ifconfig", "Show information about interfaces", [csock] (const std::vector& args) -> int { printf("ifconfig called! argc = %u\n", args.size()); diff --git a/src/kernel/terminal.cpp b/src/kernel/terminal.cpp index ac1a86c4f0..beaa24c74f 100644 --- a/src/kernel/terminal.cpp +++ b/src/kernel/terminal.cpp @@ -5,7 +5,7 @@ #include Terminal::Terminal(Connection_ptr csock) - : iac(false) + : iac(false), newline(false), subcmd(0) { csock->onReceive( [this] (auto conn, bool) @@ -21,31 +21,47 @@ Terminal::Terminal(Connection_ptr csock) { csock->write(buffer, len); }; + + on_exit = + [csock] { + csock->close(); + }; + + add_basic_commands(); + intro(); } void Terminal::read(const char* buf, size_t len) { while (len) { - if (this->iac) + if (this->subcmd) + { + // execute options + option(this->subcmd, (uint8_t) *buf); + this->subcmd = 0; + } + else if (this->iac) { command(*(uint8_t*) buf); this->iac = false; } - else if (*buf == 13 || *buf == 10) + else if (*buf == 13 && !newline) { + newline = true; + } + else if (*buf == 10 && newline) + { + newline = false; // parse message - if (buffer.size()) - { - run(buffer); - buffer.clear(); - } + run(buffer); + buffer.clear(); } else if (*buf == 0) { // NOP } - else if (*buf == -128) + else if ((uint8_t) *buf == 0xFF) { // Interpret as Command this->iac = true; @@ -60,16 +76,43 @@ void Terminal::read(const char* buf, size_t len) void Terminal::command(uint8_t cmd) { - printf("Command: 0x%x\n", cmd); switch (cmd) { case 247: // erase char - printf("CMD: Erase char\n"); - break; + printf("CMD: Erase char\n"); + break; case 248: // erase line - printf("CMD: Erase line\n"); - break; - + printf("CMD: Erase line\n"); + break; + case 250: // Begin + printf("CMD: Begin...\n"); + break; + case 251: // Will USE + case 252: // Won't USE + case 253: // Start USE + case 254: // Stop USE + //printf("CMD: Command %d\n", cmd); + this->subcmd = cmd; + break; + case 255: + //printf("CMD: Command %d\n", cmd); + this->subcmd = cmd; + break; + default: + printf("CMD: Unknown command %d\n", cmd); + } +} + +void Terminal::option(uint8_t option, uint8_t cmd) +{ + (void) option; + switch (cmd) + { + case 24: // terminal type + break; + default: + //printf("CMD: Unknown cmd %d for option %d\n", cmd, option); + break; } } @@ -91,7 +134,7 @@ split(const std::string& text, std::string& command) return retv; } // command is substring - command = text.substr(x); + command = text.substr(0, x); p = x+1; } // parse remainder @@ -129,19 +172,73 @@ void Terminal::run(const std::string& cmd_string) { std::string cmd_name; auto cmd_vec = split(cmd_string, cmd_name); - if (cmd_name.empty()) return; - - printf("Terminal::run(): %s\n", cmd_name.c_str()); - - auto it = commands.find(cmd_name); - if (it != commands.end()) - { - int retv = it->second.main(cmd_vec); - if (!retv) write("%s returned failure\r\n", cmd_name.c_str()); - } - else + if (cmd_name.size()) { - write("No such command: %s\r\n", cmd_name.c_str()); + printf("Terminal::run(): %s\n", cmd_name.c_str()); + + auto it = commands.find(cmd_name); + if (it != commands.end()) + { + int retv = it->second.main(cmd_vec); + if (retv) write("%s returned: %d\r\n", cmd_name.c_str(), retv); + } + else + { + write("No such command: '%s'\r\n", cmd_name.c_str()); + } } + prompt(); +} + +void Terminal::add_basic_commands() +{ + // ?: + add( + "?", "List available commands", + [this] (const std::vector&) -> int + { + for (auto cmd : this->commands) + { + write("%s \t-- %s\r\n", cmd.first.c_str(), cmd.second.desc.c_str()); + } + return 0; + }); + // exit: + add( + "exit", "Close the terminal", + [this] (const std::vector&) -> int + { + this->on_exit(); + return 0; + }); + +} +void Terminal::intro() +{ + std::string banana = + R"baaa( + ____ ___ + | _ \ ___ _ _.' _ `. + _ | [_) )' _ `._ _ ___ ! \ | | (_) | _ +|:;.| _ <| (_) | \ | |' _ `| \| | _ | .:;| +| `.[_) ) _ | \| | (_) | | | | |.',..| +':. `. /| | | | | _ | |\ | | |.' :;::' +!::, `-!_| | | |\ | | | | | \ !_!.' ':;! +!::; ":;:!.!.\_!_!_!.!-'-':;:'' '''! +';:' `::;::;' '' ., . + `: .,. `' .::... . .::;::;' + `..:;::;:.. ::;::;:;:;, :;::;' + "-:;::;:;: ':;::;:'' ;.-' + ""`---...________...---'"" + +> Banana Terminal v1 < +)baaa"; + write("%s", banana.c_str()); + prompt(); +} + +void Terminal::prompt() +{ + write("%s", "$ "); } From 1d125772b18570592c3ee7e3a0fe20fd5109403a Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Thu, 17 Mar 2016 16:37:25 +0100 Subject: [PATCH 040/311] term: Fix ifconfig example --- src/debug/test_service.cpp | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/debug/test_service.cpp b/src/debug/test_service.cpp index 5056ab966f..6cb476789e 100644 --- a/src/debug/test_service.cpp +++ b/src/debug/test_service.cpp @@ -76,26 +76,24 @@ void Service::start() });*/ /// terminal /// + #define SERVICE_TELNET 23 auto& tcp = inet->tcp(); - auto& server = tcp.bind(23); // TELNET port + auto& server = tcp.bind(SERVICE_TELNET); server.onConnect( - [] (auto csock) + [] (auto client) { - printf("term.write('')\n"); - term = std::make_unique (csock); - + // create terminal with open TCP connection + term = std::make_unique (client); + // add 'ifconfig' command term->add( "ifconfig", "Show information about interfaces", - [csock] (const std::vector& args) -> int + [client] (const std::vector&) -> int { - printf("ifconfig called! argc = %u\n", args.size()); - - term->write("ifconfig - %s WutFace 4Head\r\n", csock->remote().to_string().c_str()); - return 1; + term->write("%s\r\n", inet->tcp().status().c_str()); + return 0; }); - - //term->write("hello\n"); }); + /// terminal /// printf("*** TEST SERVICE STARTED *** \n"); } From b656fd7232f23f1596ec6b7d1e16802301f32f23 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Thu, 17 Mar 2016 16:49:12 +0100 Subject: [PATCH 041/311] term: Add licence --- api/kernel/terminal.hpp | 17 +++++++++++++++++ api/serial | 17 +++++++++++++++++ api/term | 17 +++++++++++++++++ src/hw/serial.cpp | 17 +++++++++++++++++ src/kernel/terminal.cpp | 17 +++++++++++++++++ 5 files changed, 85 insertions(+) diff --git a/api/kernel/terminal.hpp b/api/kernel/terminal.hpp index 405a9da695..76dc381cac 100644 --- a/api/kernel/terminal.hpp +++ b/api/kernel/terminal.hpp @@ -1,3 +1,20 @@ +// This file is a part of the IncludeOS unikernel - www.includeos.org +// +// Copyright 2015 Oslo and Akershus University College of Applied Sciences +// and Alfred Bratterud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #ifndef KERNEL_BTERM_HPP #define KERNEL_BTERM_HPP diff --git a/api/serial b/api/serial index 622f4d6160..3edbaa54dc 100644 --- a/api/serial +++ b/api/serial @@ -1,3 +1,20 @@ +// This file is a part of the IncludeOS unikernel - www.includeos.org +// +// Copyright 2015 Oslo and Akershus University College of Applied Sciences +// and Alfred Bratterud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #ifndef SERIAL_HEADER #define SERIAL_HEADER diff --git a/api/term b/api/term index ba47990615..16a25ddd30 100644 --- a/api/term +++ b/api/term @@ -1,3 +1,20 @@ +// This file is a part of the IncludeOS unikernel - www.includeos.org +// +// Copyright 2015 Oslo and Akershus University College of Applied Sciences +// and Alfred Bratterud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #ifndef TERM_HEADER #define TERM_HEADER diff --git a/src/hw/serial.cpp b/src/hw/serial.cpp index cd8b9d7b9d..c42fddb813 100644 --- a/src/hw/serial.cpp +++ b/src/hw/serial.cpp @@ -1,3 +1,20 @@ +// This file is a part of the IncludeOS unikernel - www.includeos.org +// +// Copyright 2015 Oslo and Akershus University College of Applied Sciences +// and Alfred Bratterud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include #undef DEBUG diff --git a/src/kernel/terminal.cpp b/src/kernel/terminal.cpp index beaa24c74f..65aa59373b 100644 --- a/src/kernel/terminal.cpp +++ b/src/kernel/terminal.cpp @@ -1,3 +1,20 @@ +// This file is a part of the IncludeOS unikernel - www.includeos.org +// +// Copyright 2015 Oslo and Akershus University College of Applied Sciences +// and Alfred Bratterud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include #include From 247c6e9f858110f0beb091ae3c44bbe777d66dcf Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Thu, 17 Mar 2016 18:39:35 +0100 Subject: [PATCH 042/311] fs: FileSystem no longer template parameter --- api/fs/disk.hpp | 15 +--- api/kernel/terminal.hpp | 10 +++ api/memdisk | 8 +-- src/Makefile | 5 +- src/debug/test_disk.cpp | 10 +-- src/fs/disk.cpp | 151 ++++++++++++++++++++++++++++++++++++++++ src/kernel/terminal.cpp | 1 + test/fat/fat16.cpp | 2 +- 8 files changed, 174 insertions(+), 28 deletions(-) create mode 100644 src/fs/disk.cpp diff --git a/api/fs/disk.hpp b/api/fs/disk.hpp index cc633ccc38..11e76605f8 100644 --- a/api/fs/disk.hpp +++ b/api/fs/disk.hpp @@ -20,6 +20,7 @@ #define FS_DISK_HPP #include "common.hpp" +#include "filesystem.hpp" #include #include @@ -28,9 +29,6 @@ namespace fs { -class FileSystem; //< FileSystem interface - -template class Disk { public: struct Partition; //< Representation of a disk partition @@ -108,18 +106,9 @@ class Disk { private: hw::IDiskDevice& device; - std::unique_ptr filesys; + std::unique_ptr filesys; }; //< class Disk -template -inline Disk::Disk(hw::IDiskDevice& dev) : - device {dev} -{ - filesys.reset(new FS(device)); -} - } //< namespace fs -#include "disk.inl" - #endif //< FS_DISK_HPP diff --git a/api/kernel/terminal.hpp b/api/kernel/terminal.hpp index 76dc381cac..4409c1c7b7 100644 --- a/api/kernel/terminal.hpp +++ b/api/kernel/terminal.hpp @@ -20,9 +20,15 @@ #include #include +#include #include #include +namespace fs +{ + class Disk; +} + struct Command { using main_func = std::function&)>; @@ -38,6 +44,7 @@ class Terminal { public: using Connection_ptr = std::shared_ptr; + using Disk_ptr = std::shared_ptr; enum { NUL = 0, @@ -80,6 +87,9 @@ class Terminal std::function on_exit { [] {} }; + /// + void add_disk_commands(Disk_ptr disk); + private: void command(uint8_t cmd); void option(uint8_t option, uint8_t cmd); diff --git a/api/memdisk b/api/memdisk index 7f9635d0ac..890fdb4749 100644 --- a/api/memdisk +++ b/api/memdisk @@ -26,17 +26,15 @@ namespace fs { - // describe a disk with a FAT filesystem - using FatDisk = Disk; // its not really a shared memdisk right now, // but we are only using this in conjunction with // new_shared_memdisk() which very likely contains FAT - using MountedDisk = std::shared_ptr; + using Disk_ptr = std::shared_ptr; - inline MountedDisk new_shared_memdisk() + inline Disk_ptr new_shared_memdisk() { static MemDisk device; - return std::make_shared (device); + return std::make_shared (device); } } diff --git a/src/Makefile b/src/Makefile index a96dd8843e..3a17fe87de 100644 --- a/src/Makefile +++ b/src/Makefile @@ -60,7 +60,8 @@ CXXABI_OBJ = $(CXXABI:.cpp=.o) OS_OBJECTS = kernel/kernel_start.o kernel/syscalls.o kernel/vga.o \ kernel/interrupts.o kernel/os.o kernel/cpuid.o \ - kernel/irq_manager.o kernel/pci_manager.o kernel/terminal.o \ + kernel/irq_manager.o kernel/pci_manager.o \ + kernel/terminal.o kernel/terminal_disk.o \ crt/c_abi.o crt/string.o crt/quick_exit.o crt/cxx_abi.o crt/mman.o \ util/memstream.o \ hw/ide.o hw/pit.o hw/pic.o hw/pci_device.o hw/cpu_freq_sampling.o hw/serial.o\ @@ -72,7 +73,7 @@ OS_OBJECTS = kernel/kernel_start.o kernel/syscalls.o kernel/vga.o \ net/dns/dns.o net/dns/client.o net/dhcp/dh4client.o \ net/ip6/ip6.o net/ip6/icmp6.o net/ip6/udp6.o net/ip6/ndp.o \ net/packet.o net/buffer_store.o \ - fs/filesystem.o fs/mbr.o fs/vbr.o fs/path.o \ + fs/disk.o fs/filesystem.o fs/mbr.o fs/vbr.o fs/path.o \ fs/ext4.o fs/fat.o fs/fat_sync.o fs/memdisk.o CRTI_OBJ = crt/crti.o diff --git a/src/debug/test_disk.cpp b/src/debug/test_disk.cpp index b579f126b1..9ef2416bb7 100644 --- a/src/debug/test_disk.cpp +++ b/src/debug/test_disk.cpp @@ -2,13 +2,9 @@ #include const char* service_name__ = "..."; -//#include -//auto disk = fs::new_shared_memdisk(); - #include -#include -using FatDisk = fs::Disk; -std::shared_ptr disk; +#include +std::shared_ptr disk; void list_partitions(decltype(disk)); @@ -16,7 +12,7 @@ void Service::start() { // instantiate memdisk with FAT filesystem auto& device = hw::Dev::disk<0, hw::IDE>(hw::IDE::SLAVE); - disk = std::make_shared (device); + disk = std::make_shared (device); assert(disk); // if the disk is empty, we can't mount a filesystem anyways diff --git a/src/fs/disk.cpp b/src/fs/disk.cpp new file mode 100644 index 0000000000..c7828319c5 --- /dev/null +++ b/src/fs/disk.cpp @@ -0,0 +1,151 @@ +// This file is a part of the IncludeOS unikernel - www.includeos.org +// +// Copyright 2015 Oslo and Akershus University College of Applied Sciences +// and Alfred Bratterud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +namespace fs { + +Disk::Disk(hw::IDiskDevice& dev) + : device {dev} +{ + // for now we can only assume FAT, anyways + filesys.reset(new FAT(device)); +} + +void Disk::partitions(on_parts_func func) { + + /** Read Master Boot Record (sector 0) */ + device.read(0, + [this, func] (hw::IDiskDevice::buffer_t data) + { + std::vector parts; + + if (!data) { + func(true, parts); + return; + } + + // First sector is the Master Boot Record + auto* mbr =(MBR::mbr*) data.get(); + + for (int i {0}; i < 4; ++i) { + // all the partitions are offsets to potential Volume Boot Records + parts.emplace_back( + mbr->part[i].flags, //< flags + mbr->part[i].type, //< id + mbr->part[i].lba_begin, //< LBA + mbr->part[i].sectors); + } + + func(no_error, parts); + }); +} + +void Disk::mount(on_mount_func func) +{ + device.read(0, + [this, func] (hw::IDiskDevice::buffer_t data) + { + if (!data) { + // TODO: error-case for unable to read MBR + mount(INVALID, func); + return; + } + + // auto-detect FAT on MBR: + auto* mbr = (MBR::mbr*) data.get(); + MBR::BPB* bpb = mbr->bpb(); + + if (bpb->bytes_per_sector >= 512 + && bpb->fa_tables != 0 + && bpb->signature != 0) // check MBR signature too + { + // we have FAT on MBR (and we are assuming mount FAT) + mount(MBR, func); + return; + } + + // go through partition list + for (int i = 0; i < 4; i++) + { + if (mbr->part[i].type != 0 // 0 is unused partition + && mbr->part[i].lba_begin != 0 // 0 is MBR anyways + && mbr->part[i].sectors != 0) // 0 means no size, so... + { + mount((partition_t) (VBR1 + i), func); + return; + } + } + + // no partition was found (TODO: extended partitions) + mount(INVALID, func); + return; + }); +} + +void Disk::mount(partition_t part, on_mount_func func) { + + if (part == INVALID) + { + // Something bad happened maybe in auto-detect + // Either way, no partition was found + func(true); + return; + } + else if (part == MBR) + { + // For the MBR case, all we need to do is mount on sector 0 + fs().mount(0, device.size(), func); + } + else + { + /** + * Otherwise, we will have to read the LBA offset + * of the partition to be mounted + */ + device.read(0, + [this, part, func] (hw::IDiskDevice::buffer_t data) + { + if (!data) { + // TODO: error-case for unable to read MBR + func(true); + return; + } + + auto* mbr = (MBR::mbr*) data.get(); //< Treat data as MBR + auto pint = static_cast(part - 1); //< Treat VBR1 as index 0 etc. + + /** Get LBA from selected partition */ + auto lba_base = mbr->part[pint].lba_begin; + auto lba_size = mbr->part[pint].sectors; + + /** + * Call the filesystems mount function + * with lba_begin as base address + */ + fs().mount(lba_base, lba_size, func); + }); + } +} + +std::string Disk::Partition::name() const { + return MBR::id_to_name(id); +} + +} //< namespace fs diff --git a/src/kernel/terminal.cpp b/src/kernel/terminal.cpp index 65aa59373b..a0c3145255 100644 --- a/src/kernel/terminal.cpp +++ b/src/kernel/terminal.cpp @@ -16,6 +16,7 @@ // limitations under the License. #include +#include #include #include diff --git a/test/fat/fat16.cpp b/test/fat/fat16.cpp index 34c938a18b..c527a0113c 100644 --- a/test/fat/fat16.cpp +++ b/test/fat/fat16.cpp @@ -65,7 +65,7 @@ void Service::start() CHECK(!err, "Filesystem mounted on VBR1"); assert(!err); - // verify that we can read Makefile + // verify that we can read file auto& fs = disk->fs(); auto ent = fs.stat("/banana.txt"); CHECK(ent.is_valid(), "Stat file in root dir"); From 757c73883a0d5db5efdf061f3cc387010cd1f16e Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Thu, 17 Mar 2016 18:42:49 +0100 Subject: [PATCH 043/311] test: Update FAT test --- test/fat/fat32.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/fat/fat32.cpp b/test/fat/fat32.cpp index e0c97d2901..f0c6c4514e 100644 --- a/test/fat/fat32.cpp +++ b/test/fat/fat32.cpp @@ -21,14 +21,13 @@ #include #include -using FatDisk = fs::Disk; -std::shared_ptr disk; +std::shared_ptr disk; void Service::start() { INFO("FAT32", "Running tests for FAT32"); auto& device = hw::Dev::disk<0, hw::IDE>(hw::IDE::SLAVE); - disk = std::make_shared (device); + disk = std::make_shared (device); assert(disk); // verify that the size is indeed N sectors From 27586908af6235c7fc5891f71a8f0ff3d9ddc1c2 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Thu, 17 Mar 2016 20:33:22 +0100 Subject: [PATCH 044/311] term: Disk terminal services --- src/kernel/terminal_disk.cpp | 108 +++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 src/kernel/terminal_disk.cpp diff --git a/src/kernel/terminal_disk.cpp b/src/kernel/terminal_disk.cpp new file mode 100644 index 0000000000..4b9532ee8c --- /dev/null +++ b/src/kernel/terminal_disk.cpp @@ -0,0 +1,108 @@ +// This file is a part of the IncludeOS unikernel - www.includeos.org +// +// Copyright 2015 Oslo and Akershus University College of Applied Sciences +// and Alfred Bratterud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +void Terminal::add_disk_commands(Disk_ptr disk) +{ + // add 'ls' command + add("ls", "List files in a folder", + [this, disk] (const std::vector& args) -> int + { + // current directory, somehow... + std::string operand = "/"; + if (!args.empty()) operand = args[0]; + + auto& fs = disk->fs(); + auto vec = fs::new_shared_vector(); + auto err = fs.ls(operand, vec); + if (!err) + { + this->write("%s \t%s \t%s \t%s\r\n", + "Name", "Size", "Type", "Sector"); + for (auto& ent : *vec) + { + this->write("%s \t%llu \t%s \t%llu\r\n", + ent.name().c_str(), ent.size, ent.type_string().c_str(), ent.block); + } + this->write("Total %u\r\n", vec->size()); + return 0; + } + else + { + this->write("Could not list %s\r\n", args[0].c_str()); + return 1; + } + }); + // add 'stat' command + add("stat", "List file information", + [this, disk] (const std::vector& args) -> int + { + if (!args.empty()) + { + auto& fs = disk->fs(); + auto ent = fs.stat(args[0]); + if (ent.is_valid()) + { + this->write("%s \t%s \t%s \t%s\r\n", + "Name", "Size", "Type", "Sector"); + this->write("%s \t%llu \t%s \t%llu\r\n", + ent.name().c_str(), ent.size, ent.type_string().c_str(), ent.block); + return 0; + } + else + { + this->write("stat: Cannot stat '%s'\r\n", args[0].c_str()); + return 1; + } + } + else + { + this->write("%s\r\n", "stat: Not enough arguments"); + return 1; + } + }); + // add 'cat' command + add("cat", "Concatenate files and print", + [this, disk] (const std::vector& args) -> int + { + auto& fs = disk->fs(); + + for (const auto& file : args) + { + // get file information + auto ent = fs.stat(file); + if (!ent.is_valid()) + { + this->write("cat: '%s': No such file or directory\r\n", file.c_str()); + return 1; + } + // read file contents + auto buf = fs.read(ent, 0, ent.size); + if (!buf.buffer) + { + this->write("cat: '%s': I/O error\r\n", file.c_str()); + return 1; + } + // write to terminal client + std::string buffer((char*) buf.buffer.get(), buf.len); + this->write("%s\r\n", buffer.c_str()); + } + return 0; + }); +} From 271b83dea87f02d2f31d3b819f9f9c51bb217261 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Thu, 17 Mar 2016 20:37:11 +0100 Subject: [PATCH 045/311] debug: Now creating empty smalldisk if needed --- src/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Makefile b/src/Makefile index 3a17fe87de..7627423ec8 100644 --- a/src/Makefile +++ b/src/Makefile @@ -120,6 +120,7 @@ TEST_OBJ = debug/test_service.o util/service_name.o test_service: CPPOPTS += -DSERVICE_NAME="\"Test Service\"" test_service: $(TEST_OBJ) $(CRTI_OBJ) $(CRTN_OBJ) @echo "\n>> Linking test service" + touch smalldisk $(LD_INC) -v $(LDOPTS) $(CRTBEGIN_OBJ) $(TEST_OBJ) $(LIBS_OBJ) $(CRTEND_OBJ) -o debug/$@ test_ipv6: CPPOPTS += -DSERVICE_NAME="\"IPv6 Test Service\"" @@ -130,6 +131,7 @@ test_ipv6: debug/test_ipv6.o $(CRTI_OBJ) $(CRTN_OBJ) test_disk: CPPOPTS += -DSERVICE_NAME="\"Virtio-disk Test\"" test_disk: debug/test_disk.o $(CRTI_OBJ) $(CRTN_OBJ) memdisk @echo "\n>> Linking disk test" + touch smalldisk $(LD_INC) -v $(LDOPTS) $(CRTBEGIN_OBJ) debug/test_disk.o $(LIBS_OBJ) $(CRTEND_OBJ) memdisk.o -o debug/$@ test_tcp: CPPOPTS += -DSERVICE_NAME="\"TCP Test Service\"" From 2e726035a9e1b63b6ce68e42cd66c80449a42faf Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Thu, 17 Mar 2016 21:52:00 +0100 Subject: [PATCH 046/311] fs: Remove disk.inl, add current directory to terminal --- api/fs/disk.hpp | 2 + api/fs/disk.inl | 148 ----------------------------------- api/memdisk | 7 +- src/kernel/terminal_disk.cpp | 62 +++++++++++++-- 4 files changed, 60 insertions(+), 159 deletions(-) delete mode 100644 api/fs/disk.inl diff --git a/api/fs/disk.hpp b/api/fs/disk.hpp index 11e76605f8..d49137cde8 100644 --- a/api/fs/disk.hpp +++ b/api/fs/disk.hpp @@ -109,6 +109,8 @@ class Disk { std::unique_ptr filesys; }; //< class Disk +using Disk_ptr = std::shared_ptr; + } //< namespace fs #endif //< FS_DISK_HPP diff --git a/api/fs/disk.inl b/api/fs/disk.inl deleted file mode 100644 index dd63a571e6..0000000000 --- a/api/fs/disk.inl +++ /dev/null @@ -1,148 +0,0 @@ -// This file is a part of the IncludeOS unikernel - www.includeos.org -// -// Copyright 2015 Oslo and Akershus University College of Applied Sciences -// and Alfred Bratterud -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "mbr.hpp" - -namespace fs { - -template -inline void -Disk::partitions(on_parts_func func) { - /** Read Master Boot Record (sector 0) */ - device.read(0, - [this, func] (hw::IDiskDevice::buffer_t data) - { - std::vector parts; - - if (!data) { - func(true, parts); - return; - } - - // First sector is the Master Boot Record - auto* mbr =(MBR::mbr*) data.get(); - - for (int i {0}; i < 4; ++i) { - // all the partitions are offsets to potential Volume Boot Records - parts.emplace_back( - mbr->part[i].flags, //< flags - mbr->part[i].type, //< id - mbr->part[i].lba_begin, //< LBA - mbr->part[i].sectors); - } - - func(no_error, parts); - }); -} - -template -inline void -Disk::mount(on_mount_func func) -{ - device.read(0, - [this, func] (hw::IDiskDevice::buffer_t data) - { - if (!data) { - // TODO: error-case for unable to read MBR - mount(INVALID, func); - return; - } - - // auto-detect FAT on MBR: - auto* mbr = (MBR::mbr*) data.get(); - MBR::BPB* bpb = mbr->bpb(); - - if (bpb->bytes_per_sector >= 512 - && bpb->fa_tables != 0 - && bpb->signature != 0) // check MBR signature too - { - // we have FAT on MBR (and we are assuming mount FAT) - mount(MBR, func); - return; - } - - // go through partition list - for (int i = 0; i < 4; i++) - { - if (mbr->part[i].type != 0 // 0 is unused partition - && mbr->part[i].lba_begin != 0 // 0 is MBR anyways - && mbr->part[i].sectors != 0) // 0 means no size, so... - { - mount((partition_t) (VBR1 + i), func); - return; - } - } - - // no partition was found (TODO: extended partitions) - mount(INVALID, func); - return; - }); -} - -template -inline void -Disk::mount(partition_t part, on_mount_func func) { - - if (part == INVALID) - { - // Something bad happened maybe in auto-detect - // Either way, no partition was found - func(true); - return; - } - else if (part == MBR) - { - // For the MBR case, all we need to do is mount on sector 0 - fs().mount(0, device.size(), func); - } - else - { - /** - * Otherwise, we will have to read the LBA offset - * of the partition to be mounted - */ - device.read(0, - [this, part, func] (hw::IDiskDevice::buffer_t data) - { - if (!data) { - // TODO: error-case for unable to read MBR - func(true); - return; - } - - auto* mbr = (MBR::mbr*) data.get(); //< Treat data as MBR - auto pint = static_cast(part - 1); //< Treat VBR1 as index 0 etc. - - /** Get LBA from selected partition */ - auto lba_base = mbr->part[pint].lba_begin; - auto lba_size = mbr->part[pint].sectors; - - /** - * Call the filesystems mount function - * with lba_begin as base address - */ - fs().mount(lba_base, lba_size, func); - }); - } -} - -template -std::string Disk::Partition::name() const { - return MBR::id_to_name(id); -} - -} //< namespace fs diff --git a/api/memdisk b/api/memdisk index 890fdb4749..c05f5dcc93 100644 --- a/api/memdisk +++ b/api/memdisk @@ -22,15 +22,10 @@ #include "fs/disk.hpp" #include "fs/memdisk.hpp" -#include "fs/fat.hpp" // FAT filesystem namespace fs { - // its not really a shared memdisk right now, - // but we are only using this in conjunction with - // new_shared_memdisk() which very likely contains FAT - using Disk_ptr = std::shared_ptr; - + // new_shared_memdisk() very likely contains FAT inline Disk_ptr new_shared_memdisk() { static MemDisk device; diff --git a/src/kernel/terminal_disk.cpp b/src/kernel/terminal_disk.cpp index 4b9532ee8c..03966875aa 100644 --- a/src/kernel/terminal_disk.cpp +++ b/src/kernel/terminal_disk.cpp @@ -16,21 +16,73 @@ // limitations under the License. #include -#include +#include +#include + +using namespace fs; + +int target_directory(Disk_ptr disk, const Path& path) +{ + // avoid stat on root directory + if (path.empty()) return 0; + + std::string strpath(path.to_string()); + + auto& fs = disk->fs(); + auto ent = fs.stat(strpath); + + if (!ent.is_valid()) + return 1; + else if (!ent.is_dir()) + return 1; + else + return 0; +} void Terminal::add_disk_commands(Disk_ptr disk) { + auto curdir = std::make_shared ("/"); + + // add 'cd' command + add("cd", "Change current directory", + [this, curdir, disk] (const std::vector& args) -> int + { + // current directory, somehow... + std::string target = "/"; + if (!args.empty()) target = args[0]; + + Path path(*curdir); + path += target; + + int rv = target_directory(disk, path); + if (rv) + { + this->write("cd: %s: No such file or directory\r\n", target.c_str()); + return rv; + } + *curdir = path.to_string(); + return 0; + }); // add 'ls' command add("ls", "List files in a folder", - [this, disk] (const std::vector& args) -> int + [this, curdir, disk] (const std::vector& args) -> int { // current directory, somehow... - std::string operand = "/"; - if (!args.empty()) operand = args[0]; + Path path(*curdir); + if (!args.empty()) path += args[0]; + + int rv = target_directory(disk, path); + if (rv) + { + this->write("ls: %s: No such file or directory\r\n", path.to_string().c_str()); + return rv; + } + + std::string target = path.to_string(); auto& fs = disk->fs(); auto vec = fs::new_shared_vector(); - auto err = fs.ls(operand, vec); + auto err = fs.ls(target, vec); if (!err) { this->write("%s \t%s \t%s \t%s\r\n", From e1a354d99a4156a4cea6083317f928397866709a Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Thu, 17 Mar 2016 21:52:50 +0100 Subject: [PATCH 047/311] test: Terminal with filesystem commands --- test/term/Makefile | 19 +++++++++++++ test/term/banana.txt | 13 +++++++++ test/term/term.cpp | 64 ++++++++++++++++++++++++++++++++++++++++++++ test/term/test.sh | 19 +++++++++++++ 4 files changed, 115 insertions(+) create mode 100644 test/term/Makefile create mode 100644 test/term/banana.txt create mode 100644 test/term/term.cpp create mode 100755 test/term/test.sh diff --git a/test/term/Makefile b/test/term/Makefile new file mode 100644 index 0000000000..ad0d5515b1 --- /dev/null +++ b/test/term/Makefile @@ -0,0 +1,19 @@ +################################################# +# IncludeOS SERVICE makefile # +################################################# + +# The name of your service +SERVICE = Test +SERVICE_NAME = The Terminal Test Service + +# Your service parts +FILES=term.cpp +# Your disk image +DISK= + +# IncludeOS location +ifndef INCLUDEOS_INSTALL +INCLUDEOS_INSTALL=$(HOME)/IncludeOS_install +endif + +include $(INCLUDEOS_INSTALL)/Makeseed diff --git a/test/term/banana.txt b/test/term/banana.txt new file mode 100644 index 0000000000..8e3c13d0c8 --- /dev/null +++ b/test/term/banana.txt @@ -0,0 +1,13 @@ + ____ ___ + | _ \ ___ _ _.' _ `. + _ | [_) )' _ `._ _ ___ ! \ | | (_) | _ +|:;.| _ <| (_) | \ | |' _ `| \| | _ | .:;| +| `.[_) ) _ | \| | (_) | | | | |.',..| +':. `. /| | | | | _ | |\ | | |.' :;::' + !::, `-!_| | | |\ | | | | | \ !_!.' ':;! + !::; ":;:!.!.\_!_!_!.!-'-':;:'' '''! + ';:' `::;::;' '' ., . + `: .,. `' .::... . .::;::;' + `..:;::;:.. ::;::;:;:;, :;::;' + "-:;::;:;: ':;::;:'' ;.-' + ""`---...________...---'"" diff --git a/test/term/term.cpp b/test/term/term.cpp new file mode 100644 index 0000000000..0450b5752f --- /dev/null +++ b/test/term/term.cpp @@ -0,0 +1,64 @@ +// This file is a part of the IncludeOS unikernel - www.includeos.org +// +// Copyright 2015 Oslo and Akershus University College of Applied Sciences +// and Alfred Bratterud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include +std::unique_ptr > inet; + +#include +std::unique_ptr term; + +#include + +void Service::start() +{ + // boilerplate + hw::Nic& eth0 = hw::Dev::eth<0,VirtioNet>(); + inet = std::make_unique >(eth0); + inet->network_config( + {{ 10,0,0,42 }}, // IP + {{ 255,255,255,0 }}, // Netmask + {{ 10,0,0,1 }}, // Gateway + {{ 8,8,8,8 }} ); // DNS + + INFO("TERM", "Running tests for Terminal"); + auto disk = fs::new_shared_memdisk(); + assert(disk); + + // auto-mount filesystem + disk->mount( + [disk] (fs::error_t err) + { + assert(!err); + + /// terminal /// + #define SERVICE_TELNET 23 + auto& tcp = inet->tcp(); + auto& server = tcp.bind(SERVICE_TELNET); + server.onConnect( + [disk] (auto client) + { + // create terminal with open TCP connection + term = std::make_unique (client); + term->add_disk_commands(disk); + }); + /// terminal /// + }); +} diff --git a/test/term/test.sh b/test/term/test.sh new file mode 100755 index 0000000000..eae2640310 --- /dev/null +++ b/test/term/test.sh @@ -0,0 +1,19 @@ +#!/bin/bash +source ../test_base +mkdir tmpdisk + +### FAT16 TEST ### +rm -f my.disk +dd if=/dev/zero of=my.disk count=6500 +mkfs.fat my.disk +sudo mount my.disk tmpdisk/ +sudo cp banana.txt tmpdisk/ +sudo mkdir -p tmpdisk/dir1/dir2/dir3 +sync # Mui Importante +sudo umount tmpdisk/ + +make SERVICE=Test DISK=my.disk FILES=term.cpp +start Test.img "Term: Terminal test" +make SERVICE=Test FILES=term.cpp clean +rm -f memdisk.o my.disk +rmdir tmpdisk/ From 549f97402f925be00f40fe314a5e9f15884563da Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Thu, 17 Mar 2016 22:12:49 +0100 Subject: [PATCH 048/311] term: Added serial support --- api/kernel/terminal.hpp | 14 +++++++------- src/debug/test_service.cpp | 29 ++++++++++++----------------- src/kernel/terminal.cpp | 33 +++++++++++++++++++++++++++++++-- 3 files changed, 50 insertions(+), 26 deletions(-) diff --git a/api/kernel/terminal.hpp b/api/kernel/terminal.hpp index 4409c1c7b7..21180b13ce 100644 --- a/api/kernel/terminal.hpp +++ b/api/kernel/terminal.hpp @@ -28,6 +28,10 @@ namespace fs { class Disk; } +namespace hw +{ + class Serial; +} struct Command { @@ -57,15 +61,10 @@ class Terminal CR = 13 }; - using on_read_func = std::function; using on_write_func = std::function; Terminal(Connection_ptr); - - void set_on_read(on_read_func callback) - { - on_read = callback; - } + Terminal(hw::Serial& serial); template void add(const std::string& command, @@ -91,6 +90,8 @@ class Terminal void add_disk_commands(Disk_ptr disk); private: + Terminal(); + void command(uint8_t cmd); void option(uint8_t option, uint8_t cmd); void read(const char* buf, size_t len); @@ -99,7 +100,6 @@ class Terminal void intro(); void prompt(); - on_read_func on_read; on_write_func on_write; bool iac; diff --git a/src/debug/test_service.cpp b/src/debug/test_service.cpp index 6cb476789e..c8c14099b7 100644 --- a/src/debug/test_service.cpp +++ b/src/debug/test_service.cpp @@ -26,6 +26,7 @@ using namespace std::chrono; // An IP-stack object std::unique_ptr > inet; +#include std::unique_ptr term; void Service::start() @@ -76,23 +77,17 @@ void Service::start() });*/ /// terminal /// - #define SERVICE_TELNET 23 - auto& tcp = inet->tcp(); - auto& server = tcp.bind(SERVICE_TELNET); - server.onConnect( - [] (auto client) - { - // create terminal with open TCP connection - term = std::make_unique (client); - // add 'ifconfig' command - term->add( - "ifconfig", "Show information about interfaces", - [client] (const std::vector&) -> int - { - term->write("%s\r\n", inet->tcp().status().c_str()); - return 0; - }); - }); + auto& serial = hw::Serial::port<1> (); + // create terminal with open TCP connection + term = std::make_unique (serial); + // add 'ifconfig' command + term->add( + "ifconfig", "Show information about interfaces", + [] (const std::vector&) -> int + { + term->write("%s\r\n", inet->tcp().status().c_str()); + return 0; + }); /// terminal /// printf("*** TEST SERVICE STARTED *** \n"); diff --git a/src/kernel/terminal.cpp b/src/kernel/terminal.cpp index a0c3145255..d9cc449112 100644 --- a/src/kernel/terminal.cpp +++ b/src/kernel/terminal.cpp @@ -22,8 +22,14 @@ #include #include -Terminal::Terminal(Connection_ptr csock) +Terminal::Terminal() : iac(false), newline(false), subcmd(0) +{ + add_basic_commands(); +} + +Terminal::Terminal(Connection_ptr csock) + : Terminal() { csock->onReceive( [this] (auto conn, bool) @@ -44,8 +50,31 @@ Terminal::Terminal(Connection_ptr csock) [csock] { csock->close(); }; + // after setting up everything, show introduction + intro(); +} + +Terminal::Terminal(hw::Serial& serial) + : Terminal() +{ + serial.on_data( + [this] (char c) + { + this->read(&c, 1); + }); - add_basic_commands(); + on_write = + [&serial] (const char* buffer, size_t len) + { + for (size_t i = 0; i < len; i++) + serial.write(buffer[i]); + }; + + on_exit = + [] { + // do nothing + }; + // after setting up everything, show introduction intro(); } From 00c73bfe3a9a67737f0da175fe470ca2bdf3257b Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Thu, 17 Mar 2016 22:35:49 +0100 Subject: [PATCH 049/311] term: Serial input now showing on screen --- src/kernel/terminal.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/kernel/terminal.cpp b/src/kernel/terminal.cpp index d9cc449112..180983141c 100644 --- a/src/kernel/terminal.cpp +++ b/src/kernel/terminal.cpp @@ -58,9 +58,18 @@ Terminal::Terminal(hw::Serial& serial) : Terminal() { serial.on_data( - [this] (char c) + [this, &serial] (char c) { this->read(&c, 1); + if (c == CR) + { + c = LF; + this->read(&c, 1); + } + else + { + serial.write(c); + } }); on_write = From f7f55f84948d6cf50d488f43b04307adfc8fc50b Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sat, 19 Mar 2016 22:09:24 +0100 Subject: [PATCH 050/311] Editorconfig whitespace updates --- api/hw/nic.hpp | 102 ++++++++--------- api/net/ethernet.hpp | 218 ++++++++++++++++++------------------ api/net/inet_common.hpp | 32 +++--- api/net/packet.hpp | 200 ++++++++++++++++----------------- src/net/packet.cpp | 52 ++++----- src/virtio/virtio_queue.cpp | 88 +++++++-------- src/virtio/virtionet.cpp | 18 +-- 7 files changed, 355 insertions(+), 355 deletions(-) diff --git a/api/hw/nic.hpp b/api/hw/nic.hpp index e2788d91fd..a7bac829ef 100644 --- a/api/hw/nic.hpp +++ b/api/hw/nic.hpp @@ -26,69 +26,69 @@ namespace hw { -/** - * A public interface for Network cards - * - * @note: The requirements for a driver is implicitly given by how it's used below, - * rather than explicitly by inheritance. This avoids vtables. - * - * @note: Drivers are passed in as template paramter so that only the drivers - * we actually need will be added to our project. - */ -template -class Nic { -public: - using driver_t = DRIVER; + /** + * A public interface for Network cards + * + * @note: The requirements for a driver is implicitly given by how it's used below, + * rather than explicitly by inheritance. This avoids vtables. + * + * @note: Drivers are passed in as template paramter so that only the drivers + * we actually need will be added to our project. + */ + template + class Nic { + public: + using driver_t = DRIVER; - /** Get a readable name. */ - inline const char* name() const noexcept - { return driver_.name(); } + /** Get a readable name. */ + inline const char* name() const noexcept + { return driver_.name(); } - /** The mac address. */ - inline const net::Ethernet::addr& mac() - { return driver_.mac(); } + /** The mac address. */ + inline const net::Ethernet::addr& mac() + { return driver_.mac(); } - inline void set_linklayer_out(net::upstream del) - { driver_.set_linklayer_out(del); } + inline void set_linklayer_out(net::upstream del) + { driver_.set_linklayer_out(del); } - inline net::upstream get_linklayer_out() - { return driver_.get_linklayer_out(); } + inline net::upstream get_linklayer_out() + { return driver_.get_linklayer_out(); } - inline void transmit(net::Packet_ptr pckt) - { driver_.transmit(pckt); } + inline void transmit(net::Packet_ptr pckt) + { driver_.transmit(pckt); } - inline uint16_t MTU() const noexcept - { return driver_.MTU(); } + inline uint16_t MTU() const noexcept + { return driver_.MTU(); } - inline net::BufferStore& bufstore() noexcept - { return driver_.bufstore(); } + inline net::BufferStore& bufstore() noexcept + { return driver_.bufstore(); } -private: - driver_t driver_; + private: + driver_t driver_; - /** - * Constructor - * - * Just a wrapper around the driver constructor. - * - * @note: The Dev-class is a friend and will call this - */ - Nic(PCI_Device& d) : driver_{d} {} + /** + * Constructor + * + * Just a wrapper around the driver constructor. + * + * @note: The Dev-class is a friend and will call this + */ + Nic(PCI_Device& d) : driver_{d} {} - friend class Dev; -}; + friend class Dev; + }; -/** Future drivers may start out like so, */ -class E1000 { -public: - inline const char* name() const noexcept - { return "E1000 Driver"; } - //...whatever the Nic class implicitly needs -}; - -/** Hopefully somebody will port a driver for this one */ -class RTL8139; + /** Future drivers may start out like so, */ + class E1000 { + public: + inline const char* name() const noexcept + { return "E1000 Driver"; } + //...whatever the Nic class implicitly needs + }; + /** Hopefully somebody will port a driver for this one */ + class RTL8139; + } //< namespace hw #endif // NIC_HPP diff --git a/api/net/ethernet.hpp b/api/net/ethernet.hpp index f70c2e855e..47736f4ce3 100644 --- a/api/net/ethernet.hpp +++ b/api/net/ethernet.hpp @@ -25,143 +25,143 @@ namespace net { -/** Ethernet packet handling. */ -class Ethernet { -public: - static constexpr size_t ETHER_ADDR_LEN = 6; - static constexpr size_t MINIMUM_PAYLOAD = 46; + /** Ethernet packet handling. */ + class Ethernet { + public: + static constexpr size_t ETHER_ADDR_LEN = 6; + static constexpr size_t MINIMUM_PAYLOAD = 46; - /** - * Some big-endian ethernet types - * - * From http://en.wikipedia.org/wiki/EtherType - */ - enum ethertype_le { - _ETH_IP4 = 0x0800, - _ETH_ARP = 0x0806, - _ETH_WOL = 0x0842, - _ETH_IP6 = 0x86DD, - _ETH_FLOW = 0x8808, - _ETH_JUMBO = 0x8870 - }; + /** + * Some big-endian ethernet types + * + * From http://en.wikipedia.org/wiki/EtherType + */ + enum ethertype_le { + _ETH_IP4 = 0x0800, + _ETH_ARP = 0x0806, + _ETH_WOL = 0x0842, + _ETH_IP6 = 0x86DD, + _ETH_FLOW = 0x8808, + _ETH_JUMBO = 0x8870 + }; - /** Little-endian ethertypes. */ - enum ethertype { - ETH_IP4 = 0x8, - ETH_ARP = 0x608, - ETH_WOL = 0x4208, - ETH_IP6 = 0xdd86, - ETH_FLOW = 0x888, - ETH_JUMBO = 0x7088, - ETH_VLAN = 0x81 - }; + /** Little-endian ethertypes. */ + enum ethertype { + ETH_IP4 = 0x8, + ETH_ARP = 0x608, + ETH_WOL = 0x4208, + ETH_IP6 = 0xdd86, + ETH_FLOW = 0x888, + ETH_JUMBO = 0x7088, + ETH_VLAN = 0x81 + }; - // MAC address - union addr { - uint8_t part[ETHER_ADDR_LEN]; + // MAC address + union addr { + uint8_t part[ETHER_ADDR_LEN]; - struct { - uint16_t minor; - uint32_t major; - } __attribute__((packed)); + struct { + uint16_t minor; + uint32_t major; + } __attribute__((packed)); - addr& operator=(const addr cpy) noexcept { - minor = cpy.minor; - major = cpy.major; - return *this; - } + addr& operator=(const addr cpy) noexcept { + minor = cpy.minor; + major = cpy.major; + return *this; + } - // hex string representation - std::string str() const { - char eth_addr[17]; - sprintf(eth_addr, "%1x:%1x:%1x:%1x:%1x:%1x", - part[0], part[1], part[2], - part[3], part[4], part[5]); - return eth_addr; - } + // hex string representation + std::string str() const { + char eth_addr[17]; + sprintf(eth_addr, "%1x:%1x:%1x:%1x:%1x:%1x", + part[0], part[1], part[2], + part[3], part[4], part[5]); + return eth_addr; + } - /** Check for equality */ - bool operator==(const addr mac) const noexcept - { - return strncmp( - reinterpret_cast(part), - reinterpret_cast(mac.part), - ETHER_ADDR_LEN) == 0; - } + /** Check for equality */ + bool operator==(const addr mac) const noexcept + { + return strncmp( + reinterpret_cast(part), + reinterpret_cast(mac.part), + ETHER_ADDR_LEN) == 0; + } - static const addr MULTICAST_FRAME; - static const addr BROADCAST_FRAME; + static const addr MULTICAST_FRAME; + static const addr BROADCAST_FRAME; - static const addr IPv6mcast_01; - static const addr IPv6mcast_02; + static const addr IPv6mcast_01; + static const addr IPv6mcast_02; - } __attribute__((packed)); //< union addr + } __attribute__((packed)); //< union addr - /** Constructor */ - explicit Ethernet(addr mac) noexcept; + /** Constructor */ + explicit Ethernet(addr mac) noexcept; - struct header { - addr dest; - addr src; - unsigned short type; + struct header { + addr dest; + addr src; + unsigned short type; - } __attribute__((packed)) ; + } __attribute__((packed)) ; - /** Bottom upstream input, "Bottom up". Handle raw ethernet buffer. */ - void bottom(Packet_ptr); + /** Bottom upstream input, "Bottom up". Handle raw ethernet buffer. */ + void bottom(Packet_ptr); - /** Delegate upstream ARP handler. */ - void set_arp_handler(upstream del) - { arp_handler_ = del; } + /** Delegate upstream ARP handler. */ + void set_arp_handler(upstream del) + { arp_handler_ = del; } - upstream get_arp_handler() - { return arp_handler_; } + upstream get_arp_handler() + { return arp_handler_; } - /** Delegate upstream IPv4 handler. */ - void set_ip4_handler(upstream del) - { ip4_handler_ = del; } + /** Delegate upstream IPv4 handler. */ + void set_ip4_handler(upstream del) + { ip4_handler_ = del; } - /** Delegate upstream IPv4 handler. */ - upstream get_ip4_handler() - { return ip4_handler_; } + /** Delegate upstream IPv4 handler. */ + upstream get_ip4_handler() + { return ip4_handler_; } - /** Delegate upstream IPv6 handler. */ - void set_ip6_handler(upstream del) - { ip6_handler_ = del; }; + /** Delegate upstream IPv6 handler. */ + void set_ip6_handler(upstream del) + { ip6_handler_ = del; }; - /** Delegate downstream */ - void set_physical_out(downstream del) - { physical_out_ = del; } + /** Delegate downstream */ + void set_physical_out(downstream del) + { physical_out_ = del; } - /** @return Mac address of the underlying device */ - const addr mac() const noexcept - { return mac_; } + /** @return Mac address of the underlying device */ + const addr mac() const noexcept + { return mac_; } - /** Transmit data, with preallocated space for eth.header */ - void transmit(Packet_ptr); + /** Transmit data, with preallocated space for eth.header */ + void transmit(Packet_ptr); -private: - /** MAC address */ - addr mac_; + private: + /** MAC address */ + addr mac_; - /** Upstream OUTPUT connections */ - upstream ip4_handler_ = [](Packet_ptr){}; - upstream ip6_handler_ = [](Packet_ptr){}; - upstream arp_handler_ = [](Packet_ptr){}; + /** Upstream OUTPUT connections */ + upstream ip4_handler_ = [](Packet_ptr){}; + upstream ip6_handler_ = [](Packet_ptr){}; + upstream arp_handler_ = [](Packet_ptr){}; - /** Downstream OUTPUT connection */ - downstream physical_out_ = [](Packet_ptr){}; + /** Downstream OUTPUT connection */ + downstream physical_out_ = [](Packet_ptr){}; - /* + /* - +--|IP4|---|ARP|---|IP6|---+ - | | - | Ethernet | - | | - +---------|Phys|-----------+ + +--|IP4|---|ARP|---|IP6|---+ + | | + | Ethernet | + | | + +---------|Phys|-----------+ - */ -}; //< class Ethernet + */ + }; //< class Ethernet } // namespace net #endif //< NET_ETHERNET_HPP diff --git a/api/net/inet_common.hpp b/api/net/inet_common.hpp index 723ef02fee..bf531f4189 100644 --- a/api/net/inet_common.hpp +++ b/api/net/inet_common.hpp @@ -23,27 +23,27 @@ #include namespace net { -// Packet must be forward declared to avoid circular dependency -// i.e. IP uses Packet, and Packet uses IP headers -class Packet; -class Ethernet; + // Packet must be forward declared to avoid circular dependency + // i.e. IP uses Packet, and Packet uses IP headers + class Packet; + class Ethernet; -using LinkLayer = Ethernet; + using LinkLayer = Ethernet; -using Packet_ptr = std::shared_ptr; + using Packet_ptr = std::shared_ptr; -// Downstream / upstream delegates -using downstream = delegate; -using upstream = downstream; + // Downstream / upstream delegates + using downstream = delegate; + using upstream = downstream; -// Compute the internet checksum for the buffer / buffer part provided -uint16_t checksum(void* data, size_t len) noexcept; + // Compute the internet checksum for the buffer / buffer part provided + uint16_t checksum(void* data, size_t len) noexcept; -// View a packet differently based on context -template -inline auto view_packet_as(Packet packet) noexcept { - return std::static_pointer_cast(packet); -} + // View a packet differently based on context + template + inline auto view_packet_as(Packet packet) noexcept { + return std::static_pointer_cast(packet); + } } //< namespace net diff --git a/api/net/packet.hpp b/api/net/packet.hpp index 22752ea784..e3c6ffcc24 100644 --- a/api/net/packet.hpp +++ b/api/net/packet.hpp @@ -23,128 +23,128 @@ namespace net { -/** Default buffer release-function. Returns the buffer to Packet's bufferStore **/ -void default_release(BufferStore::buffer_t, size_t); + /** Default buffer release-function. Returns the buffer to Packet's bufferStore **/ + void default_release(BufferStore::buffer_t, size_t); -class Packet : public std::enable_shared_from_this { -public: - static constexpr size_t MTU {1500}; + class Packet : public std::enable_shared_from_this { + public: + static constexpr size_t MTU {1500}; - using release_del = BufferStore::release_del; + using release_del = BufferStore::release_del; - /** - * Construct, using existing buffer. - * - * @param buf: The buffer to use as the packet - * @param bufsize: Size of the buffer - * @param datalen: Length of data in the buffer - * - * @WARNING: There are two adjacent parameters of the same type, violating CG I.24. - */ - Packet(BufferStore::buffer_t buf, size_t bufsize, size_t datalen, release_del d = default_release) noexcept; + /** + * Construct, using existing buffer. + * + * @param buf: The buffer to use as the packet + * @param bufsize: Size of the buffer + * @param datalen: Length of data in the buffer + * + * @WARNING: There are two adjacent parameters of the same type, violating CG I.24. + */ + Packet(BufferStore::buffer_t buf, size_t bufsize, size_t datalen, release_del d = default_release) noexcept; - /** Destruct. */ - virtual ~Packet(); + /** Destruct. */ + virtual ~Packet(); - /** Get the buffer */ - BufferStore::buffer_t buffer() const noexcept - { return buf_; } + /** Get the buffer */ + BufferStore::buffer_t buffer() const noexcept + { return buf_; } - /** Get the network packet length - i.e. the number of populated bytes */ - inline uint32_t size() const noexcept - { return size_; } + /** Get the network packet length - i.e. the number of populated bytes */ + inline uint32_t size() const noexcept + { return size_; } - /** Get the size of the buffer. This is >= len(), usually MTU-size */ - inline uint32_t capacity() const noexcept - { return capacity_; } + /** Get the size of the buffer. This is >= len(), usually MTU-size */ + inline uint32_t capacity() const noexcept + { return capacity_; } - int set_size(const size_t) noexcept; + int set_size(const size_t) noexcept; - /** Set next-hop ip4. */ - void next_hop(IP4::addr ip) noexcept; + /** Set next-hop ip4. */ + void next_hop(IP4::addr ip) noexcept; - /** Get next-hop ip4. */ - IP4::addr next_hop() const noexcept; + /** Get next-hop ip4. */ + IP4::addr next_hop() const noexcept; - /** - * Add a packet to this packet chain. - * - * @Warning: Let's hope this recursion won't smash the stack - */ - void chain(Packet_ptr p) noexcept { - if (!chain_) chain_ = p; - else chain_->chain(p); - } + /** + * Add a packet to this packet chain. + * + * @Warning: Let's hope this recursion won't smash the stack + */ + void chain(Packet_ptr p) noexcept { + if (!chain_) chain_ = p; + else chain_->chain(p); + } - /** - * Get the next packet in the chain. - * - * @Todo: Make chain iterators (i.e. begin / end) */ - Packet_ptr unchain() noexcept - { return chain_; } + /** + * Get the next packet in the chain. + * + * @Todo: Make chain iterators (i.e. begin / end) */ + Packet_ptr unchain() noexcept + { return chain_; } - /** Get the the total number of packets in the chain */ - size_t chain_length() const noexcept { - if (!chain_) { - return 1; - } + /** Get the the total number of packets in the chain */ + size_t chain_length() const noexcept { + if (!chain_) { + return 1; + } - return 1 + chain_->chain_length(); - } + return 1 + chain_->chain_length(); + } - /** - * For a UDPv6 packet, the payload location is the start of - * the UDPv6 header, and so on - */ - inline void set_payload(BufferStore::buffer_t location) noexcept - { payload_ = location; } + /** + * For a UDPv6 packet, the payload location is the start of + * the UDPv6 header, and so on + */ + inline void set_payload(BufferStore::buffer_t location) noexcept + { payload_ = location; } - /** Get the payload of the packet */ - inline BufferStore::buffer_t payload() const noexcept - { return payload_; } + /** Get the payload of the packet */ + inline BufferStore::buffer_t payload() const noexcept + { return payload_; } - /** - * Upcast back to normal packet - * - * Unfortunately, we can't upcast with std::static_pointer_cast - * however, all classes derived from Packet should be good to use - */ - static Packet_ptr packet(Packet_ptr pckt) noexcept - { return *static_cast(&pckt); } + /** + * Upcast back to normal packet + * + * Unfortunately, we can't upcast with std::static_pointer_cast + * however, all classes derived from Packet should be good to use + */ + static Packet_ptr packet(Packet_ptr pckt) noexcept + { return *static_cast(&pckt); } - /** @Todo: Avoid Protected Data. (Jedi Council CG, C.133) **/ -protected: - BufferStore::buffer_t payload_ {nullptr}; - BufferStore::buffer_t buf_ {nullptr}; - size_t capacity_ {MTU}; // NOTE: Actual value is provided by BufferStore - size_t size_ {0}; - IP4::addr next_hop4_ {}; -private: - /** Send the buffer back home, after destruction */ - release_del release_; + /** @Todo: Avoid Protected Data. (Jedi Council CG, C.133) **/ + protected: + BufferStore::buffer_t payload_ {nullptr}; + BufferStore::buffer_t buf_ {nullptr}; + size_t capacity_ {MTU}; // NOTE: Actual value is provided by BufferStore + size_t size_ {0}; + IP4::addr next_hop4_ {}; + private: + /** Send the buffer back home, after destruction */ + release_del release_; - /** Let's chain packets */ - Packet_ptr chain_ {}; + /** Let's chain packets */ + Packet_ptr chain_ {}; - /** Default constructor Deleted. See Packet(Packet&). */ - Packet() = delete; + /** Default constructor Deleted. See Packet(Packet&). */ + Packet() = delete; - /** - * Delete copy and move because we want Packets and buffers to be 1 to 1 - * - * (Well, we really deleted this to avoid accidental copying) - * - * The idea is to use Packet_ptr (i.e. shared_ptr) for passing packets. - * - * @todo Add an explicit way to copy packets. - */ - Packet(Packet&) = delete; - Packet(Packet&&) = delete; + /** + * Delete copy and move because we want Packets and buffers to be 1 to 1 + * + * (Well, we really deleted this to avoid accidental copying) + * + * The idea is to use Packet_ptr (i.e. shared_ptr) for passing packets. + * + * @todo Add an explicit way to copy packets. + */ + Packet(Packet&) = delete; + Packet(Packet&&) = delete; - /** Delete copy and move assignment operators. See Packet(Packet&). */ - Packet& operator=(Packet) = delete; - Packet operator=(Packet&&) = delete; -}; //< class Packet + /** Delete copy and move assignment operators. See Packet(Packet&). */ + Packet& operator=(Packet) = delete; + Packet operator=(Packet&&) = delete; + }; //< class Packet } //< namespace net #endif diff --git a/src/net/packet.cpp b/src/net/packet.cpp index 391499764d..4e2fbab63e 100644 --- a/src/net/packet.cpp +++ b/src/net/packet.cpp @@ -22,42 +22,42 @@ namespace net { -Packet::Packet(BufferStore::buffer_t buf, size_t bufsize, size_t datalen, release_del rel) noexcept: + Packet::Packet(BufferStore::buffer_t buf, size_t bufsize, size_t datalen, release_del rel) noexcept: buf_ {buf}, - capacity_ {bufsize}, - size_ {datalen}, - next_hop4_ {}, - release_ {rel} + capacity_ {bufsize}, + size_ {datalen}, + next_hop4_ {}, + release_ {rel} { debug(" CONSTRUCT packet, buf @ %p\n", buf); } -Packet::~Packet() { - debug(" DESTRUCT packet, buf @ %p\n", buf_); - release_(buf_, capacity_); -} - -IP4::addr Packet::next_hop() const noexcept { - return next_hop4_; -} + Packet::~Packet() { + debug(" DESTRUCT packet, buf @ %p\n", buf_); + release_(buf_, capacity_); + } -void Packet::next_hop(IP4::addr ip) noexcept { - next_hop4_ = ip; -} + IP4::addr Packet::next_hop() const noexcept { + return next_hop4_; + } -int Packet::set_size(const size_t size) noexcept { - if(size > capacity_) { - return 0; + void Packet::next_hop(IP4::addr ip) noexcept { + next_hop4_ = ip; } - size_ = size; + int Packet::set_size(const size_t size) noexcept { + if(size > capacity_) { + return 0; + } - return size_; -} + size_ = size; -void default_release(BufferStore::buffer_t b, size_t) { - (void) b; - debug(" Ignoring buffer."); -} + return size_; + } + + void default_release(BufferStore::buffer_t b, size_t) { + (void) b; + debug(" Ignoring buffer."); + } } //< namespace net diff --git a/src/virtio/virtio_queue.cpp b/src/virtio/virtio_queue.cpp index ce63009139..b8d12a5492 100644 --- a/src/virtio/virtio_queue.cpp +++ b/src/virtio/virtio_queue.cpp @@ -28,7 +28,7 @@ /** Virtio Queue class, nested inside Virtio. - */ +*/ #define ALIGN(x) (((x) + PAGE_SIZE) & ~PAGE_SIZE) unsigned Virtio::Queue::virtq_size(unsigned int qsz) { @@ -51,7 +51,7 @@ void Virtio::Queue::init_queue(int size, void* buf){ // (This is a formula from sanos - don't know why it works, but it does // align the used queue to the next page border) _queue.used = (virtq_used*)(((uint32_t)&_queue.avail->ring[size] + - sizeof(uint16_t)+PAGESIZE-1) & ~(PAGESIZE -1)); + sizeof(uint16_t)+PAGESIZE-1) & ~(PAGESIZE -1)); debug("\t * Queue used @ 0x%lx \n ",(long)_queue.used); } @@ -78,7 +78,7 @@ Virtio::Queue::Queue(uint16_t size, uint16_t q_index, uint16_t iobase) memset(buffer, 0, _size_bytes); debug(">>> Virtio Queue of size %i (%li bytes) initializing \n", - _size,_size_bytes); + _size,_size_bytes); init_queue(size,buffer); // Chain buffers @@ -103,7 +103,7 @@ int Virtio::Queue::enqueue(scatterlist sg[], uint32_t out, uint32_t in, void* UN _pci_index,num_avail(), _queue.used->idx,_queue.avail->idx ); - panic("Buffer full"); + panic("Buffer full"); } // Remove buffers from the free list @@ -157,24 +157,24 @@ int Virtio::Queue::enqueue(scatterlist sg[], uint32_t out, uint32_t in, void* UN return _num_free; } void Virtio::Queue::enqueue( - void* out, - uint32_t out_len, - void* in, - uint32_t in_len) + void* out, + uint32_t out_len, + void* in, + uint32_t in_len) { int total = (out) ? 1 : 0; total += (in) ? 1 : 0; if (_num_free < total) - { - // Queue is full (we think) - printf("Buffer full (%i avail," \ - " used.idx: %i, avail.idx: %i )\n", - _pci_index, num_avail(), - _queue.used->idx,_queue.avail->idx - ); - panic("Buffer full"); - } + { + // Queue is full (we think) + printf("Buffer full (%i avail," \ + " used.idx: %i, avail.idx: %i )\n", + _pci_index, num_avail(), + _queue.used->idx,_queue.avail->idx + ); + panic("Buffer full"); + } // Remove buffers from the free list _num_free -= total; @@ -185,31 +185,31 @@ void Virtio::Queue::enqueue( // (implicitly) Mark all outbound tokens as device-readable if (out) - { - current().flags = VIRTQ_DESC_F_NEXT; - current().addr = (intptr_t) out; - current().len = out_len; + { + current().flags = VIRTQ_DESC_F_NEXT; + current().addr = (intptr_t) out; + current().len = out_len; - debug(" Enqueueing outbound: index %u len %li, next %i\n", - _pci_index, head, current().len, current().next); + debug(" Enqueueing outbound: index %u len %li, next %i\n", + _pci_index, head, current().len, current().next); - last = ¤t(); - // go to next - go_next(); - } + last = ¤t(); + // go to next + go_next(); + } // Mark all inbound tokens as device-writable if (in) - { - debug(" Enqueuing inbound \n"); - current().flags = VIRTQ_DESC_F_NEXT | VIRTQ_DESC_F_WRITE; - current().addr = (intptr_t) in; - current().len = in_len; + { + debug(" Enqueuing inbound \n"); + current().flags = VIRTQ_DESC_F_NEXT | VIRTQ_DESC_F_WRITE; + current().addr = (intptr_t) in; + current().len = in_len; - last = ¤t(); - // go to next - go_next(); - } + last = ¤t(); + // go to next + go_next(); + } // No continue on last buffer last->flags &= ~VIRTQ_DESC_F_NEXT; @@ -223,10 +223,10 @@ void* Virtio::Queue::dequeue(uint32_t& len) { // Return NULL if there are no more completed buffers in the queue if (_last_used_idx == _queue.used->idx) - { - debug(" Can't dequeue - no used buffers \n",_pci_index); - return nullptr; - } + { + debug(" Can't dequeue - no used buffers \n",_pci_index); + return nullptr; + } // Get next completed buffer auto& e = _queue.used->ring[_last_used_idx % _size]; @@ -252,10 +252,10 @@ void Virtio::Queue::release(uint32_t head) //...possibly with a tail while (_queue.desc[i].flags & VIRTQ_DESC_F_NEXT) - { - i = _queue.desc[i].next; - _num_free++; - } + { + i = _queue.desc[i].next; + _num_free++; + } // Add buffers back to free list _queue.desc[i].next = _free_head; diff --git a/src/virtio/virtionet.cpp b/src/virtio/virtionet.cpp index dacbce937f..800c7319cb 100644 --- a/src/virtio/virtionet.cpp +++ b/src/virtio/virtionet.cpp @@ -57,11 +57,11 @@ VirtioNet::VirtioNet(hw::PCI_Device& d) | (1 << VIRTIO_NET_F_STATUS); //| (1 << VIRTIO_NET_F_MRG_RXBUF); //Merge RX Buffers (Everything i 1 buffer) uint32_t wanted_features = needed_features; /*; - | (1 << VIRTIO_NET_F_CSUM) - | (1 << VIRTIO_F_ANY_LAYOUT) - | (1 << VIRTIO_NET_F_CTRL_VQ) - | (1 << VIRTIO_NET_F_GUEST_ANNOUNCE) - | (1 << VIRTIO_NET_F_CTRL_MAC_ADDR);*/ + | (1 << VIRTIO_NET_F_CSUM) + | (1 << VIRTIO_F_ANY_LAYOUT) + | (1 << VIRTIO_NET_F_CTRL_VQ) + | (1 << VIRTIO_NET_F_GUEST_ANNOUNCE) + | (1 << VIRTIO_NET_F_CTRL_MAC_ADDR);*/ negotiate_features(wanted_features); @@ -79,10 +79,10 @@ VirtioNet::VirtioNet(hw::PCI_Device& d) "Guest handles packets w. partial checksum"); CHECK(features() & (1 << VIRTIO_NET_F_CTRL_VQ), - "There's a control queue"); + "There's a control queue"); CHECK(features() & (1 << VIRTIO_F_ANY_LAYOUT), - "Queue can handle any header/data layout"); + "Queue can handle any header/data layout"); CHECK(features() & (1 << VIRTIO_F_RING_INDIRECT_DESC), "We can use indirect descriptors"); @@ -221,7 +221,7 @@ void VirtioNet::irq_handler(){ void VirtioNet::service_RX(){ debug2(" %i new packets, %i available tokens \n", - rx_q.new_incoming(),rx_q.num_avail()); + rx_q.new_incoming(),rx_q.num_avail()); /** For RX, we dequeue, add new buffers and let receiver is responsible for @@ -270,7 +270,7 @@ void VirtioNet::service_RX(){ void VirtioNet::service_TX(){ debug2(" %i transmitted, %i waiting packets\n", - tx_q.new_incoming(),tx_q.num_avail()); + tx_q.new_incoming(),tx_q.num_avail()); uint32_t len = 0; int i = 0; From 352572981d09de8b93a284dce50d5fd39c34b02c Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sat, 19 Mar 2016 22:13:32 +0100 Subject: [PATCH 051/311] Progress on transmit buffering + buffer available event --- api/hw/nic.hpp | 20 +++-- api/net/inet_common.hpp | 39 ++++----- api/net/packet.hpp | 81 ++++++++++--------- api/virtio/virtionet.hpp | 155 +++++++++++++++++++----------------- src/net/ethernet.cpp | 30 +++---- src/net/packet.cpp | 56 ++++++------- src/virtio/virtio_queue.cpp | 118 +++++++++++++-------------- src/virtio/virtionet.cpp | 146 +++++++++++++++++++++------------ 8 files changed, 358 insertions(+), 287 deletions(-) diff --git a/api/hw/nic.hpp b/api/hw/nic.hpp index e2788d91fd..986357fcda 100644 --- a/api/hw/nic.hpp +++ b/api/hw/nic.hpp @@ -38,6 +38,7 @@ namespace hw { template class Nic { public: + using driver_t = DRIVER; /** Get a readable name. */ @@ -47,25 +48,28 @@ class Nic { /** The mac address. */ inline const net::Ethernet::addr& mac() { return driver_.mac(); } - + inline void set_linklayer_out(net::upstream del) { driver_.set_linklayer_out(del); } - + inline net::upstream get_linklayer_out() { return driver_.get_linklayer_out(); } - + inline void transmit(net::Packet_ptr pckt) { driver_.transmit(pckt); } - + inline uint16_t MTU() const noexcept { return driver_.MTU(); } - + inline net::BufferStore& bufstore() noexcept { return driver_.bufstore(); } - + + inline void on_buffers_available(net::buf_avail_delg del) + { driver_.on_buffers_available(del); }; + private: driver_t driver_; - + /** * Constructor * @@ -80,7 +84,7 @@ class Nic { /** Future drivers may start out like so, */ class E1000 { -public: +public: inline const char* name() const noexcept { return "E1000 Driver"; } //...whatever the Nic class implicitly needs diff --git a/api/net/inet_common.hpp b/api/net/inet_common.hpp index 723ef02fee..fbc2a81f36 100644 --- a/api/net/inet_common.hpp +++ b/api/net/inet_common.hpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -23,27 +23,30 @@ #include namespace net { -// Packet must be forward declared to avoid circular dependency -// i.e. IP uses Packet, and Packet uses IP headers -class Packet; -class Ethernet; + // Packet must be forward declared to avoid circular dependency + // i.e. IP uses Packet, and Packet uses IP headers + class Packet; + class Ethernet; + + using LinkLayer = Ethernet; -using LinkLayer = Ethernet; + using Packet_ptr = std::shared_ptr; -using Packet_ptr = std::shared_ptr; + // Downstream / upstream delegates + using downstream = delegate; + using upstream = downstream; -// Downstream / upstream delegates -using downstream = delegate; -using upstream = downstream; + // Delegate for signalling available buffers + using buf_avail_delg = delegate; -// Compute the internet checksum for the buffer / buffer part provided -uint16_t checksum(void* data, size_t len) noexcept; + // Compute the internet checksum for the buffer / buffer part provided + uint16_t checksum(void* data, size_t len) noexcept; -// View a packet differently based on context -template -inline auto view_packet_as(Packet packet) noexcept { - return std::static_pointer_cast(packet); -} + // View a packet differently based on context + template + inline auto view_packet_as(Packet packet) noexcept { + return std::static_pointer_cast(packet); + } } //< namespace net diff --git a/api/net/packet.hpp b/api/net/packet.hpp index 22752ea784..ad87f0fd5c 100644 --- a/api/net/packet.hpp +++ b/api/net/packet.hpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,6 +20,7 @@ #include #include +#include namespace net { @@ -29,7 +30,7 @@ void default_release(BufferStore::buffer_t, size_t); class Packet : public std::enable_shared_from_this { public: static constexpr size_t MTU {1500}; - + using release_del = BufferStore::release_del; /** @@ -40,69 +41,72 @@ class Packet : public std::enable_shared_from_this { * @param datalen: Length of data in the buffer * * @WARNING: There are two adjacent parameters of the same type, violating CG I.24. - */ + */ Packet(BufferStore::buffer_t buf, size_t bufsize, size_t datalen, release_del d = default_release) noexcept; - + /** Destruct. */ virtual ~Packet(); - + /** Get the buffer */ BufferStore::buffer_t buffer() const noexcept { return buf_; } - + /** Get the network packet length - i.e. the number of populated bytes */ inline uint32_t size() const noexcept { return size_; } - + /** Get the size of the buffer. This is >= len(), usually MTU-size */ inline uint32_t capacity() const noexcept { return capacity_; } - + int set_size(const size_t) noexcept; - + /** Set next-hop ip4. */ void next_hop(IP4::addr ip) noexcept; - + /** Get next-hop ip4. */ IP4::addr next_hop() const noexcept; - - /** - * Add a packet to this packet chain. - * - * @Warning: Let's hope this recursion won't smash the stack - */ + + /* Add a packet to this packet chain. */ void chain(Packet_ptr p) noexcept { - if (!chain_) chain_ = p; - else chain_->chain(p); + if (!chain_) { + chain_ = p; + last_ = p; + } else { + last_->chain(p); + last_ = p->last_in_chain() ? p->last_in_chain() : p; + assert(last_); + } } - /** - * Get the next packet in the chain. - * - * @Todo: Make chain iterators (i.e. begin / end) */ - Packet_ptr unchain() noexcept + /* Get the last packet in the chain */ + Packet_ptr last_in_chain() noexcept + { return last_; } + + /* Get the tail, i.e. chain minus the first element */ + Packet_ptr tail() noexcept { return chain_; } - - /** Get the the total number of packets in the chain */ - size_t chain_length() const noexcept { - if (!chain_) { - return 1; - } - return 1 + chain_->chain_length(); + /* Get the tail, and detach it from the head (for FIFO) */ + Packet_ptr detach_tail() noexcept + { + auto tail = chain_; + chain_ = 0; + return tail; } - + + /** * For a UDPv6 packet, the payload location is the start of * the UDPv6 header, and so on */ inline void set_payload(BufferStore::buffer_t location) noexcept { payload_ = location; } - + /** Get the payload of the packet */ inline BufferStore::buffer_t payload() const noexcept { return payload_; } - + /** * Upcast back to normal packet * @@ -111,7 +115,7 @@ class Packet : public std::enable_shared_from_this { */ static Packet_ptr packet(Packet_ptr pckt) noexcept { return *static_cast(&pckt); } - + /** @Todo: Avoid Protected Data. (Jedi Council CG, C.133) **/ protected: BufferStore::buffer_t payload_ {nullptr}; @@ -122,9 +126,10 @@ class Packet : public std::enable_shared_from_this { private: /** Send the buffer back home, after destruction */ release_del release_; - + /** Let's chain packets */ - Packet_ptr chain_ {}; + Packet_ptr chain_ {0}; + Packet_ptr last_ {0}; /** Default constructor Deleted. See Packet(Packet&). */ Packet() = delete; @@ -144,7 +149,7 @@ class Packet : public std::enable_shared_from_this { /** Delete copy and move assignment operators. See Packet(Packet&). */ Packet& operator=(Packet) = delete; Packet operator=(Packet&&) = delete; -}; //< class Packet +}; //< class Packet } //< namespace net #endif diff --git a/api/virtio/virtionet.hpp b/api/virtio/virtionet.hpp index 4025822ee5..a1ae685d58 100644 --- a/api/virtio/virtionet.hpp +++ b/api/virtio/virtionet.hpp @@ -6,29 +6,29 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -/** - @note This virtionet implementation was very much inspired by - SanOS, (C) Michael Ringgaard. All due respect. - - STANDARD: - - We're aiming for standard compliance: - - Virtio 1.0, OASIS Committee Specification Draft 01 - (http://docs.oasis-open.org/virtio/virtio/v1.0/csd01/virtio-v1.0-csd01.pdf) - - In the following abbreviated to Virtio 1.01 - - ...Alas, nobody's using it yet, so we're stuck with "legacy" for now. +/** + @note This virtionet implementation was very much inspired by + SanOS, (C) Michael Ringgaard. All due respect. + + STANDARD: + + We're aiming for standard compliance: + + Virtio 1.0, OASIS Committee Specification Draft 01 + (http://docs.oasis-open.org/virtio/virtio/v1.0/csd01/virtio-v1.0-csd01.pdf) + + In the following abbreviated to Virtio 1.01 + + ...Alas, nobody's using it yet, so we're stuck with "legacy" for now. */ #ifndef VIRTIO_VIRTIONET_HPP #define VIRTIO_VIRTIONET_HPP @@ -42,7 +42,7 @@ /** Virtio Net Features. From Virtio Std. 5.1.3 */ -/* Device handles packets with partial checksum. This “checksum offload” +/* Device handles packets with partial checksum. This “checksum offload” is a common feature on modern network cards.*/ #define VIRTIO_NET_F_CSUM 0 @@ -110,7 +110,41 @@ /** Virtio-net device driver. */ class VirtioNet : Virtio { - + +public: + + /** Human readable name. */ + const char* name(); + + /** Mac address. */ + const net::Ethernet::addr& mac(); + + constexpr uint16_t MTU() const { + return 1500 + sizeof(virtio_net_hdr); } + + /** Delegate linklayer output. Hooks into IP-stack bottom, w.UPSTREAM data. */ + inline void set_linklayer_out(net::upstream link_out){ + _link_out = link_out; + //rx_q.set_data_handler(link_out); + }; + + inline net::upstream get_linklayer_out() + { return _link_out; } + + inline net::BufferStore& bufstore() { return bufstore_; } + + /** Linklayer input. Hooks into IP-stack bottom, w.DOWNSTREAM data.*/ + void transmit(net::Packet_ptr pckt); + + /** Constructor. @param pcidev an initialized PCI device. */ + VirtioNet(hw::PCI_Device& pcidev); + + + inline void on_buffers_available(net::buf_avail_delg del) + { buffer_available_event_ = del; }; + +private: + struct virtio_net_hdr { uint8_t flags; @@ -121,7 +155,7 @@ class VirtioNet : Virtio { uint16_t csum_offset; // Offset after that to place checksum }__attribute__((packed)); - /** Virtio std. § 5.1.6.1: + /** Virtio std. § 5.1.6.1: "The legacy driver only presented num_buffers in the struct virtio_net_hdr when VIRTIO_NET_F_MRG_RXBUF was not negotiated; without that feature the structure was 2 bytes shorter." */ struct virtio_net_hdr_nomerge { @@ -134,90 +168,65 @@ class VirtioNet : Virtio { uint16_t num_buffers; }__attribute__((packed)); - - /** An empty header. + + /** An empty header. It's ok to use as long as we don't need checksum offloading or other 'fancier' virtio features. */ - constexpr static virtio_net_hdr empty_header = {0,0,0,0,0,0}; - + constexpr static virtio_net_hdr empty_header = {0,0,0,0,0,0}; + Virtio::Queue rx_q; Virtio::Queue tx_q; Virtio::Queue ctrl_q; // Moved to Nic - // Ethernet eth; + // Ethernet eth; // Arp arp; // From Virtio 1.01, 5.1.4 struct config{ net::Ethernet::addr mac; uint16_t status; - + //Only valid if VIRTIO_NET_F_MQ - uint16_t max_virtq_pairs = 0; + uint16_t max_virtq_pairs = 0; }_conf; - + //sizeof(config) if VIRTIO_NET_F_MQ, else sizeof(config) - sizeof(uint16_t) int _config_length = sizeof(config); - + /** Get virtio PCI config. @see Virtio::get_config.*/ void get_config(); - - - /** Service the RX Queue. - Push incoming data up to linklayer, dequeue RX buffers. */ - void service_RX(); - - /** Service the TX Queue - Dequeue used TX buffers. @note: This function does not take any - responsibility for memory management. */ - void service_TX(); - - /** Handle device IRQ. - - Will look for config. changes and service RX/TX queues as necessary.*/ + + + /** Service the RX/TX Queues. + Push incoming data up to linklayer, dequeue any used RX- and TX buffers.*/ + void service_queues(); + + /** Add packet to buffer chain */ + void add_to_tx_buffer(net::Packet_ptr pckt); + + /** Add packet chain to virtio queue */ + void enqueue(net::Packet_ptr pckt); + + /** Handle device IRQ. + Will look for config changes and service RX/TX queues as necessary.*/ void irq_handler(); - + /** Allocate and queue buffer from bufstore_ in RX queue. */ - int add_receive_buffer(); + int add_receive_buffer(); /** Upstream delegate for linklayer output */ net::upstream _link_out; /** 20-bit / 1MB of buffers to start with */ net::BufferStore bufstore_{ 0xfffffU / MTU(), MTU(), sizeof(virtio_net_hdr) }; - net::BufferStore::release_del release_buffer = + net::BufferStore::release_del release_buffer = net::BufferStore::release_del::from (bufstore_); - -public: - - /** Human readable name. */ - const char* name(); - - /** Mac address. */ - const net::Ethernet::addr& mac(); - - constexpr uint16_t MTU() const { - return 1500 + sizeof(virtio_net_hdr); } - - /** Delegate linklayer output. Hooks into IP-stack bottom, w.UPSTREAM data. */ - inline void set_linklayer_out(net::upstream link_out){ - _link_out = link_out; - //rx_q.set_data_handler(link_out); - }; - inline net::upstream get_linklayer_out() - { return _link_out; } - - inline net::BufferStore& bufstore() { return bufstore_; } - - /** Linklayer input. Hooks into IP-stack bottom, w.DOWNSTREAM data.*/ - void transmit(net::Packet_ptr pckt); - - /** Constructor. @param pcidev an initialized PCI device. */ - VirtioNet(hw::PCI_Device& pcidev); - + net::buf_avail_delg buffer_available_event_ {}; + + net::Packet_ptr transmit_queue_ {0}; }; diff --git a/src/net/ethernet.cpp b/src/net/ethernet.cpp index 1a690fe46f..42dc4aaf28 100644 --- a/src/net/ethernet.cpp +++ b/src/net/ethernet.cpp @@ -6,17 +6,17 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -#define DEBUG // Allow debugging -#define DEBUG2 +//#define DEBUG // Allow debugging +//#define DEBUG2 #include #include @@ -55,29 +55,29 @@ void Ethernet::transmit(Packet_ptr pckt) { // Verify ethernet header assert(hdr->dest.major != 0 || hdr->dest.minor !=0); assert(hdr->type != 0); - + // Add source address hdr->src = mac_; - + debug2(" Transmitting %i b, from %s -> %s. Type: %i\n", pckt->size(), mac_.str().c_str(), hdr->dest.str().c_str(), hdr->type); - + physical_out_(pckt); } void Ethernet::bottom(Packet_ptr pckt) { assert(pckt->size() > 0); - + header* eth = reinterpret_cast(pckt->buffer()); - + /** Do we pass on ethernet headers? As for now, yes. data += sizeof(header); len -= sizeof(header); - */ + */ debug2(" %s => %s , Eth.type: 0x%x ", eth->src.str().c_str(), eth->dest.str().c_str(), eth->type); - - switch(eth->type) { + + switch(eth->type) { case ETH_IP4: debug2("IPv4 packet\n"); ip4_handler_(pckt); @@ -87,12 +87,12 @@ void Ethernet::bottom(Packet_ptr pckt) { debug2("IPv6 packet\n"); ip6_handler_(pckt); break; - + case ETH_ARP: debug2("ARP packet\n"); arp_handler_(pckt); break; - + case ETH_WOL: debug2("Wake-on-LAN packet\n"); break; @@ -100,7 +100,7 @@ void Ethernet::bottom(Packet_ptr pckt) { case ETH_VLAN: debug("VLAN tagged frame (not yet supported)"); break; - + default: // This might be 802.3 LLC traffic if (net::ntohs(eth->type) > 1500) { diff --git a/src/net/packet.cpp b/src/net/packet.cpp index 391499764d..1e08826afd 100644 --- a/src/net/packet.cpp +++ b/src/net/packet.cpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -22,42 +22,44 @@ namespace net { -Packet::Packet(BufferStore::buffer_t buf, size_t bufsize, size_t datalen, release_del rel) noexcept: + Packet::Packet(BufferStore::buffer_t buf, size_t bufsize, size_t datalen, release_del rel) noexcept: buf_ {buf}, - capacity_ {bufsize}, - size_ {datalen}, - next_hop4_ {}, - release_ {rel} + capacity_ {bufsize}, + size_ {datalen}, + next_hop4_ {}, + release_ {rel} { debug(" CONSTRUCT packet, buf @ %p\n", buf); } -Packet::~Packet() { - debug(" DESTRUCT packet, buf @ %p\n", buf_); - release_(buf_, capacity_); -} + Packet::~Packet() { + debug(" DESTRUCT packet, buf @ %p\n", buf_); + release_(buf_, capacity_); + } -IP4::addr Packet::next_hop() const noexcept { - return next_hop4_; -} + IP4::addr Packet::next_hop() const noexcept { + return next_hop4_; + } -void Packet::next_hop(IP4::addr ip) noexcept { - next_hop4_ = ip; -} + void Packet::next_hop(IP4::addr ip) noexcept { + next_hop4_ = ip; + } + + int Packet::set_size(const size_t size) noexcept { + if(size > capacity_) { + return 0; + } + + size_ = size; -int Packet::set_size(const size_t size) noexcept { - if(size > capacity_) { - return 0; + return size_; } - size_ = size; + void default_release(BufferStore::buffer_t b, size_t) { + (void) b; + debug(" Ignoring buffer."); + } - return size_; -} -void default_release(BufferStore::buffer_t b, size_t) { - (void) b; - debug(" Ignoring buffer."); -} } //< namespace net diff --git a/src/virtio/virtio_queue.cpp b/src/virtio/virtio_queue.cpp index ce63009139..8d08daa57c 100644 --- a/src/virtio/virtio_queue.cpp +++ b/src/virtio/virtio_queue.cpp @@ -6,17 +6,17 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -#define DEBUG // Allow debug -#define DEBUG2 +//#define DEBUG // Allow debug +//#define DEBUG2 #include #include @@ -26,14 +26,14 @@ #include -/** +/** Virtio Queue class, nested inside Virtio. */ -#define ALIGN(x) (((x) + PAGE_SIZE) & ~PAGE_SIZE) -unsigned Virtio::Queue::virtq_size(unsigned int qsz) -{ - return ALIGN(sizeof(virtq_desc)*qsz + sizeof(u16)*(3 + qsz)) - + ALIGN(sizeof(u16)*3 + sizeof(virtq_used_elem)*qsz); +#define ALIGN(x) (((x) + PAGE_SIZE) & ~PAGE_SIZE) +unsigned Virtio::Queue::virtq_size(unsigned int qsz) +{ + return ALIGN(sizeof(virtq_desc)*qsz + sizeof(u16)*(3 + qsz)) + + ALIGN(sizeof(u16)*3 + sizeof(virtq_used_elem)*qsz); } @@ -44,23 +44,23 @@ void Virtio::Queue::init_queue(int size, void* buf){ debug("\t * Queue desc @ 0x%lx \n ",(long)_queue.desc); // The available buffer starts right after the queue descriptors - _queue.avail = (virtq_avail*)((char*)buf + size*sizeof(virtq_desc)); + _queue.avail = (virtq_avail*)((char*)buf + size*sizeof(virtq_desc)); debug("\t * Queue avail @ 0x%lx \n ",(long)_queue.avail); // The used queue starts at the beginning of the next page // (This is a formula from sanos - don't know why it works, but it does - // align the used queue to the next page border) + // align the used queue to the next page border) _queue.used = (virtq_used*)(((uint32_t)&_queue.avail->ring[size] + sizeof(uint16_t)+PAGESIZE-1) & ~(PAGESIZE -1)); debug("\t * Queue used @ 0x%lx \n ",(long)_queue.used); - + } -/** A default handler doing nothing. - - It's here because we might not want to look at the data, e.g. for +/** A default handler doing nothing. + + It's here because we might not want to look at the data, e.g. for the VirtioNet TX-queue which will get used buffers in. */ int empty_handler(uint8_t* UNUSED(data),int UNUSED(size)) { debug(" Empty handler. DROP! "); @@ -75,27 +75,27 @@ Virtio::Queue::Queue(uint16_t size, uint16_t q_index, uint16_t iobase) { // Allocate page-aligned size and clear it void* buffer = memalign(PAGE_SIZE, _size_bytes); - memset(buffer, 0, _size_bytes); - + memset(buffer, 0, _size_bytes); + debug(">>> Virtio Queue of size %i (%li bytes) initializing \n", _size,_size_bytes); init_queue(size,buffer); - - // Chain buffers - debug("\t * Chaining buffers \n"); + + // Chain buffers + debug("\t * Chaining buffers \n"); for (int i=0; i> Virtio Queue setup complete. \n"); } /** Ported more or less directly from SanOS. */ int Virtio::Queue::enqueue(scatterlist sg[], uint32_t out, uint32_t in, void* UNUSED(data)){ - + uint16_t i,avail,head, prev = _free_head; - - + + while (_num_free < out + in){ // Queue is full (we think) //while( num_avail() >= _size) // Wait for Virtio printf("Buffer full (%i avail," \ @@ -106,13 +106,13 @@ int Virtio::Queue::enqueue(scatterlist sg[], uint32_t out, uint32_t in, void* UN panic("Buffer full"); } - // Remove buffers from the free list + // Remove buffers from the free list _num_free -= out + in; head = _free_head; - - + + // (implicitly) Mark all outbound tokens as device-readable - for (i = _free_head; out; i = _queue.desc[i].next, out--) + for (i = _free_head; out; i = _queue.desc[i].next, out--) { _queue.desc[i].flags = VIRTQ_DESC_F_NEXT; _queue.desc[i].addr = (uint64_t)sg->data; @@ -124,9 +124,9 @@ int Virtio::Queue::enqueue(scatterlist sg[], uint32_t out, uint32_t in, void* UN prev = i; sg++; } - + // Mark all inbound tokens as device-writable - for (; in; i = _queue.desc[i].next, in--) + for (; in; i = _queue.desc[i].next, in--) { debug(" Enqueuing inbound \n"); _queue.desc[i].flags = VIRTQ_DESC_F_NEXT | VIRTQ_DESC_F_WRITE; @@ -135,11 +135,11 @@ int Virtio::Queue::enqueue(scatterlist sg[], uint32_t out, uint32_t in, void* UN prev = i; sg++; } - + // No continue on last buffer _queue.desc[prev].flags &= ~VIRTQ_DESC_F_NEXT; - - + + // Update free pointer _free_head = i; @@ -150,21 +150,21 @@ int Virtio::Queue::enqueue(scatterlist sg[], uint32_t out, uint32_t in, void* UN avail = (_queue.avail->idx + _num_added++) % _size; _queue.avail->ring[avail] = head; debug(" avail: %i \n",_pci_index,avail); - + // Notify about free buffers //if (_num_free > 0) set_event(&vq->bufavail); - - return _num_free; + + return _num_free; } void Virtio::Queue::enqueue( - void* out, - uint32_t out_len, - void* in, + void* out, + uint32_t out_len, + void* in, uint32_t in_len) { int total = (out) ? 1 : 0; total += (in) ? 1 : 0; - + if (_num_free < total) { // Queue is full (we think) @@ -175,29 +175,29 @@ void Virtio::Queue::enqueue( ); panic("Buffer full"); } - - // Remove buffers from the free list + + // Remove buffers from the free list _num_free -= total; // remember current head for later uint16_t head = _free_head; // the last buffer in queue virtq_desc* last = nullptr; - + // (implicitly) Mark all outbound tokens as device-readable if (out) { current().flags = VIRTQ_DESC_F_NEXT; current().addr = (intptr_t) out; current().len = out_len; - + debug(" Enqueueing outbound: index %u len %li, next %i\n", _pci_index, head, current().len, current().next); - + last = ¤t(); // go to next go_next(); } - + // Mark all inbound tokens as device-writable if (in) { @@ -205,15 +205,15 @@ void Virtio::Queue::enqueue( current().flags = VIRTQ_DESC_F_NEXT | VIRTQ_DESC_F_WRITE; current().addr = (intptr_t) in; current().len = in_len; - + last = ¤t(); // go to next go_next(); } - + // No continue on last buffer last->flags &= ~VIRTQ_DESC_F_NEXT; - + // SanOS: Put entry in available array, but do not update avail->idx until sync uint16_t avail = (_queue.avail->idx + _num_added++) % _size; _queue.avail->ring[avail] = head; @@ -234,11 +234,11 @@ void* Virtio::Queue::dequeue(uint32_t& len) debug2(" Releasing token %li. Len: %li\n",_pci_index, e.id, e.len); void* data = (void*) _queue.desc[e.id].addr; len = e.len; - + // Release buffer release(e.id); _last_used_idx++; - + return data; } @@ -246,21 +246,21 @@ void Virtio::Queue::release(uint32_t head) { // Mark queue element "head" as free (the whole token chain) uint32_t i = head; - + //It's at least one token... _num_free++; //...possibly with a tail - while (_queue.desc[i].flags & VIRTQ_DESC_F_NEXT) + while (_queue.desc[i].flags & VIRTQ_DESC_F_NEXT) { i = _queue.desc[i].next; _num_free++; } - + // Add buffers back to free list _queue.desc[i].next = _free_head; _free_head = head; - + // What happens here? debug2(" desc[%i].next : %i \n",_pci_index,i,_queue.desc[i].next); } @@ -279,7 +279,7 @@ uint8_t* Virtio::Queue::dequeue(uint32_t* len){ debug2(" Releasing token %li. Len: %li\n",_pci_index,e->id, e->len); uint8_t* data = (uint8_t*)_queue.desc[e->id].addr; - + // Release buffer release(e->id); _last_used_idx++; @@ -303,12 +303,12 @@ void Virtio::Queue::kick(){ //__sync_synchronize (); // Atomically increment (maybe not necessary?) - //__sync_add_and_fetch(&(_queue.avail->idx),_num_added); + //__sync_add_and_fetch(&(_queue.avail->idx),_num_added); _queue.avail->idx += _num_added; //__sync_synchronize (); _num_added = 0; - + if (!(_queue.used->flags & VIRTQ_USED_F_NO_NOTIFY)){ debug(" Kicking virtio. Iobase 0x%x \n", diff --git a/src/virtio/virtionet.cpp b/src/virtio/virtionet.cpp index dacbce937f..7b26fcf242 100644 --- a/src/virtio/virtionet.cpp +++ b/src/virtio/virtionet.cpp @@ -16,7 +16,7 @@ // limitations under the License. #define PRINT_INFO -//#define DEBUG // Allow debuging +#define DEBUG // Allow debuging //#define DEBUG2 #include @@ -57,38 +57,38 @@ VirtioNet::VirtioNet(hw::PCI_Device& d) | (1 << VIRTIO_NET_F_STATUS); //| (1 << VIRTIO_NET_F_MRG_RXBUF); //Merge RX Buffers (Everything i 1 buffer) uint32_t wanted_features = needed_features; /*; - | (1 << VIRTIO_NET_F_CSUM) - | (1 << VIRTIO_F_ANY_LAYOUT) - | (1 << VIRTIO_NET_F_CTRL_VQ) - | (1 << VIRTIO_NET_F_GUEST_ANNOUNCE) - | (1 << VIRTIO_NET_F_CTRL_MAC_ADDR);*/ + | (1 << VIRTIO_NET_F_CSUM) + | (1 << VIRTIO_F_ANY_LAYOUT) + | (1 << VIRTIO_NET_F_CTRL_VQ) + | (1 << VIRTIO_NET_F_GUEST_ANNOUNCE) + | (1 << VIRTIO_NET_F_CTRL_MAC_ADDR);*/ negotiate_features(wanted_features); CHECK ((features() & needed_features) == needed_features, - "Negotiated needed features"); + "Negotiated needed features"); CHECK ((features() & wanted_features) == wanted_features, - "Negotiated wanted features"); + "Negotiated wanted features"); CHECK(features() & (1 << VIRTIO_NET_F_CSUM), - "Device handles packets w. partial checksum"); + "Device handles packets w. partial checksum"); CHECK(features() & (1 << VIRTIO_NET_F_GUEST_CSUM), - "Guest handles packets w. partial checksum"); + "Guest handles packets w. partial checksum"); CHECK(features() & (1 << VIRTIO_NET_F_CTRL_VQ), - "There's a control queue"); + "There's a control queue"); CHECK(features() & (1 << VIRTIO_F_ANY_LAYOUT), - "Queue can handle any header/data layout"); + "Queue can handle any header/data layout"); CHECK(features() & (1 << VIRTIO_F_RING_INDIRECT_DESC), - "We can use indirect descriptors"); + "We can use indirect descriptors"); CHECK(features() & (1 << VIRTIO_F_RING_EVENT_IDX), - "There's a Ring Event Index to use"); + "There's a Ring Event Index to use"); CHECK(features() & (1 << VIRTIO_NET_F_MQ), "There are multiple queue pairs"); @@ -97,23 +97,23 @@ VirtioNet::VirtioNet(hw::PCI_Device& d) printf("\t\t* max_virtqueue_pairs: 0x%x \n",_conf.max_virtq_pairs); CHECK(features() & (1 << VIRTIO_NET_F_MRG_RXBUF), - "Merge RX buffers"); + "Merge RX buffers"); // Step 1 - Initialize RX/TX queues auto success = assign_queue(0, (uint32_t)rx_q.queue_desc()); CHECK(success, "RX queue assigned (0x%x) to device", - (uint32_t)rx_q.queue_desc()); + (uint32_t)rx_q.queue_desc()); success = assign_queue(1, (uint32_t)tx_q.queue_desc()); CHECK(success, "TX queue assigned (0x%x) to device", - (uint32_t)tx_q.queue_desc()); + (uint32_t)tx_q.queue_desc()); // Step 2 - Initialize Ctrl-queue if it exists if (features() & (1 << VIRTIO_NET_F_CTRL_VQ)) { success = assign_queue(2, (uint32_t)tx_q.queue_desc()); CHECK(success, "CTRL queue assigned (0x%x) to device", - (uint32_t)ctrl_q.queue_desc()); + (uint32_t)ctrl_q.queue_desc()); } // Step 3 - Fill receive queue with buffers @@ -137,7 +137,7 @@ VirtioNet::VirtioNet(hw::PCI_Device& d) get_config(); CHECK(_conf.mac.major > 0, "Valid Mac address: %s", - _conf.mac.str().c_str()); + _conf.mac.str().c_str()); // Step 7 - 9 - GSO: @todo Not using GSO features yet. @@ -198,12 +198,9 @@ void VirtioNet::irq_handler(){ if (isr & 1){ // This now means service RX & TX interchangeably - service_RX(); - // We need a zipper-solution; we can't receive n packets before sending // anything - that's unfair. - - //service_TX(); + service_queues(); } // Step 2. B) @@ -219,19 +216,21 @@ void VirtioNet::irq_handler(){ } -void VirtioNet::service_RX(){ +void VirtioNet::service_queues(){ debug2(" %i new packets, %i available tokens \n", - rx_q.new_incoming(),rx_q.num_avail()); + rx_q.new_incoming(),rx_q.num_avail()); /** For RX, we dequeue, add new buffers and let receiver is responsible for memory management (they know when they're done with the packet.) */ - int i = 0; + int dequeued_rx = 0; uint32_t len = 0; uint8_t* data; + int dequeued_tx = 0; rx_q.disable_interrupts(); + tx_q.disable_interrupts(); // A zipper, alternating between sending and receiving while(rx_q.new_incoming() or tx_q.new_incoming()){ @@ -241,49 +240,74 @@ void VirtioNet::service_RX(){ auto pckt_ptr = std::make_shared (data+sizeof(virtio_net_hdr), // Offset buffer (bufstore knows the offset) - MTU()-sizeof(virtio_net_hdr), // Capacity - len - sizeof(virtio_net_hdr), release_buffer); // Size + MTU()-sizeof(virtio_net_hdr), // Capacity + len - sizeof(virtio_net_hdr), release_buffer); // Size _link_out(pckt_ptr); // Requeue a new buffer add_receive_buffer(); - i++; + dequeued_rx++; } debug2(" Service loop about to kick RX if %i \n",i); - if (i) - rx_q.kick(); - // Do one TX-packet if (tx_q.new_incoming()){ tx_q.dequeue(&len); + dequeued_tx++; } - rx_q.enable_interrupts(); } - debug2(" Done servicing queues\n"); -} + // Let virtio know we have increased receive capacity + if (dequeued_rx) + rx_q.kick(); -void VirtioNet::service_TX(){ - debug2(" %i transmitted, %i waiting packets\n", - tx_q.new_incoming(),tx_q.num_avail()); + rx_q.enable_interrupts(); - uint32_t len = 0; - int i = 0; + // If we have a transmit queue, eat from it, otherwise let the stack know we + // have increased transmit capacity + if (dequeued_tx) { + + debug(" Transmitted something, now transmitting any buffer\n"); - /** For TX, just dequeue all incoming tokens. + // transmit as much as possible from the buffer + if (transmit_queue_){ + auto buf = transmit_queue_; + transmit_queue_ = 0; + transmit(buf); + } + + // If we now emptied the buffer, offer packets to stack + if (! transmit_queue_ && tx_q.num_avail() > 1) + buffer_available_event_(tx_q.num_avail() / 2); + + } - Sender allocated the buffer and is responsible for memory management. - @todo Sender doesn't know when the packet is transmitted; deal with it. */ - for (;i < tx_q.new_incoming(); i++) - tx_q.dequeue(&len); + tx_q.enable_interrupts(); + + debug2(" Done servicing queues\n"); +} + +void VirtioNet::add_to_tx_buffer(net::Packet_ptr pckt){ + if (transmit_queue_) + transmit_queue_->chain(pckt); + else + transmit_queue_ = pckt; + +#ifdef DEBUG + size_t chain_length = 1; + Packet_ptr next = transmit_queue_->tail(); + while (next) { + chain_length++; + next = next->tail(); + } +#endif + + debug("Buffering, %i packets chained \n", chain_length); - debug2("\t Dequeued %i packets \n",i); - // Deallocate buffer. } void VirtioNet::transmit(net::Packet_ptr pckt){ @@ -302,6 +326,32 @@ void VirtioNet::transmit(net::Packet_ptr pckt){ support VirtualBox */ + int transmitted = 0; + net::Packet_ptr tail {pckt}; + + // Transmit all we can directly + while (tx_q.num_free() and tail) { + debug("%i tokens left in TX queue \n", tx_q.num_free()); + enqueue(tail); + tail = tail->detach_tail(); + transmitted++; + if (! tail) + break; + + } + + // Notify virtio about new packets + if (transmitted) + tx_q.kick(); + + // Buffer the rest + if (tail) + add_to_tx_buffer(tail); + +} + +void VirtioNet::enqueue(net::Packet_ptr pckt){ + // A scatterlist for virtio-header + data scatterlist sg[2]; @@ -314,6 +364,4 @@ void VirtioNet::transmit(net::Packet_ptr pckt){ // Enqueue scatterlist, 2 pieces readable, 0 writable. tx_q.enqueue(sg, 2, 0, 0); - tx_q.kick(); - } From b73c835fea3de443e84b8cac48a3c0c9a37a5d53 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sat, 19 Mar 2016 22:32:17 +0100 Subject: [PATCH 052/311] Testing transmission buffering + packet available event. WIP --- test/transmit/Makefile | 20 ++++++++++ test/transmit/README.md | 5 +++ test/transmit/run.sh | 3 ++ test/transmit/service.cpp | 78 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 106 insertions(+) create mode 100644 test/transmit/Makefile create mode 100644 test/transmit/README.md create mode 100755 test/transmit/run.sh create mode 100644 test/transmit/service.cpp diff --git a/test/transmit/Makefile b/test/transmit/Makefile new file mode 100644 index 0000000000..1e647c76cb --- /dev/null +++ b/test/transmit/Makefile @@ -0,0 +1,20 @@ +################################################# +# IncludeOS SERVICE makefile # +################################################# + +# The name of your service +SERVICE = test_transmit +SERVICE_NAME = Network transmission tests + +# Your service parts +FILES = service.cpp + +# Your disk image +DISK= + +# IncludeOS location +ifndef INCLUDEOS_INSTALL +INCLUDEOS_INSTALL=$(HOME)/IncludeOS_install +endif + +include $(INCLUDEOS_INSTALL)/Makeseed diff --git a/test/transmit/README.md b/test/transmit/README.md new file mode 100644 index 0000000000..5ad27829e7 --- /dev/null +++ b/test/transmit/README.md @@ -0,0 +1,5 @@ +# Test packet transmission, buffering and transmit-buffers available event + +This test will try to generate and transmit packets as fast as possible, which should now not cause panic, but rather buffering. + +*NOTE: This is a Work In Progress* diff --git a/test/transmit/run.sh b/test/transmit/run.sh new file mode 100755 index 0000000000..3b2132d2cb --- /dev/null +++ b/test/transmit/run.sh @@ -0,0 +1,3 @@ +#! /bin/bash +source ${INCLUDEOS_HOME-$HOME/IncludeOS_install}/etc/run.sh + diff --git a/test/transmit/service.cpp b/test/transmit/service.cpp new file mode 100644 index 0000000000..0109263b40 --- /dev/null +++ b/test/transmit/service.cpp @@ -0,0 +1,78 @@ +// This file is a part of the IncludeOS unikernel - www.includeos.org +// +// Copyright 2015 Oslo and Akershus University College of Applied Sciences +// and Alfred Bratterud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//#define DEBUG // Debug supression + +#include +#include +#include +#include + +using namespace std; +using namespace net; + +std::shared_ptr > inet; + +void Service::start() +{ + // Assign an IP-address, using Hårek-mapping :-) + auto& eth0 = hw::Dev::eth<0,VirtioNet>(); + auto& mac = eth0.mac(); + + inet = std::make_shared>(eth0); + + inet->network_config({{ mac.part[2],mac.part[3],mac.part[4],mac.part[5] }}, + {{ 255,255,0,0 }}, // Netmask + {{ 10,0,0,1 }}, // Gateway + {{ 8,8,8,8}}); // DNS + + printf("Service IP address: %s \n", inet->ip_addr().str().c_str()); + + // UDP + UDP::port_t port = 4242; + auto& sock = inet->udp().bind(port); + + sock.onRead([] (UDP::Socket& conn, UDP::addr_t addr, UDP::port_t port, + const char* data, int len) -> int { + printf("Getting UDP data from %s: %i: %s\n", + addr.str().c_str(), port, data); + // send the same thing right back! + conn.sendto(addr, port, data, len); + return 0; + }); + + eth0.on_buffers_available([](size_t s){ + CHECK(1,"There are now %i available buffers", s); + }); + + + hw::PIT::instance().onTimeout(200ms,[=](){ + const int packets { 600 }; + INFO("TEST", "Trying to transmit %i packets at maximum throttle", packets); + for (int i=0; i < packets; i++){ + auto pckt = inet->createPacket(inet->MTU()); + Ethernet::header* hdr = reinterpret_cast(pckt->buffer()); + hdr->dest.major = Ethernet::addr::BROADCAST_FRAME.major; + hdr->dest.minor = Ethernet::addr::BROADCAST_FRAME.minor; + hdr->type = Ethernet::ETH_ARP; + inet->link().transmit(pckt); + } + + CHECK(1,"Transmission didn't panic"); + + }); +} From 2ad4d9af58582eabf30b41cd3015de8d4419bcca Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sat, 19 Mar 2016 22:36:37 +0100 Subject: [PATCH 053/311] Restore OS class name --- api/kernel/os.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/kernel/os.hpp b/api/kernel/os.hpp index 2cc2c2c79c..7f64e49f4b 100644 --- a/api/kernel/os.hpp +++ b/api/kernel/os.hpp @@ -34,7 +34,7 @@ namespace hw{ class Serial; } * * @note For device access, see Dev */ -class OSCAR WILDE ISN'T A VALID CLASS NAME IS IT? { +class OS { public: using rsprint_func = delegate; From a496fc0c64361065a95da1069c8d8f0a90dabf13 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Mon, 21 Mar 2016 09:03:19 +0100 Subject: [PATCH 054/311] Testing max transmission speed on UDP as well --- test/transmit/service.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/test/transmit/service.cpp b/test/transmit/service.cpp index 0109263b40..a4a7de1fa9 100644 --- a/test/transmit/service.cpp +++ b/test/transmit/service.cpp @@ -48,10 +48,18 @@ void Service::start() sock.onRead([] (UDP::Socket& conn, UDP::addr_t addr, UDP::port_t port, const char* data, int len) -> int { - printf("Getting UDP data from %s: %i: %s\n", - addr.str().c_str(), port, data); + CHECK(1, "Got UDP data from %s: %i: %s", + addr.str().c_str(), port, data); // send the same thing right back! - conn.sendto(addr, port, data, len); + const int packets { 600 }; + + INFO("TEST 2", "Trying to transmit %i packets at maximum throttle", packets); + for (int i = 0; i < packets; i++) + conn.sendto(addr, port, data, len); + + + + return 0; }); @@ -62,7 +70,7 @@ void Service::start() hw::PIT::instance().onTimeout(200ms,[=](){ const int packets { 600 }; - INFO("TEST", "Trying to transmit %i packets at maximum throttle", packets); + INFO("TEST 2", "Trying to transmit %i packets at maximum throttle", packets); for (int i=0; i < packets; i++){ auto pckt = inet->createPacket(inet->MTU()); Ethernet::header* hdr = reinterpret_cast(pckt->buffer()); @@ -74,5 +82,8 @@ void Service::start() CHECK(1,"Transmission didn't panic"); + }); + + } From d95a8e1c922d3b4e8cf9adbf8a4ae9fdf2f6b9f0 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Tue, 29 Mar 2016 11:43:14 +0200 Subject: [PATCH 055/311] fs: Move async calls to fat_async module --- src/Makefile | 2 +- src/fs/fat.cpp | 274 +---------------------------------------- src/fs/fat_async.cpp | 285 +++++++++++++++++++++++++++++++++++++++++++ src/fs/fat_sync.cpp | 13 +- 4 files changed, 289 insertions(+), 285 deletions(-) create mode 100644 src/fs/fat_async.cpp diff --git a/src/Makefile b/src/Makefile index c420b09af6..0dbdba81d8 100644 --- a/src/Makefile +++ b/src/Makefile @@ -74,7 +74,7 @@ OS_OBJECTS = kernel/kernel_start.o kernel/syscalls.o kernel/vga.o \ net/ip6/ip6.o net/ip6/icmp6.o net/ip6/udp6.o net/ip6/ndp.o \ net/packet.o net/buffer_store.o \ fs/disk.o fs/filesystem.o fs/mbr.o fs/vbr.o fs/path.o \ - fs/ext4.o fs/fat.o fs/fat_sync.o fs/memdisk.o + fs/ext4.o fs/fat.o fs/fat_async.o fs/fat_sync.o fs/memdisk.o CRTI_OBJ = crt/crti.o CRTN_OBJ = crt/crtn.o diff --git a/src/fs/fat.cpp b/src/fs/fat.cpp index 0e5d16d1b3..361c5dfc81 100644 --- a/src/fs/fat.cpp +++ b/src/fs/fat.cpp @@ -1,13 +1,11 @@ -#define DEBUG +//#define DEBUG #include -#include #include -#include +#include #include #include -#include #include #include // for panic() @@ -272,272 +270,4 @@ namespace fs return found_last; } - void FAT::int_ls( - uint32_t sector, - dirvec_t dirents, - on_internal_ls_func callback) - { - // list contents of meme sector by sector - typedef std::function next_func_t; - - auto next = std::make_shared (); - *next = - [this, sector, callback, dirents, next] (uint32_t sector) - { - debug("int_ls: sec=%u\n", sector); - device.read(sector, - [this, sector, callback, dirents, next] (buffer_t data) - { - if (!data) - { - // could not read sector - callback(true, dirents); - return; - } - - // parse entries in sector - bool done = int_dirent(sector, data.get(), dirents); - if (done) - { - // execute callback - callback(no_error, dirents); - } - else - { - // go to next sector - (*next)(sector+1); - } - - }); // read root dir - }; - - // start reading sectors asynchronously - (*next)(sector); - } - - void FAT::traverse(std::shared_ptr path, cluster_func callback) - { - // parse this path into a stack of memes - typedef std::function next_func_t; - - // asynch stack traversal - auto next = std::make_shared (); - *next = - [this, path, next, callback] (uint32_t cluster) - { - if (path->empty()) - { - // attempt to read directory - uint32_t S = this->cl_to_sector(cluster); - - // result allocated on heap - auto dirents = std::make_shared> (); - - int_ls(S, dirents, - [callback] (error_t error, dirvec_t ents) - { - callback(error, ents); - }); - return; - } - - // retrieve next name - std::string name = path->front(); - path->pop_front(); - - uint32_t S = this->cl_to_sector(cluster); - debug("Current target: %s on cluster %u (sector %u)\n", name.c_str(), cluster, S); - - // result allocated on heap - auto dirents = std::make_shared> (); - - // list directory contents - int_ls(S, dirents, - [name, dirents, next, callback] (error_t error, dirvec_t ents) - { - if (unlikely(error)) - { - debug("Could not find: %s\n", name.c_str()); - callback(true, dirents); - return; - } - - // look for name in directory - for (auto& e : *ents) - { - if (unlikely(e.name() == name)) - { - // go to this directory, unless its the last name - debug("Found match for %s", name.c_str()); - // enter the matching directory - debug("\t\t cluster: %llu\n", e.block); - // only follow directories - if (e.type() == DIR) - (*next)(e.block); - else - callback(true, dirents); - return; - } - } // for (ents) - - debug("NO MATCH for %s\n", name.c_str()); - callback(true, dirents); - }); - - }; - // start by reading root directory - (*next)(0); - } - - void FAT::ls(const std::string& path, on_ls_func on_ls) - { - // parse this path into a stack of names - auto pstk = std::make_shared (path); - - traverse(pstk, - [on_ls] (error_t error, dirvec_t dirents) - { - on_ls(error, dirents); - }); - } - - void FAT::read(const Dirent& ent, uint64_t pos, uint64_t n, on_read_func callback) - { - auto buf = read(ent, pos, n); - callback(buf.err, buf.buffer, buf.len); - } - - void FAT::readFile(const Dirent& ent, on_read_func callback) - { - // cluster -> sector - uint32_t sector = this->cl_to_sector(ent.block); - // number of sectors to read ahead - size_t chunks = ent.size / sector_size + 1; - // allocate buffer - auto* buffer = new uint8_t[chunks * sector_size]; - // at which sector we will stop - size_t total = chunks; - size_t current = 0; - - typedef std::function next_func_t; - auto next = std::make_shared (); - - *next = - [this, buffer, ent, callback, next] (uint32_t sector, size_t current, size_t total) - { - if (unlikely(current == total)) - { - // report back to HQ - debug("DONE SIZE: %lu (current=%lu, total=%lu)\n", - ent.size, current, total); - // create shared buffer - auto buffer_ptr = buffer_t(buffer, std::default_delete()); - // notify caller - callback(no_error, buffer_ptr, ent.size); - return; - } - device.read(sector, - [this, current, total, buffer, ent, &callback, sector, next] (buffer_t data) - { - if (!data) - { - // general I/O error occurred - debug("Failed to read sector %u for read()", sector); - // cleanup - delete[] buffer; - callback(true, buffer_t(), 0); - return; - } - - // copy over data - memcpy(buffer + current * sector_size, data.get(), sector_size); - // continue reading next sector - (*next)(sector+1, current+1, total); - }); - }; - - // start! - (*next)(sector, current, total); - } - - void FAT::readFile(const std::string& strpath, on_read_func callback) - { - auto path = std::make_shared (strpath); - if (unlikely(path->empty())) - { - // there is no possible file to read where path is empty - callback(true, nullptr, 0); - return; - } - debug("readFile: %s\n", path->back().c_str()); - - std::string filename = path->back(); - path->pop_back(); - - traverse(path, - [this, filename, &callback] (error_t error, dirvec_t dirents) - { - if (unlikely(error)) - { - // no path, no file! - callback(error, nullptr, 0); - return; - } - - // find the matching filename in directory - for (auto& e : *dirents) - { - if (unlikely(e.name() == filename)) - { - // read this file - readFile(e, callback); - return; - } - } - }); - } // readFile() - - void FAT::stat(const std::string& strpath, on_stat_func func) - { - auto path = std::make_shared (strpath); - if (unlikely(path->empty())) - { - // root doesn't have any stat anyways - // Note: could use ATTR_VOLUME_ID in FAT - func(true, Dirent(INVALID_ENTITY, strpath)); - return; - } - - debug("stat: %s\n", path->back().c_str()); - // extract file we are looking for - std::string filename = path->back(); - path->pop_back(); - // we need to remember this later - auto callback = std::make_shared (func); - - traverse(path, - [this, filename, callback] (error_t error, dirvec_t dirents) - { - if (unlikely(error)) - { - // no path, no file! - (*callback)(error, Dirent(INVALID_ENTITY, filename)); - return; - } - - // find the matching filename in directory - for (auto& e : *dirents) - { - if (unlikely(e.name() == filename)) - { - // read this file - (*callback)(no_error, e); - return; - } - } - - // not found - (*callback)(true, Dirent(INVALID_ENTITY, filename)); - }); - } } diff --git a/src/fs/fat_async.cpp b/src/fs/fat_async.cpp new file mode 100644 index 0000000000..292ab99b5f --- /dev/null +++ b/src/fs/fat_async.cpp @@ -0,0 +1,285 @@ +//#define DEBUG +#include + +#include +#include +#include + +#include +#include +#include + +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) + +namespace fs +{ + void FAT::int_ls( + uint32_t sector, + dirvec_t dirents, + on_internal_ls_func callback) + { + // list contents of meme sector by sector + typedef std::function next_func_t; + + auto next = std::make_shared (); + *next = + [this, sector, callback, dirents, next] (uint32_t sector) + { + debug("int_ls: sec=%u\n", sector); + device.read(sector, + [this, sector, callback, dirents, next] (buffer_t data) + { + if (!data) + { + // could not read sector + callback(true, dirents); + return; + } + + // parse entries in sector + bool done = int_dirent(sector, data.get(), dirents); + if (done) + { + // execute callback + callback(no_error, dirents); + } + else + { + // go to next sector + (*next)(sector+1); + } + + }); // read root dir + }; + + // start reading sectors asynchronously + (*next)(sector); + } + + void FAT::traverse(std::shared_ptr path, cluster_func callback) + { + // parse this path into a stack of memes + typedef std::function next_func_t; + + // asynch stack traversal + auto next = std::make_shared (); + *next = + [this, path, next, callback] (uint32_t cluster) + { + if (path->empty()) + { + // attempt to read directory + uint32_t S = this->cl_to_sector(cluster); + + // result allocated on heap + auto dirents = std::make_shared> (); + + int_ls(S, dirents, + [callback] (error_t error, dirvec_t ents) + { + callback(error, ents); + }); + return; + } + + // retrieve next name + std::string name = path->front(); + path->pop_front(); + + uint32_t S = this->cl_to_sector(cluster); + debug("Current target: %s on cluster %u (sector %u)\n", name.c_str(), cluster, S); + + // result allocated on heap + auto dirents = std::make_shared> (); + + // list directory contents + int_ls(S, dirents, + [name, dirents, next, callback] (error_t error, dirvec_t ents) + { + if (unlikely(error)) + { + debug("Could not find: %s\n", name.c_str()); + callback(true, dirents); + return; + } + + // look for name in directory + for (auto& e : *ents) + { + if (unlikely(e.name() == name)) + { + // go to this directory, unless its the last name + debug("Found match for %s", name.c_str()); + // enter the matching directory + debug("\t\t cluster: %llu\n", e.block); + // only follow directories + if (e.type() == DIR) + (*next)(e.block); + else + callback(true, dirents); + return; + } + } // for (ents) + + debug("NO MATCH for %s\n", name.c_str()); + callback(true, dirents); + }); + + }; + // start by reading root directory + (*next)(0); + } + + void FAT::ls(const std::string& path, on_ls_func on_ls) + { + // parse this path into a stack of names + auto pstk = std::make_shared (path); + + traverse(pstk, + [on_ls] (error_t error, dirvec_t dirents) + { + on_ls(error, dirents); + }); + } + + void FAT::read(const Dirent& ent, uint64_t pos, uint64_t n, on_read_func callback) + { + auto buf = read(ent, pos, n); + callback(buf.err, buf.buffer, buf.len); + } + + void FAT::readFile(const Dirent& ent, on_read_func callback) + { + // cluster -> sector + uint32_t sector = this->cl_to_sector(ent.block); + // number of sectors to read ahead + size_t chunks = ent.size / sector_size + 1; + // allocate buffer + auto* buffer = new uint8_t[chunks * sector_size]; + // at which sector we will stop + size_t total = chunks; + size_t current = 0; + + typedef std::function next_func_t; + auto next = std::make_shared (); + + *next = + [this, buffer, ent, callback, next] (uint32_t sector, size_t current, size_t total) + { + if (unlikely(current == total)) + { + // report back to HQ + debug("DONE SIZE: %lu (current=%lu, total=%lu)\n", + ent.size, current, total); + // create shared buffer + auto buffer_ptr = buffer_t(buffer, std::default_delete()); + // notify caller + callback(no_error, buffer_ptr, ent.size); + return; + } + device.read(sector, + [this, current, total, buffer, ent, &callback, sector, next] (buffer_t data) + { + if (!data) + { + // general I/O error occurred + debug("Failed to read sector %u for read()", sector); + // cleanup + delete[] buffer; + callback(true, buffer_t(), 0); + return; + } + + // copy over data + memcpy(buffer + current * sector_size, data.get(), sector_size); + // continue reading next sector + (*next)(sector+1, current+1, total); + }); + }; + + // start! + (*next)(sector, current, total); + } + + void FAT::readFile(const std::string& strpath, on_read_func callback) + { + auto path = std::make_shared (strpath); + if (unlikely(path->empty())) + { + // there is no possible file to read where path is empty + callback(true, nullptr, 0); + return; + } + debug("readFile: %s\n", path->back().c_str()); + + std::string filename = path->back(); + path->pop_back(); + + traverse(path, + [this, filename, &callback] (error_t error, dirvec_t dirents) + { + if (unlikely(error)) + { + // no path, no file! + callback(error, nullptr, 0); + return; + } + + // find the matching filename in directory + for (auto& e : *dirents) + { + if (unlikely(e.name() == filename)) + { + // read this file + readFile(e, callback); + return; + } + } + }); + } // readFile() + + void FAT::stat(const std::string& strpath, on_stat_func func) + { + auto path = std::make_shared (strpath); + if (unlikely(path->empty())) + { + // root doesn't have any stat anyways + // Note: could use ATTR_VOLUME_ID in FAT + func(true, Dirent(INVALID_ENTITY, strpath)); + return; + } + + debug("stat: %s\n", path->back().c_str()); + // extract file we are looking for + std::string filename = path->back(); + path->pop_back(); + // we need to remember this later + auto callback = std::make_shared (func); + + traverse(path, + [this, filename, callback] (error_t error, dirvec_t dirents) + { + if (unlikely(error)) + { + // no path, no file! + (*callback)(error, Dirent(INVALID_ENTITY, filename)); + return; + } + + // find the matching filename in directory + for (auto& e : *dirents) + { + if (unlikely(e.name() == filename)) + { + // read this file + (*callback)(no_error, e); + return; + } + } + + // not found + (*callback)(true, Dirent(INVALID_ENTITY, filename)); + }); + } +} diff --git a/src/fs/fat_sync.cpp b/src/fs/fat_sync.cpp index 25c7286ae5..0d60c7e4ee 100644 --- a/src/fs/fat_sync.cpp +++ b/src/fs/fat_sync.cpp @@ -1,28 +1,17 @@ -#define DEBUG +//#define DEBUG #include #include -#include #include #include #include #include #include -#include // for panic() - -#include #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) -inline std::string trim_right_copy( - const std::string& s, - const std::string& delimiters = " \f\n\r\t\v" ) -{ - return s.substr( 0, s.find_last_not_of( delimiters ) + 1 ); -} - namespace fs { typedef FileSystem::Buffer Buffer; From 7d8f55c06d2d43d49a50c01cb3878bf375d3c25e Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 29 Mar 2016 13:14:07 +0200 Subject: [PATCH 056/311] Outgoing packet buffering in virtionet --- api/virtio/virtio.hpp | 220 +++++++++++++++++++-------------------- src/virtio/virtionet.cpp | 37 ++++--- 2 files changed, 133 insertions(+), 124 deletions(-) diff --git a/api/virtio/virtio.hpp b/api/virtio/virtio.hpp index 1d4fd0ba40..4ec99d0cd1 100644 --- a/api/virtio/virtio.hpp +++ b/api/virtio/virtio.hpp @@ -6,27 +6,27 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -/** - @note This virtio implementation was very much inspired by +/** + @note This virtio implementation was very much inspired by SanOS, (C) Michael Ringgaard. All due respect. - + STANDARD: - + We're aiming to become standards compilant according to this one: - + Virtio 1.0, OASIS Committee Specification Draft 03 (http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.html) - - In the following abbreviated to Virtio 1.03 or Virtio std. + + In the following abbreviated to Virtio 1.03 or Virtio std. */ #pragma once #ifndef VIRTIO_VIRTIO_HPP @@ -61,7 +61,7 @@ #define VIRTIO_CONFIG_S_DRIVER_OK 4 #define VIRTIO_CONFIG_S_FAILED 0x80 -/** A simple scatter-gather list used for Queue::enqueue. +/** A simple scatter-gather list used for Queue::enqueue. ( From sanos, virtio.h - probably Linux originally) */ struct scatterlist { @@ -72,7 +72,7 @@ struct scatterlist { //#include class Virtio { -public: +public: // http://docs.oasis-open.org/virtio/virtio/v1.0/csprd01/virtio-v1.0-csprd01.html#x1-860005 // Virtio device types enum virtiotype_t @@ -91,7 +91,7 @@ class Virtio RP_SERIAL, CAIF }; - + /** Virtio Queue class. */ class Queue { @@ -102,83 +102,83 @@ class Virtio typedef uint16_t u16; typedef uint8_t u8; - + /** Virtio Ring Descriptor. Virtio std. §2.4.5 */ - struct virtq_desc { - /* Address (guest-physical). */ - le64 addr; - /* Length. */ - le32 len; - - /* This marks a buffer as continuing via the next field. */ + struct virtq_desc { + /* Address (guest-physical). */ + le64 addr; + /* Length. */ + le32 len; + + /* This marks a buffer as continuing via the next field. */ #define VIRTQ_DESC_F_NEXT 1 - /* This marks a buffer as device write-only (otherwise device read-only). */ + /* This marks a buffer as device write-only (otherwise device read-only). */ #define VIRTQ_DESC_F_WRITE 2 - /* This means the buffer contains a list of buffer descriptors. */ + /* This means the buffer contains a list of buffer descriptors. */ #define VIRTQ_DESC_F_INDIRECT 4 - /* The flags as indicated above. */ - le16 flags; - /* Next field if flags & NEXT */ - le16 next; + /* The flags as indicated above. */ + le16 flags; + /* Next field if flags & NEXT */ + le16 next; }; - - + + /** Virtio Available ring. Virtio std. §2.4.6 */ - struct virtq_avail { -#define VIRTQ_AVAIL_F_NO_INTERRUPT 1 - le16 flags; - le16 idx; - le16 ring[/* Queue Size */]; - /*le16 used_event; Only if VIRTIO_F_EVENT_IDX */ + struct virtq_avail { +#define VIRTQ_AVAIL_F_NO_INTERRUPT 1 + le16 flags; + le16 idx; + le16 ring[/* Queue Size */]; + /*le16 used_event; Only if VIRTIO_F_EVENT_IDX */ }; - - + + /** Virtio Used ring elements. Virtio std. §2.4.8 */ - struct virtq_used_elem { - /* le32 is used here for ids for padding reasons. */ - /* Index of start of used descriptor chain. */ - le32 id; - /* Total length of the descriptor chain which was used (written to) */ - le32 len; + struct virtq_used_elem { + /* le32 is used here for ids for padding reasons. */ + /* Index of start of used descriptor chain. */ + le32 id; + /* Total length of the descriptor chain which was used (written to) */ + le32 len; }; - + /** Virtio Used ring. Virtio std. §2.4.8 */ - struct virtq_used { -#define VIRTQ_USED_F_NO_NOTIFY 1 - le16 flags; - le16 idx; - struct virtq_used_elem ring[ /* Queue Size */]; - /*le16 avail_event; Only if VIRTIO_F_EVENT_IDX */ - }; - - + struct virtq_used { +#define VIRTQ_USED_F_NO_NOTIFY 1 + le16 flags; + le16 idx; + struct virtq_used_elem ring[ /* Queue Size */]; + /*le16 avail_event; Only if VIRTIO_F_EVENT_IDX */ + }; + + /** Virtqueue. Virtio std. §2.4.2 */ - struct virtq { - // The actual descriptors (16 bytes each) - virtq_desc* desc;// [ /* Queue Size*/ ]; - - // A ring of available descriptor heads with free-running index. - virtq_avail* avail; - - // Padding to the next PAGE_SIZE boundary. - u8* pad; //[ /* Padding */ ]; - - // A ring of used descriptor heads with free-running index. - virtq_used* used; + struct virtq { + // The actual descriptors (16 bytes each) + virtq_desc* desc;// [ /* Queue Size*/ ]; + + // A ring of available descriptor heads with free-running index. + virtq_avail* avail; + + // Padding to the next PAGE_SIZE boundary. + u8* pad; //[ /* Padding */ ]; + + // A ring of used descriptor heads with free-running index. + virtq_used* used; }; - + /** Virtque size calculation. Virtio std. §2.4.2 */ static inline unsigned virtq_size(unsigned int qsz); - + // The size as read from the PCI device uint16_t _size; - + // Actual size in bytes - virtq_size(size) - uint32_t _size_bytes; - + uint32_t _size_bytes; + // The actual queue struct virtq _queue; - + uint16_t _iobase = 0; // Device PCI location uint16_t _num_free = 0; // Number of free descriptors uint16_t _free_head = 0; // First available descriptor @@ -186,47 +186,47 @@ class Virtio uint16_t _last_used_idx = 0; // Last entry inserted by device uint16_t _pci_index = 0; // Queue nr. //void **_data; - - + + /** Handler for data coming in on virtq.used. */ delegate _data_handler; - + /** Initialize the queue buffer */ void init_queue(int size, void* buf); public: /** Kick hypervisor. - + Will notify the host (Qemu/Virtualbox etc.) about pending data */ void kick(); /** Constructor. @param size shuld be fetched from PCI device. */ Queue(uint16_t size, uint16_t q_index, uint16_t iobase); - + /** Get the queue descriptor. To be written to the Virtio device. */ virtq_desc* queue_desc() const { return _queue.desc; } - - /** Push data tokens onto the queue. + + /** Push data tokens onto the queue. @param sg : A scatterlist of tokens @param out : The number of outbound tokens (device-readable - TX) @param in : The number of tokens to be inbound (device-writable RX) */ int enqueue(scatterlist sg[], uint32_t out, uint32_t in, void*); - + void enqueue(void* out, uint32_t out_len, void* in, uint32_t in_len); void* dequeue(uint32_t& len); - + /** Dequeue a received packet. From SanOS */ uint8_t* dequeue(uint32_t* len); - + void disable_interrupts(); void enable_interrupts(); - + void set_data_handler(delegate dataHandler); - + /** Release token. @param head : the token ID to release*/ void release(uint32_t head); - + /** Get number of free tokens in Queue */ inline uint16_t num_free(){ return _num_free; } @@ -234,9 +234,10 @@ class Virtio inline uint16_t new_incoming() { return _queue.used->idx - _last_used_idx; } + /** Get number of used buffers */ inline uint16_t num_avail() { return _queue.avail->idx - _queue.used->idx; } - + // access the current index virtq_desc& current() { @@ -246,65 +247,65 @@ class Virtio { return _queue.desc[ _queue.desc[_free_head].next ]; } - + // go to next index void go_next() { _free_head = _queue.desc[_free_head].next; } - + inline uint16_t size(){ return _size; } - + }; - + /** Get the Virtio config registers from the PCI device. - + @note it varies how these are structured, hence a void* buf */ void get_config(void* buf, int len); - + /** Get the (saved) device IRQ */ inline uint8_t irq(){ return _irq; }; /** Reset the virtio device */ void reset(); - + /** Negotiate supported features with host */ void negotiate_features(uint32_t features); - + /** Register interrupt handler & enable IRQ */ //void enable_irq_handler(IRQ_handler::irq_delegate d); void enable_irq_handler(); /** Probe PCI device for features */ uint32_t probe_features(); - + /** Get locally stored features */ inline uint32_t features(){ return _features; }; - + /** Get iobase. Wrapper around PCI_Device::iobase */ inline uint32_t iobase(){ return _iobase; } /** Get queue size. @param index - the Virtio queue index */ - uint32_t queue_size(uint16_t index); - + uint32_t queue_size(uint16_t index); + /** Assign a queue descriptor to a PCI queue index */ bool assign_queue(uint16_t index, uint32_t queue_desc); - + /** Tell Virtio device if we're OK or not. Virtio Std. § 3.1.1,step 8*/ void setup_complete(bool ok); - /** Indicate which Virtio version (PCI revision ID) is supported. - + /** Indicate which Virtio version (PCI revision ID) is supported. + Currently only Legacy is supported (partially the 1.0 standard) */ static inline bool version_supported(uint16_t i) { return i <= 0; } - - /** Virtio device constructor. - - Should conform to Virtio std. §3.1.1, steps 1-6 + + /** Virtio device constructor. + + Should conform to Virtio std. §3.1.1, steps 1-6 (Step 7 is "Device specific" which a subclass will handle) */ Virtio(hw::PCI_Device& pci); @@ -312,25 +313,24 @@ class Virtio private: //PCI memer as reference (so no indirection overhead) hw::PCI_Device& _pcidev; - + //We'll get this from PCI_device::iobase(), but that lookup takes longer - uint32_t _iobase = 0; - + uint32_t _iobase = 0; + uint8_t _irq = 0; uint32_t _features = 0; uint16_t _virtio_device_id = 0; - + // Indicate if virtio device ID is legacy or standard bool _LEGACY_ID = 0; bool _STD_ID = 0; - + void set_irq(); //TEST int calls = 0; - + void default_irq_handler(); }; #endif - diff --git a/src/virtio/virtionet.cpp b/src/virtio/virtionet.cpp index 13f47f0a88..9dc8d27074 100644 --- a/src/virtio/virtionet.cpp +++ b/src/virtio/virtionet.cpp @@ -17,7 +17,7 @@ #define PRINT_INFO #define DEBUG // Allow debuging -//#define DEBUG2 +#define DEBUG2 #include #include @@ -167,7 +167,7 @@ int VirtioNet::add_receive_buffer(){ // Virtio Std. § 5.1.6.3 auto buf = bufstore_.get_raw_buffer(); - debug2(" Added receive-bufer @ 0x%lx \n", (uint32_t)buf); + debug2(" Added receive-bufer @ 0x%x \n", (uint32_t)buf); hdr = (virtio_net_hdr*)buf; @@ -240,7 +240,7 @@ void VirtioNet::service_queues(){ data = rx_q.dequeue(&len); //BUG # 102? + sizeof(virtio_net_hdr); auto pckt_ptr = std::make_shared - (data+sizeof(virtio_net_hdr), // Offset buffer (bufstore knows the offset) + (data+sizeof(virtio_net_hdr), // Offset buffer (bufstore knows the offseto) MTU()-sizeof(virtio_net_hdr), // Capacity len - sizeof(virtio_net_hdr), release_buffer); // Size @@ -252,45 +252,50 @@ void VirtioNet::service_queues(){ dequeued_rx++; } - debug2(" Service loop about to kick RX if %i \n",i); // Do one TX-packet if (tx_q.new_incoming()){ + debug2(" Dequeing TX"); tx_q.dequeue(&len); dequeued_tx++; } } + debug2(" Service loop about to kick RX if %i \n", + dequeued_rx); // Let virtio know we have increased receive capacity if (dequeued_rx) rx_q.kick(); rx_q.enable_interrupts(); + tx_q.enable_interrupts(); // If we have a transmit queue, eat from it, otherwise let the stack know we // have increased transmit capacity if (dequeued_tx) { - debug(" Transmitted something, now transmitting any buffer\n"); + debug("%i dequeued, transmitting backlog\n", dequeued_tx); // transmit as much as possible from the buffer if (transmit_queue_){ auto buf = transmit_queue_; transmit_queue_ = 0; transmit(buf); + }else{ + debug(" Transmit queue is empty \n"); } // If we now emptied the buffer, offer packets to stack - if (! transmit_queue_ && tx_q.num_avail() > 1) - buffer_available_event_(tx_q.num_avail() / 2); - + if (!transmit_queue_ && tx_q.num_free() > 1) + buffer_available_event_(tx_q.num_free() / 2); + else + debug(" No event: !transmit q %i, num_avail %i \n", + !transmit_queue_, tx_q.num_free()); } - tx_q.enable_interrupts(); - - debug2(" Done servicing queues\n"); + debug(" Done servicing queues\n"); } void VirtioNet::add_to_tx_buffer(net::Packet_ptr pckt){ @@ -313,7 +318,7 @@ void VirtioNet::add_to_tx_buffer(net::Packet_ptr pckt){ } void VirtioNet::transmit(net::Packet_ptr pckt){ - debug2(" Enqueuing %lib of data. \n",pckt->len()); + debug2(" Enqueuing %ib of data. \n",pckt->size()); /** @note We have to send a virtio header first, then the packet. @@ -343,13 +348,17 @@ void VirtioNet::transmit(net::Packet_ptr pckt){ } // Notify virtio about new packets - if (transmitted) + if (transmitted) { tx_q.kick(); + } // Buffer the rest - if (tail) + if (tail) { add_to_tx_buffer(tail); + debug("Buffering remaining packets \n"); + } + } void VirtioNet::enqueue(net::Packet_ptr pckt){ From 382f0268a4241ff5250f14787da7f2e4a45994b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Tue, 29 Mar 2016 13:36:20 +0200 Subject: [PATCH 057/311] tcp: remade read and write on connection (not fully done) --- api/net/tcp.hpp | 371 ++++++++++++++++++++++-------- api/net/tcp_connection_states.hpp | 125 ++++++---- src/net/tcp.cpp | 64 ++++-- src/net/tcp_connection.cpp | 286 +++++++++++------------ src/net/tcp_connection_states.cpp | 173 +++++++------- 5 files changed, 647 insertions(+), 372 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index d96a7040c4..c51c0ee38d 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -44,6 +44,8 @@ class TCP { */ using Seq = uint32_t; + using buffer_t = std::shared_ptr; + class Packet; using Packet_ptr = std::shared_ptr; @@ -365,44 +367,44 @@ class TCP { /// OFFSET, OPTIONS, DATA /// // Get the raw tcp offset, in quadruples - inline uint8_t offset() const { return (uint8_t)(header().offset_flags.offset_reserved >> 4); } + inline uint8_t offset() const { return (uint8_t)(header().offset_flags.offset_reserved >> 4); } - // Set raw TCP offset in quadruples - inline void set_offset(uint8_t offset) { header().offset_flags.offset_reserved = (offset << 4); } + // Set raw TCP offset in quadruples + inline void set_offset(uint8_t offset) { header().offset_flags.offset_reserved = (offset << 4); } - // The actaul TCP header size (including options). - inline uint8_t header_size() const { return offset() * 4; } + // The actaul TCP header size (including options). + inline uint8_t header_size() const { return offset() * 4; } - // Calculate the full header length, down to linklayer, in bytes - uint8_t all_headers_len() const { return (HEADERS_SIZE - sizeof(TCP::Header)) + header_size(); } + // Calculate the full header length, down to linklayer, in bytes + uint8_t all_headers_len() const { return (HEADERS_SIZE - sizeof(TCP::Header)) + header_size(); } - // Where data starts - inline char* data() { return (char*) (buffer() + all_headers_len()); } + // Where data starts + inline char* data() { return (char*) (buffer() + all_headers_len()); } - inline uint16_t data_length() const { return size() - all_headers_len(); } + inline uint16_t data_length() const { return size() - all_headers_len(); } - inline bool has_data() const { return data_length() > 0; } + inline bool has_data() const { return data_length() > 0; } - inline uint16_t tcp_length() const { return header_size() + data_length(); } + inline uint16_t tcp_length() const { return header_size() + data_length(); } - template - inline void add_option(Args&&... args) { - // to avoid headache, options need to be added BEFORE any data. - assert(!has_data()); - // option address - auto* addr = options()+options_length(); - new (addr) T(args...); - // update offset - set_offset(offset() + round_up( ((T*)addr)->length, 4 )); - set_length(); // update - } + template + inline void add_option(Args&&... args) { + // to avoid headache, options need to be added BEFORE any data. + assert(!has_data()); + // option address + auto* addr = options()+options_length(); + new (addr) T(args...); + // update offset + set_offset(offset() + round_up( ((T*)addr)->length, 4 )); + set_length(); // update + } - inline void clear_options() { - // clear existing options - // move data (if any) (??) - set_offset(5); - set_length(); // update - } + inline void clear_options() { + // clear existing options + // move data (if any) (??) + set_offset(5); + set_length(); // update + } inline uint8_t* options() { return (uint8_t*) header().options; } @@ -534,7 +536,108 @@ class TCP { Transist between many states. */ class Connection : public std::enable_shared_from_this { - public: + friend class TCP; + public: + + /* + Wrapper around a buffer that receives data. + */ + struct ReadBuffer { + buffer_t buffer; + size_t remaining; + size_t offset; + bool push; + + ReadBuffer(buffer_t buf, size_t length, size_t offs = 0) + : buffer(buf), remaining(length-offs), offset(offs), push(false) {} + + inline size_t capacity() const { return remaining + offset; } + + inline bool empty() const { return offset == 0; } + + inline bool full() const { return remaining == 0; } + + inline size_t size() const { return offset; } + + inline uint8_t* begin() const { return buffer.get(); } + + inline uint8_t* pos() const { return buffer.get() + offset; } + + inline uint8_t* end() const { return buffer.get() + capacity(); } + + inline bool advance(size_t length) { + assert(length <= remaining); + offset += length; + remaining -= length; + return length > 0; + } + + inline size_t add(uint8_t* data, size_t n) { + auto written = std::min(n, remaining); + memcpy(pos(), data, written); + return written; + } + + inline void clear() { + memset(begin(), 0, offset); + remaining = capacity(); + offset = 0; + push = false; + } + }; // < Connection::ReadBuffer + + + /* + Wrapper around a buffer that contains data to be written. + */ + struct WriteBuffer { + buffer_t buffer; + size_t remaining; + size_t offset; + bool push; + + WriteBuffer(buffer_t buf, size_t length, bool PSH, size_t offs = 0) + : buffer(buf), remaining(length-offs), offset(offs), push(PSH) {} + + inline size_t length() const { return remaining + offset; } + + inline bool done() const { return remaining == 0; } + + inline uint8_t* begin() const { return buffer.get(); } + + inline uint8_t* pos() const { return buffer.get() + offset; } + + inline uint8_t* end() const { return buffer.get() + length(); } + + inline bool advance(size_t length) { + assert(length <= remaining); + offset += length; + remaining -= length; + return length > 0; + } + }; // < Connection::WriteBuffer + + /* + Callback when a receive buffer receives either push or is full - Supplied on asynchronous read + */ + using OnRead = delegate; + + struct ReadRequest { + ReadBuffer buffer; + OnRead callback; + + ReadRequest(ReadBuffer buf, OnRead cb) : buffer(buf), callback(cb) {} + ReadRequest() : buffer({std::make_shared(1024), 1024}), callback([](auto, auto&, bool){}) {} + }; + //using ReadRequest = std::pair; + + /* + Callback when a write is done - Supplied on asynchronous write, gives the user a callback when the "write job" is complete. + */ + using OnWritten = delegate; + + using WriteRequest = std::pair; + /* Connection identifier */ @@ -570,7 +673,7 @@ class TCP { /* On error - When any of the users request fails. */ - using ErrorCallback = delegate, TCPException)>; + using ErrorCallback = delegate, TCPException)>; /* When a packet is received - Everytime a connection receives an incoming packet. @@ -645,13 +748,13 @@ class TCP { Write to a Connection. SEND */ - virtual size_t send(Connection&, const char* buffer, size_t n, bool push = false); + virtual size_t send(Connection&, WriteBuffer&); /* Read from a Connection. RECEIVE */ - virtual size_t receive(Connection&, char* buffer, size_t n); + virtual void receive(Connection&, ReadBuffer&); /* Close a Connection. @@ -677,6 +780,17 @@ class TCP { */ virtual std::string to_string() const = 0; + /* + + */ + virtual bool is_connected() const { return false; } + + virtual bool is_writable() const { return false; } + + virtual bool is_readable() const { return false; } + + virtual bool is_closing() const { return false; } + protected: /* Helper functions @@ -708,8 +822,8 @@ class TCP { class FinWait1; class FinWait2; class CloseWait; - class LastAck; class Closing; + class LastAck; class TimeWait; /* @@ -787,29 +901,28 @@ class TCP { */ inline void set_remote(Socket remote) { remote_ = remote; } + /* + Read content from remote. + */ + void read(ReadBuffer buffer, OnRead callback); - /* - Read content from remote. - */ - size_t read(char* buffer, size_t n); + inline void read(buffer_t buffer, size_t n, OnRead callback) { + read({buffer, n}, callback); + } - /* - Read n bytes into a string. - Default 1024 bytes. - */ - std::string read(size_t n = 0); + inline void read(size_t n, OnRead callback) { + ReadBuffer buffer = {buffer_t(new uint8_t[n], std::default_delete()), n}; + read(buffer, callback); + } /* Write content to remote. */ - size_t write(const char* buffer, size_t n, bool PUSH = true); + void write(WriteBuffer request, OnWritten callback); - /* - Write a string to the remote. - */ - inline void write(const std::string& content) { - write(content.data(), content.size(), true); - } + inline void write(buffer_t buffer, size_t n, OnWritten callback, bool PUSH = true) { + write({buffer, n, PUSH}, callback); + } /* Open connection. @@ -923,38 +1036,21 @@ class TCP { return {local_port_, remote_}; } - /* - Receive buffer - */ - inline const Buffer& receive_buffer() { - return receive_buffer_; - } /* - Send buffer + State checks. */ - inline const Buffer& send_buffer() { - return send_buffer_; - } - - /* - Receive a TCP Packet. + bool is_listening() const; - @WARNING: Public, for use in TCP::bottom (friend it?) - */ - void receive(TCP::Packet_ptr); + inline bool is_connected() const { return state_->is_connected(); } + inline bool is_writable() const { return state_->is_writable(); } - /* - State checks. - */ - bool is_listening() const; + inline bool is_readable() const { return state_->is_readable(); } - bool is_connected() const; + inline bool is_closing() const { return state_->is_closing(); } - bool is_closing() const; - bool is_writable() const; /* Helper function for state checks. @@ -999,11 +1095,17 @@ class TCP { */ TCB control_block; // 36 B - /* - Buffers - */ - Buffer receive_buffer_; - Buffer send_buffer_; + /* + The given read request + */ + ReadRequest read_request; + + /* + Queue for write requests to process + */ + std::queue write_queue; + + /* When time-wait timer was started. @@ -1052,6 +1154,77 @@ class TCP { // packet->to_string().c_str(), reason.c_str()); }; + + /// READING /// + + /* + Assign the read request (read buffer) + */ + inline void receive(ReadBuffer& buffer) { + read_request.buffer = {buffer}; + } + + /* + Receive data into the current read requests buffer. + */ + size_t receive(const uint8_t* data, size_t n, bool PUSH); + + /* + Copy data into the ReadBuffer + */ + inline size_t receive(ReadBuffer& buf, const uint8_t* data, size_t n) { + auto received = std::min(n, buf.remaining); + memcpy(buf.pos(), data, received); // Can we use move? + return received; + } + + /* + + */ + inline void receive_disconnect() { + //assert(read_request); + assert(!read_request.buffer.empty()); + auto& buf = read_request.buffer; + buf.push = true; + read_request.callback(shared_from_this(), buf, true); + } + + + /// WRITING /// + + /* + Active try to send a buffer by asking the TCP. + */ + inline size_t send(WriteBuffer& buffer) { + return host_.send(shared_from_this(), buffer); + } + + /* + Segmentize buffer into packets until either everything has been written, + or all packets are used up. + */ + size_t send(const char* buffer, size_t remaining, size_t& packets, bool PUSH); + + inline size_t send(WriteBuffer& buffer, size_t& packets) { + return send((char*)buffer.pos(), buffer.remaining, packets, buffer.push); + } + + /* + Process the write queue with the given amount of packets. + Returns true if all the jobs are done (queue is empty) + */ + bool offer(size_t& packets); + + /* + Try to write (some of) queue when connected. + */ + void write_queue_on_connect(); + + /* + Reset queue on disconnect. Clears the queue and notice every requests callback. + */ + void write_queue_reset(); + /* Invoke/signal the diffrent TCP events. */ @@ -1108,11 +1281,6 @@ class TCP { */ bool add_to_receive_buffer(TCP::Packet_ptr packet); - /* - Write to the send buffer. Segmentize into packets. - */ - size_t write_to_send_buffer(const char* buffer, size_t n, bool PUSH = true); - /* Transmit the send buffer. */ @@ -1152,7 +1320,7 @@ class TCP { Time (RTT). */ //std::chrono::milliseconds RTT() const; - std::chrono::milliseconds RTO() const; + std::chrono::milliseconds RTO() const; /* Start the time wait timeout for 2*MSL @@ -1184,6 +1352,11 @@ class TCP { */ void add_option(TCP::Option::Kind, TCP::Packet_ptr); + /* + Receive a TCP Packet. + */ + void segment_arrived(TCP::Packet_ptr); + }; // < class TCP::Connection @@ -1221,6 +1394,11 @@ class TCP { */ void bottom(net::Packet_ptr); + /* + Write data to a connection. + */ + void write(Connection_ptr, std::shared_ptr, size_t, Connection::OnWritten, bool = true); + /* Delegate output to network layer */ @@ -1229,15 +1407,15 @@ class TCP { /* Compute the TCP checksum */ - static uint16_t checksum(const TCP::Packet_ptr); + static uint16_t checksum(const TCP::Packet_ptr); - inline const auto& listeners() { return listeners_; } + inline const auto& listeners() { return listeners_; } - inline const auto& connections() { return connections_; } + inline const auto& connections() { return connections_; } - /* - Number of open ports. - */ + /* + Number of open ports. + */ inline size_t openPorts() { return listeners_.size(); } /* @@ -1292,12 +1470,15 @@ class TCP { private: + IPStack& inet_; std::map listeners_; std::map connections_; downstream _network_layer_out; + std::queue write_queue; + /* Settings */ @@ -1341,6 +1522,16 @@ class TCP { */ void close_connection(TCP::Connection&); + /* + Process the write queue with the given amount of free packets. + */ + void process_write_queue(size_t packets); + + /* + + */ + size_t send(Connection_ptr, Connection::WriteBuffer&); + }; // < class TCP diff --git a/api/net/tcp_connection_states.hpp b/api/net/tcp_connection_states.hpp index 67e314d43d..b3935b7aa8 100644 --- a/api/net/tcp_connection_states.hpp +++ b/api/net/tcp_connection_states.hpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -36,10 +36,10 @@ class Connection::Closed : public State { virtual void open(Connection&, bool active = false) override; - virtual size_t send(Connection&, const char* buffer, size_t n, bool push) override; + virtual size_t send(Connection&, WriteBuffer&) override; /* - PASSIVE: + PASSIVE: <- Do nothing (Start listening). => Listen. @@ -69,7 +69,7 @@ class Connection::Listen : public State { } virtual void open(Connection&, bool active = false) override; - virtual size_t send(Connection&, const char* buffer, size_t n, bool push) override; + virtual size_t send(Connection&, WriteBuffer&) override; virtual void close(Connection&) override; /* @@ -98,7 +98,7 @@ class Connection::SynSent : public State { return instance; } - virtual size_t send(Connection&, const char* buffer, size_t n, bool push) override; + virtual size_t send(Connection&, WriteBuffer&) override; virtual void close(Connection&) override; /* @@ -127,7 +127,7 @@ class Connection::SynReceived : public State { return instance; } - virtual size_t send(Connection&, const char* buffer, size_t n, bool push) override; + virtual size_t send(Connection&, WriteBuffer&) override; virtual void close(Connection&) override; @@ -159,9 +159,9 @@ class Connection::Established : public State { return instance; } - virtual size_t send(Connection&, const char* buffer, size_t n, bool push) override; + virtual size_t send(Connection&, WriteBuffer&) override; - virtual size_t receive(Connection&, char* buffer, size_t n) override; + virtual void receive(Connection&, ReadBuffer&) override; virtual void close(Connection&) override; @@ -173,6 +173,18 @@ class Connection::Established : public State { return "ESTABLISHED"; }; + inline virtual bool is_connected() const override { + return true; + } + + inline virtual bool is_writable() const override { + return true; + } + + inline virtual bool is_readable() const override { + return true; + } + private: inline Established() {}; }; @@ -187,7 +199,7 @@ class Connection::FinWait1 : public State { return instance; } - virtual size_t receive(Connection&, char* buffer, size_t n) override; + virtual void receive(Connection&, ReadBuffer&) override; virtual void close(Connection&) override; @@ -204,6 +216,14 @@ class Connection::FinWait1 : public State { return "FIN-WAIT-1"; }; + inline virtual bool is_readable() const override { + return true; + } + + inline virtual bool is_closing() const override { + return true; + } + private: inline FinWait1() {}; }; @@ -218,19 +238,28 @@ class Connection::FinWait2 : public State { return instance; } - virtual size_t receive(Connection&, char* buffer, size_t n) override; + virtual void receive(Connection&, ReadBuffer&) override; virtual void close(Connection&) override; virtual void abort(Connection&) override; /* - + */ virtual Result handle(Connection&, TCP::Packet_ptr in) override; inline virtual std::string to_string() const override { return "FIN-WAIT-2"; }; + + inline virtual bool is_readable() const override { + return true; + } + + inline virtual bool is_closing() const override { + return true; + } + private: inline FinWait2() {}; }; @@ -245,9 +274,9 @@ class Connection::CloseWait : public State { return instance; } - virtual size_t send(Connection&, const char* buffer, size_t n, bool push) override; + virtual size_t send(Connection&, WriteBuffer&) override; - virtual size_t receive(Connection&, char* buffer, size_t n) override; + virtual void receive(Connection&, ReadBuffer&) override; virtual void close(Connection&) override; @@ -256,7 +285,7 @@ class Connection::CloseWait : public State { -> Nothing I think... <- Send FIN. - + => LastAck */ virtual Result handle(Connection&, TCP::Packet_ptr in) override; @@ -265,58 +294,70 @@ class Connection::CloseWait : public State { return "CLOSE-WAIT"; }; + inline virtual bool is_writable() const override { + return true; + } + private: inline CloseWait() {}; }; /* - LAST-ACK + CLOSING */ -class Connection::LastAck : public State { +class Connection::Closing : public State { public: inline static State& instance() { - static LastAck instance; + static Closing instance; return instance; } /* -> Receive ACK. - <- conn.onClose(); - - => Closed (Tell TCP to remove this connection) + => TimeWait (Guess this isnt needed, just start a Close-timer) */ virtual Result handle(Connection&, TCP::Packet_ptr in) override; inline virtual std::string to_string() const override { - return "LAST-ACK"; + return "CLOSING"; }; + inline virtual bool is_closing() const override { + return true; + } + private: - inline LastAck() {}; + inline Closing() {}; }; /* - CLOSING + LAST-ACK */ -class Connection::Closing : public State { +class Connection::LastAck : public State { public: - inline static State& instance() { - static Closing instance; - return instance; - } - /* - -> Receive ACK. + inline static State& instance() { + static LastAck instance; + return instance; + } + /* + -> Receive ACK. - => TimeWait (Guess this isnt needed, just start a Close-timer) - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + <- conn.onClose(); - inline virtual std::string to_string() const override { - return "CLOSING"; - }; + => Closed (Tell TCP to remove this connection) + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) override; + + inline virtual std::string to_string() const override { + return "LAST-ACK"; + }; + + inline virtual bool is_closing() const override { + return true; + } private: - inline Closing() {}; + inline LastAck() {}; }; /* @@ -329,7 +370,7 @@ class Connection::TimeWait : public State { return instance; } /* - + */ virtual Result handle(Connection&, TCP::Packet_ptr in) override; @@ -337,8 +378,12 @@ class Connection::TimeWait : public State { return "TIME-WAIT"; }; + inline virtual bool is_closing() const override { + return true; + } + private: inline TimeWait() {}; }; -#endif \ No newline at end of file +#endif diff --git a/src/net/tcp.cpp b/src/net/tcp.cpp index adfe3165e5..c141fb74d7 100644 --- a/src/net/tcp.cpp +++ b/src/net/tcp.cpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -23,10 +23,11 @@ using namespace std; using namespace net; -TCP::TCP(IPStack& inet) : +TCP::TCP(IPStack& inet) : inet_(inet), listeners_(), connections_(), + write_queue(), MAX_SEG_LIFETIME(30s) { @@ -36,8 +37,8 @@ TCP::TCP(IPStack& inet) : Note: There is different approaches to how to handle listeners & connections. Need to discuss and decide for the best one. - Best solution(?): - Preallocate a pool with listening connections. + Best solution(?): + Preallocate a pool with listening connections. When threshold is reach, remove/add new ones, similar to TCP window. Current solution: @@ -58,7 +59,7 @@ TCP::Connection& TCP::bind(Port port) { /* Active open a new connection to the given remote. - @WARNING: Callback is added when returned (TCP::connect(...).onSuccess(...)), + @WARNING: Callback is added when returned (TCP::connect(...).onSuccess(...)), and open() is called before callback is added. */ TCP::Connection_ptr TCP::connect(Socket remote) { @@ -105,7 +106,7 @@ uint16_t TCP::checksum(TCP::Packet_ptr packet) { pseudo_hdr.saddr.whole = packet->src().whole; pseudo_hdr.daddr.whole = packet->dst().whole; pseudo_hdr.zero = 0; - pseudo_hdr.proto = IP4::IP4_TCP; + pseudo_hdr.proto = IP4::IP4_TCP; pseudo_hdr.tcp_length = htons(tcp_length); union { @@ -117,7 +118,7 @@ uint16_t TCP::checksum(TCP::Packet_ptr packet) { // Compute sum of pseudo header for (uint16_t* it = (uint16_t*)&pseudo_hdr; it < (uint16_t*)&pseudo_hdr + sizeof(pseudo_hdr)/2; it++) - sum.whole += *it; + sum.whole += *it; // Compute sum sum the actual header and data for (uint16_t* it = (uint16_t*)tcp_hdr; it < (uint16_t*)tcp_hdr + tcp_length/2; it++) @@ -144,9 +145,9 @@ uint16_t TCP::checksum(TCP::Packet_ptr packet) { void TCP::bottom(net::Packet_ptr packet_ptr) { // Translate into a TCP::Packet. This will be used inside the TCP-scope. auto packet = std::static_pointer_cast(packet_ptr); - debug(" TCP Packet received - Source: %s, Destination: %s \n", + debug(" TCP Packet received - Source: %s, Destination: %s \n", packet->source().to_string().c_str(), packet->destination().to_string().c_str()); - + // Do checksum if(checksum(packet)) { debug(" TCP Packet Checksum != 0 \n"); @@ -159,9 +160,9 @@ void TCP::bottom(net::Packet_ptr packet_ptr) { // Connection found if(conn_it != connections_.end()) { debug(" Connection found: %s \n", conn_it->second->to_string().c_str()); - conn_it->second->receive(packet); + conn_it->second->segment_arrived(packet); } - // No connection found + // No connection found else { // Is there a listener? auto listen_conn_it = listeners_.find(packet->dst_port()); @@ -174,8 +175,8 @@ void TCP::bottom(net::Packet_ptr packet_ptr) { // Set remote connection->set_remote(packet->source()); debug(" ... Creating connection: %s \n", connection->to_string().c_str()); - - connection->receive(packet); + + connection->segment_arrived(packet); } // No listener found else { @@ -184,6 +185,30 @@ void TCP::bottom(net::Packet_ptr packet_ptr) { } } +void TCP::process_write_queue(size_t packets) { + // foreach connection who wants to write + while(packets and !write_queue.empty()) { + auto conn = write_queue.front(); + if(conn->offer(packets)) + write_queue.pop(); + } +} + +size_t TCP::send(Connection_ptr conn, Connection::WriteBuffer& buffer) { + size_t written{0}; + + if(write_queue.empty()) { + //auto packets = inet_->free_packets(); + size_t packets = 10; + written = conn->send(buffer, packets); + } + + if(written < buffer.remaining) + write_queue.push(conn); + + return written; +} + /* Show all connections for TCP as a string. @@ -202,22 +227,19 @@ string TCP::status() const { ss << "\nCONNECTIONS:\n" << "Proto\tRecv\tSend\tIn\tOut\tLocal\t\t\tRemote\t\t\tState\n"; for(auto con_it : connections_) { auto& c = *(con_it.second); - ss << "tcp4\t" + ss << "tcp4\t" << " " << "\t" << " " << "\t" << " " << "\t" << " " << "\t" - << c.local().to_string() << "\t\t" << c.remote().to_string() << "\t\t" + << c.local().to_string() << "\t\t" << c.remote().to_string() << "\t\t" << c.state().to_string() << "\n"; } return ss.str(); } -/*TCP::Socket& TCP::add_listener(TCP::Socket&& socket) { - -}*/ TCP::Connection_ptr TCP::add_connection(Port local_port, TCP::Socket remote) { return (connections_.emplace( - Connection::Tuple{ local_port, remote }, + Connection::Tuple{ local_port, remote }, std::make_shared(*this, local_port, remote)) ).first->second; } @@ -238,4 +260,4 @@ void TCP::transmit(TCP::Packet_ptr packet) { packet->set_checksum(TCP::checksum(packet)); //packet->set_checksum(checksum(packet)); _network_layer_out(packet); -} \ No newline at end of file +} diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index c7fc2b70e6..44380281f7 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -30,13 +30,12 @@ using namespace std; */ Connection::Connection(TCP& host, Port local_port, Socket remote) : host_(host), - local_port_(local_port), + local_port_(local_port), remote_(remote), state_(&Connection::Closed::instance()), prev_state_(state_), control_block(), - receive_buffer_(host.buffer_limit()), - send_buffer_(host.buffer_limit()), + read_request(), time_wait_started(0) { @@ -47,119 +46,150 @@ Connection::Connection(TCP& host, Port local_port, Socket remote) : */ Connection::Connection(TCP& host, Port local_port) : host_(host), - local_port_(local_port), + local_port_(local_port), remote_(TCP::Socket()), state_(&Connection::Closed::instance()), prev_state_(state_), control_block(), - receive_buffer_(host.buffer_limit()), - send_buffer_(host.buffer_limit()), + read_request(), time_wait_started(0) { - -} +} -size_t Connection::read(char* buffer, size_t n) { - debug(" Reading %u bytes of data from RCV buffer. Total amount of packets stored: %u\n", - n, receive_buffer_.size()); +void Connection::read(ReadBuffer buffer, OnRead callback) { try { - return state_->receive(*this, buffer, n); - } catch(TCPException err) { - signal_error(err); - return 0; - } + state_->receive(*this, buffer); + read_request.callback = callback; + } + catch (TCPException err) { + callback(shared_from_this(), buffer, false); + } } -std::string Connection::read(size_t n) { - if(n == 0) { - // Read all data. - n = receive_buffer_.data_size(); - } - char buffer[n]; - size_t length = read(&buffer[0], n); - return {buffer, length}; +size_t Connection::receive(const uint8_t* data, size_t n, bool PUSH) { + // should not be called without an read request + assert(read_request.buffer.capacity()); + assert(n); + auto& buf = read_request.buffer; + size_t received{0}; + while(n) { + auto read = receive(buf, data+received, n); + // nothing was read to buffer + if(!buf.advance(read)) { + // buffer should be full + assert(buf.full()); + // signal the user + read_request.callback(shared_from_this(), buf, true); + // reset the buffer + buf.clear(); + } + n -= read; + received += read; + } + // n shouldnt be negative + assert(n == 0); + + // end of data, signal the user + if(PUSH) { + buf.push = PUSH; + read_request.callback(shared_from_this(), buf, true); + // reset the buffer + buf.clear(); + } + + return received; } -size_t Connection::read_from_receive_buffer(char* buffer, size_t n) { - size_t bytes_read = 0; - // Read data to buffer until either whole buffer is emptied, or the user got all the data requested. - while(!receive_buffer_.empty() and bytes_read < n) - { - // Packet in front - auto packet = receive_buffer_.front(); - // Where to begin reading - char* begin = packet->data()+receive_buffer_.data_offset(); - // Read this iteration - size_t total{0}; - // Remaining bytes to read. - size_t remaining = n - bytes_read; - // Trying to read over more than one packet - if( remaining >= (packet->data_length() - receive_buffer_.data_offset()) ) { - debug2(" Remaining >: %u Current p: %u\n", - remaining, packet->data_length() - receive_buffer_.data_offset()); - // Reading whole packet - total = packet->data_length(); - // Removing packet from receive buffer. - receive_buffer_.pop(); - // Next packet will start from beginning. - receive_buffer_.set_data_offset(0); - } - // Reading less than one packet. - else { - debug2(" Remaining <: %u\n", remaining); - total = remaining; - receive_buffer_.set_data_offset(packet->data_length() - remaining); - } - memcpy(buffer+bytes_read, begin, total); - bytes_read += total; - } - return bytes_read; +void Connection::write(WriteBuffer request, OnWritten callback) { + try { + auto written = state_->send(*this, request); + request.advance(written); + + if(!request.remaining) { + callback(shared_from_this(), request, true); + } + else { + write_queue.emplace(request, callback); + } + } + catch(TCPException err) { + callback(shared_from_this(), request, false); + } } -bool Connection::add_to_receive_buffer(TCP::Packet_ptr packet) { - return receive_buffer_.add(packet); +bool Connection::offer(size_t& packets) { + assert(packets); + + while(!write_queue.empty() and packets) { + auto& req = write_queue.front().first; + auto written = send(req, packets); + req.advance(written); + if(!req.remaining) { + write_queue.front().second(shared_from_this(), req, true); + write_queue.pop(); + } + } + assert(packets >= 0); + return write_queue.empty(); } -size_t Connection::write(const char* buffer, size_t n, bool PUSH) { - debug(" Asking to write %u bytes of data to SND buffer. \n", n); - try { - return state_->send(*this, buffer, n, PUSH); - } catch(TCPException err) { - signal_error(err); - return 0; - } + +size_t Connection::send(const char* buffer, size_t remaining, size_t& packet_count, bool PUSH) { + size_t bytes_written{0}; + while(remaining and packet_count) { + // retreive a new packet + auto packet = create_outgoing_packet(); + // reduce the amount of packets available by one + packet_count--; + // add the seq, ack and flag + packet->set_seq(control_block.SND.NXT).set_ack(control_block.RCV.NXT).set_flag(ACK); + // calculate how much the packet can be filled with + auto packet_limit = (uint32_t)MSDS() - packet->header_size(); + // fill the packet with data from the request + size_t written = packet->fill(buffer+bytes_written, std::min(packet_limit, remaining)); + // update local variables + bytes_written += written; + remaining -= written; + + debug2(" Packet Limit: %u - Written: %u - Remaining: %u\n", + packet_limit, written, remaining); + + // If last packet, add PUSH. + if(!remaining and PUSH) + packet->set_flag(PSH); + + // Advance outgoing sequence number (SND.NXT) with the length of the data. + control_block.SND.NXT += packet->data_length(); + transmit(packet); + } + return bytes_written; +} + +void Connection::write_queue_on_connect() { + while(!write_queue.empty()) { + auto& req = write_queue.front().first; + auto written = send(req); + req.advance(written); + if(req.remaining) + return; + write_queue.front().second(shared_from_this(), req, true); + write_queue.pop(); + } } -size_t Connection::write_to_send_buffer(const char* buffer, size_t n, bool PUSH) { - size_t bytes_written{0}; - size_t remaining{n}; - do { - auto packet = create_outgoing_packet(); - packet->set_seq(control_block.SND.NXT).set_ack(control_block.RCV.NXT).set_flag(ACK); - // calculate how much the packet can be filled with - auto packet_limit = (uint32_t)MSDS() - packet->header_size(); - size_t written = packet->fill(buffer + (n-remaining), std::min(packet_limit, remaining)); - bytes_written += written; - remaining -= written; - - debug2(" Packet Limit: %u - Written: %u - Remaining: %u\n", - packet_limit, written, remaining); - - // If last packet, add PUSH. - if(!remaining and PUSH) - packet->set_flag(PSH); - - // Advance outgoing sequence number (SND.NXT) with the length of the data. - control_block.SND.NXT += packet->data_length(); - } while(remaining and !send_buffer_.full()); - - return bytes_written; +void Connection::write_queue_reset() { + while(!write_queue.empty()) { + auto job = write_queue.front(); + job.second(shared_from_this(), job.first, false); + write_queue.pop(); + } } + /* - If ACTIVE: + If ACTIVE: Need a remote Socket. */ void Connection::open(bool active) { @@ -171,7 +201,7 @@ void Connection::open(bool active) { catch (TCPException e) { debug(" Cannot open Connection. \n"); signal_error(e); - } + } } void Connection::close() { @@ -185,6 +215,7 @@ void Connection::close() { } } + string Connection::to_string() const { ostringstream os; os << local().to_string() << "\t" << remote_.to_string() << "\t" << state_->to_string(); @@ -194,13 +225,13 @@ string Connection::to_string() const { /* Where the magic happens. */ -void Connection::receive(TCP::Packet_ptr incoming) { +void Connection::segment_arrived(TCP::Packet_ptr incoming) { signal_packet_received(incoming); if(incoming->has_options()) { try { - parse_options(incoming); + parse_options(incoming); } catch(TCPBadOptionException err) { printf(" %s \n", err.what()); @@ -229,20 +260,8 @@ void Connection::receive(TCP::Packet_ptr incoming) { } } -bool Connection::is_listening() const { - return is_state(Listen::instance()); -} - -bool Connection::is_connected() const { - return is_state(Established::instance()); -} - -bool Connection::is_closing() const { - return (is_state(Closing::instance()) or is_state(LastAck::instance()) or is_state(TimeWait::instance())); -} - -bool Connection::is_writable() const { - return (is_connected() and (!send_buffer_.full())); +bool Connection::is_listening() const { + return is_state(Listen::instance()); } Connection::~Connection() { @@ -254,7 +273,7 @@ Connection::~Connection() { TCP::Packet_ptr Connection::create_outgoing_packet() { auto packet = std::static_pointer_cast((host_.inet_).createPacket(TCP::Packet::HEADERS_SIZE)); - + packet->init(); // Set Source (local == the current connection) packet->set_source(local()); @@ -262,29 +281,14 @@ TCP::Packet_ptr Connection::create_outgoing_packet() { packet->set_destination(remote_); packet->set_win_size(control_block.SND.WND); - + // Set SEQ and ACK - I think this is OK.. packet->set_seq(control_block.SND.NXT).set_ack(control_block.RCV.NXT); debug(" Outgoing packet created: %s \n", packet->to_string().c_str()); - // Will also add the packet to the back of the send queue. - send_buffer_.push(packet); - return packet; } -void Connection::transmit() { - assert(! send_buffer_.empty() ); - - debug(" Transmitting: [ %i ] packets. \n", send_buffer_.size()); - while(! send_buffer_.empty() ) { - auto packet = send_buffer_.front(); - assert(! packet->destination().is_empty()); - transmit(packet); - send_buffer_.pop(); - } -} - void Connection::transmit(TCP::Packet_ptr packet) { debug(" Transmitting: %s \n", packet->to_string().c_str()); host_.transmit(packet); @@ -293,10 +297,8 @@ void Connection::transmit(TCP::Packet_ptr packet) { // add_retransmission(packet); } -TCP::Packet_ptr Connection::outgoing_packet() { - if(send_buffer_.empty()) - create_outgoing_packet(); - return send_buffer_.back(); +inline TCP::Packet_ptr Connection::outgoing_packet() { + return create_outgoing_packet(); } TCP::Seq Connection::generate_iss() { @@ -306,7 +308,7 @@ TCP::Seq Connection::generate_iss() { void Connection::set_state(State& state) { prev_state_ = state_; state_ = &state; - debug(" %s => %s \n", + debug(" %s => %s \n", prev_state_->to_string().c_str(), state_->to_string().c_str()); } @@ -382,15 +384,15 @@ std::string Connection::TCB::to_string() const { void Connection::parse_options(TCP::Packet_ptr packet) { assert(packet->has_options()); - debug(" Parsing options. Offset: %u, Options: %u \n", + debug(" Parsing options. Offset: %u, Options: %u \n", packet->offset(), packet->options_length()); - + auto* opt = packet->options(); - + while((char*)opt < packet->data()) { - + auto* option = (TCP::Option*)opt; - + switch(option->kind) { case Option::END: { @@ -409,7 +411,7 @@ void Connection::parse_options(TCP::Packet_ptr packet) { // unlikely if(!packet->isset(SYN)) throw TCPBadOptionException{Option::MSS, "Non-SYN packet"}; - + auto* opt_mss = (Option::opt_mss*)option; uint16_t mss = ntohs(opt_mss->mss); control_block.SND.MSS = mss; @@ -425,12 +427,12 @@ void Connection::parse_options(TCP::Packet_ptr packet) { } void Connection::add_option(TCP::Option::Kind kind, TCP::Packet_ptr packet) { - + switch(kind) { case Option::MSS: { packet->add_option(host_.MSS()); - debug2(" Packet: %s - MSS: %u\n", + debug2(" Packet: %s - MSS: %u\n", packet->to_string().c_str(), ntohs(*(uint16_t*)(packet->options()+2))); break; } diff --git a/src/net/tcp_connection_states.cpp b/src/net/tcp_connection_states.cpp index 79eadc9e7f..7f2511bff1 100644 --- a/src/net/tcp_connection_states.cpp +++ b/src/net/tcp_connection_states.cpp @@ -123,8 +123,9 @@ bool Connection::State::check_seq(Connection& tcp, TCP::Packet_ptr in) { */ if(!acceptable) { if(!in->isset(RST)) { - tcp.outgoing_packet()->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); - tcp.transmit(); + auto packet = tcp.outgoing_packet(); + packet->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); + tcp.transmit(packet); } tcp.drop(in, "Unacceptable SEQ."); return false; @@ -170,8 +171,9 @@ void Connection::State::unallowed_syn_reset_connection(Connection& tcp, TCP::Pac debug(" Unallowed SYN for STATE: %s, reseting connection.\n", tcp.state().to_string().c_str()); // Not sure if this is the correct way to send a "reset response" - tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); - tcp.transmit(); + auto packet = tcp.outgoing_packet(); + packet->set_seq(in->ack()).set_flag(RST); + tcp.transmit(packet); tcp.signal_disconnect(Disconnect::RESET); } @@ -229,8 +231,9 @@ bool Connection::State::check_ack(Connection& tcp, TCP::Packet_ptr in) { } /* If the ACK acks something not yet sent (SEG.ACK > SND.NXT) then send an ACK, drop the segment, and return. */ else if( in->ack() > tcb.SND.NXT ) { - tcp.outgoing_packet()->set_flag(ACK); - tcp.transmit(); + auto packet = tcp.outgoing_packet(); + packet->set_flag(ACK); + tcp.transmit(packet); tcp.drop(in, "ACK > SND.NXT"); return false; } @@ -285,32 +288,26 @@ void Connection::State::process_segment(Connection& tcp, TCP::Packet_ptr in) { assert(in->has_data()); auto& tcb = tcp.tcb(); - int length = in->data_length(); + auto length = in->data_length(); debug(" Received packet with DATA-LENGTH: %i. Add to receive buffer. \n", length); - if(!tcp.add_to_receive_buffer(in)) { - tcp.signal_error({"Receive buffer is full!"}); // Redo to BufferException? - return; // Don't ACK, sender need to resend. - } + if(tcp.read_request.buffer.capacity()) { + auto received = tcp.receive((uint8_t*)in->data(), in->data_length(), in->isset(PSH)); + assert(received == length); + } tcb.RCV.NXT += length; auto snd_nxt = tcb.SND.NXT; debug2(" Advanced RCV.NXT: %u. SND.NXT = %u \n", tcb.RCV.NXT, snd_nxt); - if(in->isset(PSH)) { - debug(" Packet carries PUSH. Notify user.\n"); - tcp.signal_receive(true); - } else if(tcp.receive_buffer().full()) { - // Buffer is now full - debug(" Receive buffer is full. Notify user. \n"); - tcp.signal_receive(false); - } /* Once the TCP takes responsibility for the data it advances RCV.NXT over the data accepted, and adjusts RCV.WND as apporopriate to the current buffer availability. The total of RCV.NXT and RCV.WND should not be reduced. */ + // TODO: SACK (Selective ACK), or if there is a write queue, don't send ACK. if(tcb.SND.NXT == snd_nxt) { - tcp.outgoing_packet()->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); - tcp.transmit(); + auto packet = tcp.outgoing_packet(); + packet->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); + tcp.transmit(packet); } else { debug2(" SND.NXT > snd_nxt, this packet has already been acknowledged. \n"); } @@ -342,11 +339,11 @@ void Connection::State::process_fin(Connection& tcp, TCP::Packet_ptr in) { tcb.RCV.NXT++; //auto fin = in->data_length(); //tcb.RCV.NXT += fin; - tcp.outgoing_packet()->set_ack(tcb.RCV.NXT).set_flag(ACK); - tcp.transmit(); - if(!tcp.receive_buffer().empty()) { - tcp.signal_receive(true); - } + auto packet = tcp.outgoing_packet(); + packet->set_ack(tcb.RCV.NXT).set_flag(ACK); + tcp.transmit(packet); + // signal the user + tcp.receive_disconnect(); } ///////////////////////////////////////////////////////////////////// @@ -367,9 +364,10 @@ void Connection::State::process_fin(Connection& tcp, TCP::Packet_ptr in) { ///////////////////////////////////////////////////////////////////// void Connection::State::send_reset(Connection& tcp) { - tcp.send_buffer_.clear(); - tcp.outgoing_packet()->set_seq(tcp.tcb().SND.NXT).set_ack(0).set_flag(RST); - tcp.transmit(); + tcp.write_queue_reset(); + auto packet = tcp.outgoing_packet(); + packet->set_seq(tcp.tcb().SND.NXT).set_ack(0).set_flag(RST); + tcp.transmit(packet); } ///////////////////////////////////////////////////////////////////// @@ -435,7 +433,7 @@ void Connection::Closed::open(Connection& tcp, bool active) { tcb.SND.UNA = tcb.ISS; tcb.SND.NXT = tcb.ISS+1; - tcp.transmit(); + tcp.transmit(packet); tcp.set_state(SynSent::instance()); } else { throw TCPException{"No remote host set."}; @@ -449,10 +447,11 @@ void Connection::Listen::open(Connection& tcp, bool) { if(!tcp.remote().is_empty()) { auto& tcb = tcp.tcb(); tcb.ISS = tcp.generate_iss(); - tcp.outgoing_packet()->set_seq(tcb.ISS).set_flag(SYN); + auto packet = tcp.outgoing_packet(); + packet->set_seq(tcb.ISS).set_flag(SYN); tcb.SND.UNA = tcb.ISS; tcb.SND.NXT = tcb.ISS+1; - tcp.transmit(); + tcp.transmit(packet); tcp.set_state(SynSent::instance()); } else { throw TCPException{"No remote host set."}; @@ -469,15 +468,15 @@ void Connection::Listen::open(Connection& tcp, bool) { */ ///////////////////////////////////////////////////////////////////// -size_t Connection::State::send(Connection&, const char*, size_t, bool) { +size_t Connection::State::send(Connection&, WriteBuffer&) { throw TCPException{"Connection closing."}; } -size_t Connection::Closed::send(Connection&, const char*, size_t, bool) { +size_t Connection::Closed::send(Connection&, WriteBuffer&) { throw TCPException{"Connection does not exist."}; } -size_t Connection::Listen::send(Connection&, const char*, size_t, bool) { +size_t Connection::Listen::send(Connection&, WriteBuffer&) { // TODO: Skip this? /* If the foreign socket is specified, then change the connection @@ -491,40 +490,46 @@ size_t Connection::Listen::send(Connection&, const char*, size_t, bool) { Foreign socket was not specified, then return "error: foreign socket unspecified". */ + //if(tcp.remote().is_empty()) + // throw TCPException{"Foreign socket unspecified."}; + throw TCPException{"Cannot send on listening connection."}; return 0; } -size_t Connection::SynSent::send(Connection& tcp, const char* buffer, size_t n, bool push) { +size_t Connection::SynSent::send(Connection&, WriteBuffer&) { /* Queue the data for transmission after entering ESTABLISHED state. If no space to queue, respond with "error: insufficient resources". */ - //return tcp.write_to_send_buffer(buffer, n, push); - return 0; + + return 0; // nothing written, indicates queue } -size_t Connection::SynReceived::send(Connection& tcp, const char* buffer, size_t n, bool push) { +size_t Connection::SynReceived::send(Connection&, WriteBuffer&) { /* Queue the data for transmission after entering ESTABLISHED state. If no space to queue, respond with "error: insufficient resources". */ - return tcp.write_to_send_buffer(buffer, n, push); + + return 0; // nothing written, indicates queue } -size_t Connection::Established::send(Connection& tcp, const char* buffer, size_t n, bool push) { - debug(" Sending data with the length of %u. PUSH: %d \n", n, push); - auto bytes_written = tcp.write_to_send_buffer(buffer, n, push); - tcp.transmit(); - return bytes_written; +size_t Connection::Established::send(Connection& tcp, WriteBuffer& buffer) { + // if nothing in queue, try to write directly + if(tcp.write_queue.empty()) + return tcp.send(buffer); + + return 0; } -size_t Connection::CloseWait::send(Connection& tcp, const char* buffer, size_t n, bool push) { - debug(" Sending data with the length of %u. PUSH: %d \n", n, push); - auto bytes_written = tcp.write_to_send_buffer(buffer, n, push); - tcp.transmit(); - return bytes_written; +size_t Connection::CloseWait::send(Connection& tcp, WriteBuffer& buffer) { + // if nothing in queue, try to write directly + if(tcp.write_queue.empty()) + return tcp.send(buffer); + + return 0; } ///////////////////////////////////////////////////////////////////// @@ -536,24 +541,24 @@ size_t Connection::CloseWait::send(Connection& tcp, const char* buffer, size_t n */ ///////////////////////////////////////////////////////////////////// -size_t Connection::State::receive(Connection&, char*, size_t) { +void Connection::State::receive(Connection&, ReadBuffer&) { throw TCPException{"Connection closing."}; } -size_t Connection::Established::receive(Connection& tcp, char* buffer, size_t n) { - return tcp.read_from_receive_buffer(buffer, n); +void Connection::Established::receive(Connection& tcp, ReadBuffer& buffer) { + tcp.receive(buffer); } -size_t Connection::FinWait1::receive(Connection& tcp, char* buffer, size_t n) { - return tcp.read_from_receive_buffer(buffer, n); +void Connection::FinWait1::receive(Connection& tcp, ReadBuffer& buffer) { + tcp.receive(buffer); } -size_t Connection::FinWait2::receive(Connection& tcp, char* buffer, size_t n) { - return tcp.read_from_receive_buffer(buffer, n); +void Connection::FinWait2::receive(Connection& tcp, ReadBuffer& buffer) { + tcp.receive(buffer); } -size_t Connection::CloseWait::receive(Connection& tcp, char* buffer, size_t n) { - return tcp.read_from_receive_buffer(buffer, n); +void Connection::CloseWait::receive(Connection& tcp, ReadBuffer& buffer) { + tcp.receive(buffer); } ///////////////////////////////////////////////////////////////////// @@ -595,8 +600,9 @@ void Connection::SynReceived::close(Connection& tcp) { */ // Dont know how to queue for close for processing... auto& tcb = tcp.tcb(); - tcp.outgoing_packet()->set_seq(tcb.SND.NXT++).set_ack(tcb.RCV.NXT).set_flags(ACK | FIN); - tcp.transmit(); + auto packet = tcp.outgoing_packet(); + packet->set_seq(tcb.SND.NXT++).set_ack(tcb.RCV.NXT).set_flags(ACK | FIN); + tcp.transmit(packet); tcp.set_state(Connection::FinWait1::instance()); } @@ -606,8 +612,9 @@ void Connection::SynReceived::abort(Connection& tcp) { void Connection::Established::close(Connection& tcp) { auto& tcb = tcp.tcb(); - tcp.outgoing_packet()->set_seq(tcb.SND.NXT++).set_ack(tcb.RCV.NXT).set_flags(ACK | FIN); - tcp.transmit(); + auto packet = tcp.outgoing_packet(); + packet->set_seq(tcb.SND.NXT++).set_ack(tcb.RCV.NXT).set_flags(ACK | FIN); + tcp.transmit(packet); tcp.set_state(Connection::FinWait1::instance()); } @@ -635,8 +642,9 @@ void Connection::CloseWait::close(Connection& tcp) { segmentized; then send a FIN segment, enter CLOSING state. */ auto& tcb = tcp.tcb(); - tcp.outgoing_packet()->set_seq(tcb.SND.NXT++).set_ack(tcb.RCV.NXT).set_flags(ACK | FIN); - tcp.transmit(); + auto packet = tcp.outgoing_packet(); + packet->set_seq(tcb.SND.NXT++).set_ack(tcb.RCV.NXT).set_flags(ACK | FIN); + tcp.transmit(packet); tcp.set_state(Connection::Closing::instance()); } @@ -682,12 +690,13 @@ State::Result Connection::Closed::handle(Connection& tcp, TCP::Packet_ptr in) { if(in->isset(RST)) { return OK; } + auto packet = tcp.outgoing_packet(); if(!in->isset(ACK)) { - tcp.outgoing_packet()->set_seq(0).set_ack(in->seq() + in->data_length()).set_flags(RST | ACK); + packet->set_seq(0).set_ack(in->seq() + in->data_length()).set_flags(RST | ACK); } else { - tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); + packet->set_seq(in->ack()).set_flag(RST); } - tcp.transmit(); + tcp.transmit(packet); return OK; } @@ -698,8 +707,9 @@ State::Result Connection::Listen::handle(Connection& tcp, TCP::Packet_ptr in) { return OK; } if(in->isset(ACK)) { - tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); - tcp.transmit(); + auto packet = tcp.outgoing_packet(); + packet->set_seq(in->ack()).set_flag(RST); + tcp.transmit(packet); return OK; } if(in->isset(SYN)) { @@ -725,7 +735,7 @@ State::Result Connection::Listen::handle(Connection& tcp, TCP::Packet_ptr in) { */ tcp.add_option(Option::MSS, packet); - tcp.transmit(); + tcp.transmit(packet); tcp.set_state(SynReceived::instance()); return OK; @@ -742,8 +752,9 @@ State::Result Connection::SynSent::handle(Connection& tcp, TCP::Packet_ptr in) { if(in->ack() <= tcb.ISS or in->ack() > tcb.SND.NXT) { // send a reset if(!in->isset(RST)) { - tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); - tcp.transmit(); + auto packet = tcp.outgoing_packet(); + packet->set_seq(in->ack()).set_flag(RST); + tcp.transmit(packet); return OK; } // (unless the RST bit is set, if so drop the segment and return) @@ -806,6 +817,7 @@ State::Result Connection::SynSent::handle(Connection& tcp, TCP::Packet_ptr in) { // TODO: Fix this one according to the text above. if(in->isset(SYN)) { + auto& tcb = tcp.tcb(); tcb.RCV.NXT = in->seq()+1; tcb.IRS = in->seq(); tcb.SND.UNA = in->ack(); @@ -817,8 +829,9 @@ State::Result Connection::SynSent::handle(Connection& tcp, TCP::Packet_ptr in) { tcp.signal_connect(); // NOTE: User callback if(tcb.SND.NXT == snd_nxt) { - tcp.outgoing_packet()->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); - tcp.transmit(); + auto packet = tcp.outgoing_packet(); + packet->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); + tcp.transmit(packet); } // State is now ESTABLISHED. // Experimental, also makes unessecary process. @@ -840,8 +853,9 @@ State::Result Connection::SynSent::handle(Connection& tcp, TCP::Packet_ptr in) { } // Otherwise enter SYN-RECEIVED, form a SYN,ACK segment else { - tcp.outgoing_packet()->set_seq(tcb.ISS).set_ack(tcb.RCV.NXT).set_flags(SYN | ACK); - tcp.transmit(); + auto packet = tcp.outgoing_packet(); + packet->set_seq(tcb.ISS).set_ack(tcb.RCV.NXT).set_flags(SYN | ACK); + tcp.transmit(packet); tcp.set_state(Connection::SynReceived::instance()); if(in->has_data()) { tcp.add_to_receive_buffer(in); @@ -915,8 +929,9 @@ State::Result Connection::SynReceived::handle(Connection& tcp, TCP::Packet_ptr i reset segment, and send it. */ else { - tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); - tcp.transmit(); + auto packet = tcp.outgoing_packet(); + packet->set_seq(in->ack()).set_flag(RST); + tcp.transmit(packet); } } // ACK is missing From e1d5a91e2e9757d8130472cfb9e035fd3ee7b742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Tue, 29 Mar 2016 13:59:36 +0200 Subject: [PATCH 058/311] tcp: fixed an error --- api/net/tcp.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index c51c0ee38d..137b71a2a8 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -627,7 +627,9 @@ class TCP { OnRead callback; ReadRequest(ReadBuffer buf, OnRead cb) : buffer(buf), callback(cb) {} - ReadRequest() : buffer({std::make_shared(1024), 1024}), callback([](auto, auto&, bool){}) {} + ReadRequest(size_t n = 0) : + buffer(buffer_t(new uint8_t[n], std::default_delete()), n), + callback([](auto, auto&, bool){}) {} }; //using ReadRequest = std::pair; @@ -911,7 +913,7 @@ class TCP { } inline void read(size_t n, OnRead callback) { - ReadBuffer buffer = {buffer_t(new uint8_t[n], std::default_delete()), n}; + ReadBuffer buffer = {buffer_t(new uint8_t[n], std::default_delete()), n}; read(buffer, callback); } From 998dc7f354648b9d4f8ea125520d6fde28b2a262 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Tue, 29 Mar 2016 14:17:22 +0200 Subject: [PATCH 059/311] fs: Async FAT random access read --- src/fs/fat_async.cpp | 61 ++++++++++++++++++++++++++++++++++++++++++-- test/fat/fat32.cpp | 2 +- test/fat/test.sh | 4 +-- 3 files changed, 62 insertions(+), 5 deletions(-) diff --git a/src/fs/fat_async.cpp b/src/fs/fat_async.cpp index 292ab99b5f..984f647d99 100644 --- a/src/fs/fat_async.cpp +++ b/src/fs/fat_async.cpp @@ -145,8 +145,65 @@ namespace fs void FAT::read(const Dirent& ent, uint64_t pos, uint64_t n, on_read_func callback) { - auto buf = read(ent, pos, n); - callback(buf.err, buf.buffer, buf.len); + // cluster -> sector + uint32_t sector = this->cl_to_sector(ent.block); + + // allocate buffer + auto* buffer = new uint8_t[n]; + + // start reading process + typedef std::function next_func_t; + auto next = std::make_shared (); + + *next = + [this, sector, buffer, callback, next] (size_t start, size_t n, size_t end) + { + if (unlikely(n == end)) + { + // report back to HQ + debug("DONE start=%lu, current=%lu, total=%lu\n", start, n, end - start); + // create shared buffer + auto buffer_ptr = buffer_t(buffer, std::default_delete()); + // notify caller + callback(no_error, buffer_ptr, end - start); + return; + } + + // read the current sector based on position @n + uint32_t current_sector = sector + n / this->sector_size; + + device.read(current_sector, + [this, start, n, end, buffer, &callback, sector, next] (buffer_t data) + { + if (!data) + { + // general I/O error occurred + debug("Failed to read sector %u for read()", sector); + // cleanup + delete[] buffer; + callback(true, buffer_t(), 0); + return; + } + + uint32_t length = n & (sector_size-1); + if (n == start && n > 0) + { + length = sector_size - length; + } + else + { + length = (n + sector_size) < end ? sector_size : (end - n); + } + + // copy over data + memcpy(buffer + n, data.get(), length); + // continue reading next sector + (*next)(start, n + length, end); + }); + }; + + // start! + (*next)(pos, pos, pos + n); } void FAT::readFile(const Dirent& ent, on_read_func callback) diff --git a/test/fat/fat32.cpp b/test/fat/fat32.cpp index f0c6c4514e..a795777a29 100644 --- a/test/fat/fat32.cpp +++ b/test/fat/fat32.cpp @@ -96,7 +96,7 @@ void Service::start() assert(ent.name() == "banana.txt"); // asynch file reading test - fs.readFile(ent, + fs.read(ent, 0, ent.size, [] (fs::error_t err, fs::buffer_t buf, uint64_t len) { CHECK(!err, "Read 'banana.txt' asynchronously"); diff --git a/test/fat/test.sh b/test/fat/test.sh index b684926ed3..e347a79140 100755 --- a/test/fat/test.sh +++ b/test/fat/test.sh @@ -1,6 +1,6 @@ #!/bin/bash source ../test_base -mkdir tmpdisk +mkdir -p tmpdisk ### FAT16 TEST ### rm -f my.disk @@ -19,7 +19,7 @@ rm -f memdisk.o my.disk ### FAT16 TEST ### fallocate -l 2147483648 my.disk mkfs.fat my.disk -mkdir tmpdisk +mkdir -p tmpdisk sudo mount my.disk tmpdisk/ sudo cp banana.txt tmpdisk/ sudo mkdir -p tmpdisk/dir1/dir2/dir3/dir4/dir5/dir6 From 1cb08d3042eca02ef843ba3e06d8545025e176b9 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Tue, 29 Mar 2016 14:17:45 +0200 Subject: [PATCH 060/311] vmbuild: Increased size further --- vmbuild/vmbuild.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vmbuild/vmbuild.cpp b/vmbuild/vmbuild.cpp index 454b13672c..564c77549a 100644 --- a/vmbuild/vmbuild.cpp +++ b/vmbuild/vmbuild.cpp @@ -45,13 +45,14 @@ int main(int argc, char** argv) { // Verify proper command usage if (argc < 3) { cout << info << usage; - exit(0x00); + exit(EXIT_FAILURE); } const string bootloc {argv[1]}; const string srvloc {argv[2]}; - const int extra_sectors {1}; //< Fixes missing Magic Signature :bug: + // Fixes missing Magic Signature :bug: + const int extra_sectors = 2; const string img_name {srvloc.substr(srvloc.find_last_of("/") + 1, string::npos) + ".img"}; From 5a851546251c768b274816d2a70908fc729ec9e4 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Tue, 29 Mar 2016 14:36:08 +0200 Subject: [PATCH 061/311] fs: Truncate async readFile, use read instead --- src/fs/fat_async.cpp | 52 ++------------------------------------------ 1 file changed, 2 insertions(+), 50 deletions(-) diff --git a/src/fs/fat_async.cpp b/src/fs/fat_async.cpp index 984f647d99..498e19f1c1 100644 --- a/src/fs/fat_async.cpp +++ b/src/fs/fat_async.cpp @@ -208,55 +208,7 @@ namespace fs void FAT::readFile(const Dirent& ent, on_read_func callback) { - // cluster -> sector - uint32_t sector = this->cl_to_sector(ent.block); - // number of sectors to read ahead - size_t chunks = ent.size / sector_size + 1; - // allocate buffer - auto* buffer = new uint8_t[chunks * sector_size]; - // at which sector we will stop - size_t total = chunks; - size_t current = 0; - - typedef std::function next_func_t; - auto next = std::make_shared (); - - *next = - [this, buffer, ent, callback, next] (uint32_t sector, size_t current, size_t total) - { - if (unlikely(current == total)) - { - // report back to HQ - debug("DONE SIZE: %lu (current=%lu, total=%lu)\n", - ent.size, current, total); - // create shared buffer - auto buffer_ptr = buffer_t(buffer, std::default_delete()); - // notify caller - callback(no_error, buffer_ptr, ent.size); - return; - } - device.read(sector, - [this, current, total, buffer, ent, &callback, sector, next] (buffer_t data) - { - if (!data) - { - // general I/O error occurred - debug("Failed to read sector %u for read()", sector); - // cleanup - delete[] buffer; - callback(true, buffer_t(), 0); - return; - } - - // copy over data - memcpy(buffer + current * sector_size, data.get(), sector_size); - // continue reading next sector - (*next)(sector+1, current+1, total); - }); - }; - - // start! - (*next)(sector, current, total); + read(ent, 0, ent.size, callback); } void FAT::readFile(const std::string& strpath, on_read_func callback) @@ -279,7 +231,7 @@ namespace fs if (unlikely(error)) { // no path, no file! - callback(error, nullptr, 0); + callback(error, buffer_t(), 0); return; } From f9950e76bc3cfcb8fb4a2088d0343421060c8281 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Tue, 29 Mar 2016 15:26:41 +0200 Subject: [PATCH 062/311] fs: Add sync readFile version --- api/fs/ext4.hpp | 4 ++-- api/fs/fat.hpp | 4 ++-- api/fs/filesystem.hpp | 4 ++-- src/fs/ext4.cpp | 4 ++-- src/fs/fat_async.cpp | 14 ++++++-------- src/fs/fat_sync.cpp | 32 ++++++++++++++++++++++++++++++++ test/memdisk/test.sh | 2 +- 7 files changed, 47 insertions(+), 17 deletions(-) diff --git a/api/fs/ext4.hpp b/api/fs/ext4.hpp index df5a821261..d6f73782e5 100644 --- a/api/fs/ext4.hpp +++ b/api/fs/ext4.hpp @@ -53,8 +53,8 @@ namespace fs virtual error_t ls(const std::string& path, dirvec_t e) override; // read an entire file into a buffer, then call on_read - virtual void readFile(const std::string&, on_read_func) override; - virtual void readFile(const Dirent& ent, on_read_func) override; + virtual void readFile(const std::string&, on_read_func) override; + virtual Buffer readFile(const std::string&) override; /** Read @n bytes from file pointed by @entry starting at position @pos */ virtual void read(const Dirent&, uint64_t pos, uint64_t n, on_read_func) override; diff --git a/api/fs/fat.hpp b/api/fs/fat.hpp index 16c1d336e2..424ce4e19e 100644 --- a/api/fs/fat.hpp +++ b/api/fs/fat.hpp @@ -39,8 +39,8 @@ namespace fs virtual error_t ls(const std::string& path, dirvec_t) override; // read an entire file into a buffer, then call on_read - virtual void readFile(const std::string&, on_read_func) override; - virtual void readFile(const Dirent& ent, on_read_func) override; + virtual void readFile(const std::string&, on_read_func) override; + virtual Buffer readFile(const std::string&) override; /** Read @n bytes from file pointed by @entry starting at position @pos */ virtual void read(const Dirent&, uint64_t pos, uint64_t n, on_read_func) override; diff --git a/api/fs/filesystem.hpp b/api/fs/filesystem.hpp index 05702bcb9f..215e0cb9b2 100644 --- a/api/fs/filesystem.hpp +++ b/api/fs/filesystem.hpp @@ -128,8 +128,8 @@ class FileSystem { virtual error_t ls(const std::string& path, dirvec_t e) = 0; /** Read an entire file into a buffer, then call on_read */ - virtual void readFile(const std::string&, on_read_func) = 0; - virtual void readFile(const Dirent& ent, on_read_func) = 0; + virtual void readFile(const std::string&, on_read_func) = 0; + virtual Buffer readFile(const std::string&) = 0; /** Read @n bytes from direntry from position @pos */ virtual void read(const Dirent&, uint64_t pos, uint64_t n, on_read_func) = 0; diff --git a/src/fs/ext4.cpp b/src/fs/ext4.cpp index 3fabf278e3..7a6e26cd9b 100644 --- a/src/fs/ext4.cpp +++ b/src/fs/ext4.cpp @@ -47,9 +47,9 @@ namespace fs (void) path; } - void EXT4::readFile(const Dirent&, on_read_func callback) + EXT4::Buffer EXT4::readFile(const std::string&) { - callback(true, buffer_t(), 0); + return Buffer(true, buffer_t(), 0); } void EXT4::readFile(const std::string& strpath, on_read_func callback) { diff --git a/src/fs/fat_async.cpp b/src/fs/fat_async.cpp index 498e19f1c1..965a35de98 100644 --- a/src/fs/fat_async.cpp +++ b/src/fs/fat_async.cpp @@ -206,11 +206,6 @@ namespace fs (*next)(pos, pos, pos + n); } - void FAT::readFile(const Dirent& ent, on_read_func callback) - { - read(ent, 0, ent.size, callback); - } - void FAT::readFile(const std::string& strpath, on_read_func callback) { auto path = std::make_shared (strpath); @@ -236,15 +231,18 @@ namespace fs } // find the matching filename in directory - for (auto& e : *dirents) + for (auto& ent : *dirents) { - if (unlikely(e.name() == filename)) + if (unlikely(ent.name() == filename)) { // read this file - readFile(e, callback); + read(ent, 0, ent.size, callback); return; } } + + // file not found + callback(true, buffer_t(), 0); }); } // readFile() diff --git a/src/fs/fat_sync.cpp b/src/fs/fat_sync.cpp index 0d60c7e4ee..6a446d3712 100644 --- a/src/fs/fat_sync.cpp +++ b/src/fs/fat_sync.cpp @@ -68,6 +68,38 @@ namespace fs return Buffer(no_error, buffer_t(result), total); } + Buffer FAT::readFile(const std::string& strpath) + { + Path path(strpath); + if (unlikely(path.empty())) + { + // there is no possible file to read where path is empty + return Buffer(true, nullptr, 0); + } + debug("readFile: %s\n", path.back().c_str()); + + std::string filename = path.back(); + path.pop_back(); + + // result directory entries are put into @dirents + auto dirents = new_shared_vector(); + + auto err = traverse(path, dirents); + if (err) return Buffer(true, buffer_t(), 0); // for now + + // find the matching filename in directory + for (auto& e : *dirents) + { + if (unlikely(e.name() == filename)) + { + // read this file + return read(e, 0, e.size); + } + } + // entry not found + return Buffer(true, buffer_t(), 0); + } // readFile() + error_t FAT::int_ls(uint32_t sector, dirvec_t ents) { bool done = false; diff --git a/test/memdisk/test.sh b/test/memdisk/test.sh index e508abfc7b..e0915da628 100755 --- a/test/memdisk/test.sh +++ b/test/memdisk/test.sh @@ -24,4 +24,4 @@ start Test.img "Memdisk: Big disk test" make SERVICE=Test FILES=bigdisk.cpp clean sudo umount tmpdisk/ -rm -f big.disk +rm -f big.disk memdisk.o From 64d9b6b40bb9dcc58df738a8c4517545c093022c Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 29 Mar 2016 15:31:39 +0200 Subject: [PATCH 063/311] Debugging info is now turned off by default --- src/Makefile | 36 +++++++++++++++++++++++------------- src/seed/Makefile | 19 +++++++++++++++---- 2 files changed, 38 insertions(+), 17 deletions(-) diff --git a/src/Makefile b/src/Makefile index c420b09af6..aff1a711ba 100644 --- a/src/Makefile +++ b/src/Makefile @@ -12,7 +12,7 @@ INSTALL = $(INCLUDEOS_INSTALL) # stackrealign is needed to guarantee 16-byte stack alignment for SSE # the compiler seems to be really dumb in this regard, creating a misaligned stack left and right CAPABS_COMMON = -mstackrealign -msse3 -CAPABS = $(CAPABS_COMMON) -O2 #-DNO_DEBUG=1 +CAPABS = $(CAPABS_COMMON) -O2 -DNO_DEBUG=1 WARNS = -Wall -Wextra #-pedantic DEBUG_OPTS = -ggdb3 @@ -21,7 +21,7 @@ DEBUG_OPTS = -ggdb3 ################################################### LIBC_OBJ = $(INSTALL)/newlib/libc.a LIBG_OBJ = $(INSTALL)/newlib/libg.a -LIBM_OBJ = $(INSTALL)/newlib/libm.a +LIBM_OBJ = $(INSTALL)/newlib/libm.a LIBGCC = $(INSTALL)/libgcc/libgcc.a LIBCXX = $(INSTALL)/libcxx/libc++.a libc++abi.a @@ -48,10 +48,10 @@ CPPOPTS = -target i686-elf INCLUDES = -I../api/sys -I$(INSTALL)/libcxx/include -I$(INC_NEWLIB) -Iinclude -I../api # CINCLUDES = -I../api/sys -I$(INC_NEWLIB) -Iinclude -I../api # -CCOPTS += $(CAPABS) $(WARNS) -c -m32 -fno-stack-protector -fno-builtin -march=i686 $(CINCLUDES) -CPPOPTS += $(CAPABS) $(WARNS) -c -m32 -std=c++14 -fno-stack-protector $(INCLUDES) -D_LIBCPP_HAS_NO_THREADS=1 -DOS_VERSION="\"$(shell git describe --dirty)\"" +CCOPTS += $(CAPABS) $(WARNS) -c -m32 -fno-stack-protector -fno-builtin -march=i686 $(CINCLUDES) +CPPOPTS += $(CAPABS) $(WARNS) -c -m32 -std=c++14 -fno-stack-protector $(INCLUDES) -D_LIBCPP_HAS_NO_THREADS=1 -DOS_VERSION="\"$(shell git describe --dirty)\"" -LDOPTS = -nostdlib -melf_i386 -N --eh-frame-hdr --script=linker.ld #-flto +LDOPTS = -nostdlib -melf_i386 -N --eh-frame-hdr --script=linker.ld #-flto # Objects ################################################### @@ -90,23 +90,33 @@ OS_DEPS = $(OS_OBJECTS:.o=.d) # - a bootloader # - an OS library for the service to link against -all: bootloader libc++abi.a os.a +all: bootloader libc++abi.a os.a @echo "\n>>> Built OS-library. Install to '"$(INSTALL)"' using 'make install'" #stripped: LDOPTS += -s #strip all stripped: CAPABS += -Oz stripped: all test -production: CAPABS += -DNO_DEBUG=1 -production: all test +# Build like "all" but with debugging output (i.e. the 'debug'-macro) enabled +debug-info: CAPABS += -UNO_DEBUG +debug-info: all test -# The same, but with debugging symbols (OBS: Dramatically increases binary size) +# Build with debugging symbols (OBS: Dramatically increases binary size) debug: CCOPTS += $(DEBUG_OPTS) debug: CPPOPTS += $(DEBUG_OPTS) debug: OBJ_LIST += $(LIBG_OBJ) -debug: CAPABS += -O0 -UNO_DEBUG +debug: CAPABS += -O0 debug: all test +# Build with debugging symbols + debugging ouput, i.e. "debug" + "debug-info" +debug-all: CAPABS += -UNO_DEBUG +debug-all: CCOPTS += $(DEBUG_OPTS) +debug-all: CPPOPTS += $(DEBUG_OPTS) +debug-all: OBJ_LIST += $(LIBG_OBJ) +debug-all: CAPABS += -O0 +debug-all: all test + + silent: CPPOPTS += -DNO_INFO=1 silent: all test @@ -174,11 +184,11 @@ install: $(CRTI_OBJ) $(CRTN_OBJ) # Makefile recipes ################################################### %.o: %.c - $(CC) -MMD $(CCOPTS) -o $@ $< + $(CC) -MMD $(CCOPTS) -o $@ $< -%.o: %.cpp +%.o: %.cpp @echo "\n" - $(CPP) -MMD $(CPPOPTS) -o $@ $< + $(CPP) -MMD $(CPPOPTS) -o $@ $< # AS-assembled object files %.o: %.s diff --git a/src/seed/Makefile b/src/seed/Makefile index 2ec66c6419..4687746ad0 100644 --- a/src/seed/Makefile +++ b/src/seed/Makefile @@ -78,13 +78,24 @@ stripped: LDOPTS += -S #strip all stripped: CPPOPTS += -Oz stripped: service +# Build like "all" but with debugging output (i.e. the 'debug'-macro) enabled +debug-info: CAPABS += -UNO_DEBUG +debug-info: service -# The same, but with debugging symbols (OBS: Dramatically increases binary size) +# Build with debugging symbols (OBS: Dramatically increases binary size) debug: CCOPTS += $(DEBUG_OPTS) debug: CPPOPTS += $(DEBUG_OPTS) -#debug: LDOPTS += -M --verbose -debug: OBJS += $(LIBG_OBJ) -debug: service #Don't wanna call 'all', since it strips debug info +debug: OBJ_LIST += $(LIBG_OBJ) +debug: CAPABS += -O0 +debug: service + +# Build with debugging symbols + debugging ouput, i.e. "debug" + "debug-info" +debug-all: CAPABS += -UNO_DEBUG +debug-all: CCOPTS += $(DEBUG_OPTS) +debug-all: CPPOPTS += $(DEBUG_OPTS) +debug-all: OBJ_LIST += $(LIBG_OBJ) +debug-all: CAPABS += -O0 +debug-all: service # Disk image as a section ################################################### From e2a166f539b49654d0ebc4703c0293c53417c97b Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Tue, 29 Mar 2016 15:45:02 +0200 Subject: [PATCH 064/311] test: Update FAT tests for readFile changes --- test/fat/fat16.cpp | 7 ++++-- test/fat/fat32.cpp | 53 +++++++++++++++++++++++++++++----------------- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/test/fat/fat16.cpp b/test/fat/fat16.cpp index c527a0113c..a912a85432 100644 --- a/test/fat/fat16.cpp +++ b/test/fat/fat16.cpp @@ -92,9 +92,12 @@ void Service::start() "-:;::;:;: ':;::;:'' ;.-' ""`---...________...---'"" )"; - CHECK(banana == internal_banana, "Correct banana"); - printf("%s\n", banana.c_str()); + printf("%s\n", internal_banana.c_str()); + CHECK(banana == internal_banana, "Correct banana #1"); + buf = fs.readFile("/banana.txt"); + banana = std::string((char*) buf.buffer.get(), buf.len); + CHECK(banana == internal_banana, "Correct banana #2"); }); INFO("FAT16", "SUCCESS"); diff --git a/test/fat/fat32.cpp b/test/fat/fat32.cpp index a795777a29..972652e3bf 100644 --- a/test/fat/fat32.cpp +++ b/test/fat/fat32.cpp @@ -23,6 +23,22 @@ #include std::shared_ptr disk; +std::string internal_banana = + R"( ____ ___ + | _ \ ___ _ _.' _ `. + _ | [_) )' _ `._ _ ___ ! \ | | (_) | _ +|:;.| _ <| (_) | \ | |' _ `| \| | _ | .:;| +| `.[_) ) _ | \| | (_) | | | | |.',..| +':. `. /| | | | | _ | |\ | | |.' :;::' + !::, `-!_| | | |\ | | | | | \ !_!.' ':;! + !::; ":;:!.!.\_!_!_!.!-'-':;:'' '''! + ';:' `::;::;' '' ., . + `: .,. `' .::... . .::;::;' + `..:;::;:.. ::;::;:;:;, :;::;' + "-:;::;:;: ':;::;:'' ;.-' + ""`---...________...---'"" +)"; + void Service::start() { INFO("FAT32", "Running tests for FAT32"); @@ -95,34 +111,33 @@ void Service::start() CHECK(ent.name() == "banana.txt", "Name is 'banana.txt'"); assert(ent.name() == "banana.txt"); + printf("%s\n", internal_banana.c_str()); + // asynch file reading test fs.read(ent, 0, ent.size, - [] (fs::error_t err, fs::buffer_t buf, uint64_t len) + [&fs] (fs::error_t err, fs::buffer_t buf, uint64_t len) { - CHECK(!err, "Read 'banana.txt' asynchronously"); + CHECK(!err, "read: Read 'banana.txt' asynchronously"); if (err) { panic("Failed to read file async"); } std::string banana((char*) buf.get(), len); - std::string internal_banana = - R"( ____ ___ - | _ \ ___ _ _.' _ `. - _ | [_) )' _ `._ _ ___ ! \ | | (_) | _ -|:;.| _ <| (_) | \ | |' _ `| \| | _ | .:;| -| `.[_) ) _ | \| | (_) | | | | |.',..| -':. `. /| | | | | _ | |\ | | |.' :;::' - !::, `-!_| | | |\ | | | | | \ !_!.' ':;! - !::; ":;:!.!.\_!_!_!.!-'-':;:'' '''! - ';:' `::;::;' '' ., . - `: .,. `' .::... . .::;::;' - `..:;::;:.. ::;::;:;:;, :;::;' - "-:;::;:;: ':;::;:'' ;.-' - ""`---...________...---'"" -)"; - CHECK(banana == internal_banana, "Correct banana"); - printf("%s\n", banana.c_str()); + CHECK(banana == internal_banana, "Correct banana #1"); + + fs.readFile("/banana.txt", + [&fs] (fs::error_t err, fs::buffer_t buf, uint64_t len) + { + CHECK(!err, "readFile: Read 'banana.txt' asynchronously"); + if (err) + { + panic("Failed to read file async"); + } + + std::string banana((char*) buf.get(), len); + CHECK(banana == internal_banana, "Correct banana #2"); + }); }); }); From fed428903c4a89fec17eda36761cdbace45bee8a Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 29 Mar 2016 16:56:26 +0200 Subject: [PATCH 065/311] Added 'available buffers' and 'available transmit queue' getters, + refactored event --- api/hw/nic.hpp | 10 ++++-- api/net/buffer_store.hpp | 4 +++ api/net/inet.hpp | 34 +++++++++++------- api/net/inet4.hpp | 75 +++++++++++++++++++++++---------------- api/net/inet_common.hpp | 5 +-- api/virtio/virtionet.hpp | 10 ++++-- src/virtio/virtionet.cpp | 2 +- test/transmit/service.cpp | 18 +++++----- 8 files changed, 98 insertions(+), 60 deletions(-) diff --git a/api/hw/nic.hpp b/api/hw/nic.hpp index 698f8cf777..ea280f3197 100644 --- a/api/hw/nic.hpp +++ b/api/hw/nic.hpp @@ -64,8 +64,14 @@ namespace hw { inline net::BufferStore& bufstore() noexcept { return driver_.bufstore(); } - inline void on_buffers_available(net::buf_avail_delg del) - { driver_.on_buffers_available(del); }; + inline void on_transmit_queue_available(net::transmit_avail_delg del) + { driver_.on_transmit_queue_available(del); } + + inline size_t transmit_queue_available() + { return driver_.transmit_queue_available(); } + + inline size_t buffers_available() + { return bufstore().buffers_available(); } private: driver_t driver_; diff --git a/api/net/buffer_store.hpp b/api/net/buffer_store.hpp index 9a6daf04c0..f552f4b31b 100644 --- a/api/net/buffer_store.hpp +++ b/api/net/buffer_store.hpp @@ -77,6 +77,10 @@ class BufferStore { /** Check if an address is the start of a buffer */ inline bool address_is_offset_bufstart(buffer_t addr) { return (addr - pool_ - device_offset_) % bufsize_ == 0; } + + inline size_t buffers_available() + { return available_buffers_.size(); } + private: size_t bufcount_; const size_t bufsize_; diff --git a/api/net/inet.hpp b/api/net/inet.hpp index bb7db1794c..198b153d4d 100644 --- a/api/net/inet.hpp +++ b/api/net/inet.hpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -21,12 +21,12 @@ #include namespace net { - + class TCP; class UDP; class DHClient; -/** An abstract IP-stack interface */ +/** An abstract IP-stack interface */ template class Inet { public: @@ -34,7 +34,7 @@ class Inet { template using resolve_func = delegate; - + virtual typename IPV::addr ip_addr() = 0; virtual typename IPV::addr netmask() = 0; virtual typename IPV::addr router() = 0; @@ -46,19 +46,29 @@ class Inet { virtual UDP& udp() = 0; virtual std::shared_ptr dhclient() = 0; - + virtual uint16_t MTU() const = 0; - + virtual Packet_ptr createPacket(size_t size) = 0; - + virtual void resolve(const std::string& hostname, resolve_func func) = 0; - + virtual void set_dns_server(typename IPV::addr server) = 0; - - virtual void network_config(typename IPV::addr ip, - typename IPV::addr nmask, + + virtual void network_config(typename IPV::addr ip, + typename IPV::addr nmask, typename IPV::addr router, typename IPV::addr dnssrv) = 0; + + /** Event triggered when there are available buffers in the transmit queue */ + virtual void on_transmit_queue_available(transmit_avail_delg del) = 0; + + /** Number of packets the transmit queue has room for */ + virtual size_t transmit_queue_available() = 0; + + /** Number of buffers available in the bufstore */ + virtual size_t buffers_available() = 0; + }; //< class Inet } //< namespace net diff --git a/api/net/inet4.hpp b/api/net/inet4.hpp index 4359c54caa..36f0a3db10 100644 --- a/api/net/inet4.hpp +++ b/api/net/inet4.hpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -34,43 +34,43 @@ #include "ip4/icmpv4.hpp" namespace net { - + /** A complete IP4 network stack */ template class Inet4 : public Inet{ public: - - Ethernet::addr link_addr() override + + Ethernet::addr link_addr() override { return eth_.mac(); } - - IP4::addr ip_addr() override + + IP4::addr ip_addr() override { return ip4_addr_; } - - IP4::addr netmask() override + + IP4::addr netmask() override { return netmask_; } - - IP4::addr router() override + + IP4::addr router() override { return router_; } - + Ethernet& link() override - { return eth_; } - + { return eth_; } + inline IP4& ip_obj() override { return ip4_; } - + /** Get the TCP-object belonging to this stack */ inline TCP& tcp() override { debug(" Returning tcp-reference to %p \n",&tcp_); return tcp_; } - + /** Get the UDP-object belonging to this stack */ inline UDP& udp() override { return udp_; } /** Get the DHCP client (if any) */ inline std::shared_ptr dhclient() override { return dhcp_; } - + /** Create a Packet, with a preallocated buffer. - @param size : the "size" reported by the allocated packet. + @param size : the "size" reported by the allocated packet. @note as of v0.6.3 this has no effect other than to force the size to be - set explicitly by the caller. + set explicitly by the caller. @todo make_shared will allocate with new. This is fast in IncludeOS, (no context switch for sbrk) but consider overloading operator new. */ @@ -79,17 +79,17 @@ namespace net { auto release = BufferStore::release_del::from (nic_.bufstore()); // Create the packet, using buffer and . - return std::make_shared(bufstore_.get_offset_buffer(), + return std::make_shared(bufstore_.get_offset_buffer(), bufstore_.offset_bufsize(), size, release); } - + // We have to ask the Nic for the MTU virtual inline uint16_t MTU() const override { return nic_.MTU(); } inline auto available_capacity() { return bufstore_.capacity(); } - + /** * @func a delegate that provides a hostname and its address, which is 0 if the * name @hostname was not found. Note: Test with INADDR_ANY for a 0-address. @@ -100,25 +100,25 @@ namespace net { { dns.resolve(this->dns_server, hostname, func); } - + inline virtual void set_dns_server(IP4::addr server) override { this->dns_server = server; } - + /** We don't want to copy or move an IP-stack. It's tied to a device. */ Inet4(Inet4&) = delete; Inet4(Inet4&&) = delete; Inet4& operator=(Inet4) = delete; Inet4 operator=(Inet4&&) = delete; - + /** Initialize with static IP / netmask */ Inet4(hw::Nic& nic, IP4::addr ip, IP4::addr netmask); - + /** Initialize with DHCP */ Inet4(hw::Nic& nic); - + virtual void network_config(IP4::addr addr, IP4::addr nmask, IP4::addr router, IP4::addr dns) override { @@ -129,15 +129,28 @@ namespace net { this->dns_server = dns; } - private: + inline virtual void + on_transmit_queue_available(transmit_avail_delg del) override { + nic_.on_transmit_queue_available(del); + } + + inline virtual size_t transmit_queue_available() override { + return nic_.transmit_queue_available(); + } + + inline virtual size_t buffers_available() override { + return nic_.buffers_available(); + } + + private: IP4::addr ip4_addr_; IP4::addr netmask_; IP4::addr router_; IP4::addr dns_server; - + // This is the actual stack - hw::Nic& nic_; + hw::Nic& nic_; Ethernet eth_; Arp arp_; IP4 ip4_; @@ -146,7 +159,7 @@ namespace net { TCP tcp_; // we need this to store the cache per-stack DNSClient dns; - + std::shared_ptr dhcp_{}; BufferStore& bufstore_; }; diff --git a/api/net/inet_common.hpp b/api/net/inet_common.hpp index fbc2a81f36..ef8d0d5c48 100644 --- a/api/net/inet_common.hpp +++ b/api/net/inet_common.hpp @@ -36,8 +36,9 @@ namespace net { using downstream = delegate; using upstream = downstream; - // Delegate for signalling available buffers - using buf_avail_delg = delegate; + // Delegate for signalling available space in device transmit queue + // 'count' is a multiple of packets + using transmit_avail_delg = delegate; // Compute the internet checksum for the buffer / buffer part provided uint16_t checksum(void* data, size_t len) noexcept; diff --git a/api/virtio/virtionet.hpp b/api/virtio/virtionet.hpp index a1ae685d58..a2beb1e4b8 100644 --- a/api/virtio/virtionet.hpp +++ b/api/virtio/virtionet.hpp @@ -139,9 +139,13 @@ class VirtioNet : Virtio { /** Constructor. @param pcidev an initialized PCI device. */ VirtioNet(hw::PCI_Device& pcidev); + inline void on_transmit_queue_available(net::transmit_avail_delg del) + { transmit_queue_available_event_ = del; }; - inline void on_buffers_available(net::buf_avail_delg del) - { buffer_available_event_ = del; }; + /** Space available in the transmit queue, in packets */ + inline size_t transmit_queue_available(){ + return tx_q.num_free() / 2; + }; private: @@ -224,7 +228,7 @@ class VirtioNet : Virtio { net::BufferStore::release_del::from (bufstore_); - net::buf_avail_delg buffer_available_event_ {}; + net::transmit_avail_delg transmit_queue_available_event_ {}; net::Packet_ptr transmit_queue_ {0}; diff --git a/src/virtio/virtionet.cpp b/src/virtio/virtionet.cpp index 9dc8d27074..c21b35decf 100644 --- a/src/virtio/virtionet.cpp +++ b/src/virtio/virtionet.cpp @@ -289,7 +289,7 @@ void VirtioNet::service_queues(){ // If we now emptied the buffer, offer packets to stack if (!transmit_queue_ && tx_q.num_free() > 1) - buffer_available_event_(tx_q.num_free() / 2); + transmit_queue_available_event_(tx_q.num_free() / 2); else debug(" No event: !transmit q %i, num_avail %i \n", !transmit_queue_, tx_q.num_free()); diff --git a/test/transmit/service.cpp b/test/transmit/service.cpp index a4a7de1fa9..dd7a2edfdd 100644 --- a/test/transmit/service.cpp +++ b/test/transmit/service.cpp @@ -48,35 +48,35 @@ void Service::start() sock.onRead([] (UDP::Socket& conn, UDP::addr_t addr, UDP::port_t port, const char* data, int len) -> int { - CHECK(1, "Got UDP data from %s: %i: %s", - addr.str().c_str(), port, data); + INFO("Test 2","Starting UDP-test (got UDP data from %s: %i: %s", + addr.str().c_str(), port, data); // send the same thing right back! const int packets { 600 }; - INFO("TEST 2", "Trying to transmit %i packets at maximum throttle", packets); + INFO("TEST 2", "Trying to transmit %i UDP packets at maximum throttle", packets); for (int i = 0; i < packets; i++) conn.sendto(addr, port, data, len); - - - - return 0; }); - eth0.on_buffers_available([](size_t s){ + eth0.on_transmit_queue_available([](size_t s){ CHECK(1,"There are now %i available buffers", s); }); hw::PIT::instance().onTimeout(200ms,[=](){ const int packets { 600 }; - INFO("TEST 2", "Trying to transmit %i packets at maximum throttle", packets); + INFO("TEST 1", "Trying to transmit %i ethernet packets at maximum throttle", packets); for (int i=0; i < packets; i++){ auto pckt = inet->createPacket(inet->MTU()); Ethernet::header* hdr = reinterpret_cast(pckt->buffer()); hdr->dest.major = Ethernet::addr::BROADCAST_FRAME.major; hdr->dest.minor = Ethernet::addr::BROADCAST_FRAME.minor; hdr->type = Ethernet::ETH_ARP; + printf("\t Transmit Queue available: %i \n", + inet->transmit_queue_available()); + printf("\t Bufstore available: %i \n", + inet->buffers_available()); inet->link().transmit(pckt); } From c1e1bb80704ba668574c99d117d09fa1de5ef6ba Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 29 Mar 2016 21:19:39 +0200 Subject: [PATCH 066/311] Changed MTU to return only MTU and added 'bufsize()'-getter --- api/hw/nic.hpp | 3 +++ api/virtio/virtionet.hpp | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/api/hw/nic.hpp b/api/hw/nic.hpp index ea280f3197..ec360ea64d 100644 --- a/api/hw/nic.hpp +++ b/api/hw/nic.hpp @@ -61,6 +61,9 @@ namespace hw { inline uint16_t MTU() const noexcept { return driver_.MTU(); } + inline uint16_t bufsize() const noexcept + { return driver_.bufsize(); } + inline net::BufferStore& bufstore() noexcept { return driver_.bufstore(); } diff --git a/api/virtio/virtionet.hpp b/api/virtio/virtionet.hpp index a2beb1e4b8..0abd435f80 100644 --- a/api/virtio/virtionet.hpp +++ b/api/virtio/virtionet.hpp @@ -120,7 +120,10 @@ class VirtioNet : Virtio { const net::Ethernet::addr& mac(); constexpr uint16_t MTU() const { - return 1500 + sizeof(virtio_net_hdr); } + return 1500; } + + constexpr uint16_t bufsize() const { + return MTU() + sizeof(virtio_net_hdr); } /** Delegate linklayer output. Hooks into IP-stack bottom, w.UPSTREAM data. */ inline void set_linklayer_out(net::upstream link_out){ @@ -223,7 +226,7 @@ class VirtioNet : Virtio { net::upstream _link_out; /** 20-bit / 1MB of buffers to start with */ - net::BufferStore bufstore_{ 0xfffffU / MTU(), MTU(), sizeof(virtio_net_hdr) }; + net::BufferStore bufstore_{ 0xfffffU / bufsize(), bufsize(), sizeof(virtio_net_hdr) }; net::BufferStore::release_del release_buffer = net::BufferStore::release_del::from (bufstore_); From 042722e31973f0d66373c535cdf5e52674f32a58 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 29 Mar 2016 21:23:55 +0200 Subject: [PATCH 067/311] Test net::BufferStore and net::Packet chaining --- test/bufstore/Makefile | 22 +++++++++ test/bufstore/README.md | 3 ++ test/bufstore/run.sh | 3 ++ test/bufstore/service.cpp | 99 +++++++++++++++++++++++++++++++++++++++ test/bufstore/test.sh | 4 ++ 5 files changed, 131 insertions(+) create mode 100644 test/bufstore/Makefile create mode 100644 test/bufstore/README.md create mode 100755 test/bufstore/run.sh create mode 100644 test/bufstore/service.cpp create mode 100755 test/bufstore/test.sh diff --git a/test/bufstore/Makefile b/test/bufstore/Makefile new file mode 100644 index 0000000000..6fd9a57702 --- /dev/null +++ b/test/bufstore/Makefile @@ -0,0 +1,22 @@ +################################################# +# IncludeOS SERVICE makefile # +################################################# + +# The name of your service +SERVICE = test_bufstore +SERVICE_NAME = net::buffer_store tests + +# Your service parts +FILES = service.cpp + +# Your disk image +DISK= + + + +# IncludeOS location +ifndef INCLUDEOS_INSTALL +INCLUDEOS_INSTALL=$(HOME)/IncludeOS_install +endif + +include $(INCLUDEOS_INSTALL)/Makeseed diff --git a/test/bufstore/README.md b/test/bufstore/README.md new file mode 100644 index 0000000000..95e7b422f9 --- /dev/null +++ b/test/bufstore/README.md @@ -0,0 +1,3 @@ +# Test net::BufferStore and net::Packet chaining + +Internal tests that verifies that packet chaining plays well with the buffer store, i.e. that you can chain lots of packets, dechain, and they all return their buffers back to the bufstore. diff --git a/test/bufstore/run.sh b/test/bufstore/run.sh new file mode 100755 index 0000000000..3b2132d2cb --- /dev/null +++ b/test/bufstore/run.sh @@ -0,0 +1,3 @@ +#! /bin/bash +source ${INCLUDEOS_HOME-$HOME/IncludeOS_install}/etc/run.sh + diff --git a/test/bufstore/service.cpp b/test/bufstore/service.cpp new file mode 100644 index 0000000000..2942a984e9 --- /dev/null +++ b/test/bufstore/service.cpp @@ -0,0 +1,99 @@ +// This file is a part of the IncludeOS unikernel - www.includeos.org +// +// Copyright 2015 Oslo and Akershus University College of Applied Sciences +// and Alfred Bratterud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//#define DEBUG // Debug supression + +#include +#include +#include + +using namespace std; +using namespace net; + +constexpr size_t bufcount_ {100}; +BufferStore bufstore_{ bufcount_, 1500, 10 }; + +void Service::start() +{ + + INFO("Test net::Packet","Starting tests"); + + INFO("Test 1","Naively create, chain and release packets"); + + // Create a release delegate - i.e. the thing in charge of releasing packets + auto release = BufferStore::release_del::from + (bufstore_); + + // Create packets, using buffer from the bufstore, and the bufstore's release + auto packet = std::make_shared(bufstore_.get_offset_buffer(), + bufstore_.offset_bufsize(), 1500, release); + + CHECK(bufstore_.buffers_available() == bufcount_ - 1, "Bufcount is now %i", bufcount_ -1); + + int chain_size = bufcount_; + + // Chain packets + for (int i = 0; i < chain_size - 1; i++){ + auto chained_packet = std::make_shared(bufstore_.get_offset_buffer(), + bufstore_.offset_bufsize(), 1500, release); + packet->chain(chained_packet); + CHECK(bufstore_.buffers_available() == bufcount_ - i - 2 , "Bufcount is now %i", bufcount_ - i -2); + } + + + // Release + INFO("Test 1","Releaseing packet-chain all at once: Expect bufcount restored"); + packet = 0; + CHECK(bufstore_.buffers_available() == bufcount_ , "Bufcount is now %i", bufcount_); + + INFO("Test 2","Create and chain packets, release one-by-one"); + + // Reinitialize the first packet + packet = std::make_shared(bufstore_.get_offset_buffer(), + bufstore_.offset_bufsize(), 1500, release); + + CHECK(bufstore_.buffers_available() == bufcount_ - 1, "Bufcount is now %i", bufcount_ -1); + + // Chain + for (int i = 0; i < chain_size - 1; i++){ + auto chained_packet = std::make_shared(bufstore_.get_offset_buffer(), + bufstore_.offset_bufsize(), 1500, release); + packet->chain(chained_packet); + CHECK(bufstore_.buffers_available() == bufcount_ - i -2, "Bufcount is now %i", bufcount_ - i -2); + } + + INFO("Test 2","Releaseing packet-chain one-by-one"); + + // Release one-by-one + auto tail = packet; + size_t i = 0; + while(tail && i < bufcount_ - 1 ) { + tail = tail->detach_tail(); + CHECK(bufstore_.buffers_available() == i, + "Bufcount is now %i == %i", i, + bufstore_.buffers_available()); + i++; + } + + INFO("Test 2","Releaseing last packet"); + tail = 0; + packet = 0; + CHECK(bufstore_.buffers_available() == bufcount_ , "Bufcount is now %i", bufcount_); + + + +} diff --git a/test/bufstore/test.sh b/test/bufstore/test.sh new file mode 100755 index 0000000000..97187e5d5f --- /dev/null +++ b/test/bufstore/test.sh @@ -0,0 +1,4 @@ +#!/bin/bash +source ../test_base +make SERVICE=Test FILES=service.cpp +start test_transmit.img "Network Transmission Tests" From 7f041547f3645497321989ca2236585492bcf419 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 29 Mar 2016 21:43:02 +0200 Subject: [PATCH 068/311] Added README and test.sh to bufstore test --- test/bufstore/service.cpp | 19 ++++++++++--------- test/bufstore/test.sh | 5 +++-- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/test/bufstore/service.cpp b/test/bufstore/service.cpp index 2942a984e9..272875e72f 100644 --- a/test/bufstore/service.cpp +++ b/test/bufstore/service.cpp @@ -42,7 +42,7 @@ void Service::start() auto packet = std::make_shared(bufstore_.get_offset_buffer(), bufstore_.offset_bufsize(), 1500, release); - CHECK(bufstore_.buffers_available() == bufcount_ - 1, "Bufcount is now %i", bufcount_ -1); + CHECKSERT(bufstore_.buffers_available() == bufcount_ - 1, "Bufcount is now %i", bufcount_ -1); int chain_size = bufcount_; @@ -51,14 +51,14 @@ void Service::start() auto chained_packet = std::make_shared(bufstore_.get_offset_buffer(), bufstore_.offset_bufsize(), 1500, release); packet->chain(chained_packet); - CHECK(bufstore_.buffers_available() == bufcount_ - i - 2 , "Bufcount is now %i", bufcount_ - i -2); + CHECKSERT(bufstore_.buffers_available() == bufcount_ - i - 2 , "Bufcount is now %i", bufcount_ - i -2); } // Release INFO("Test 1","Releaseing packet-chain all at once: Expect bufcount restored"); packet = 0; - CHECK(bufstore_.buffers_available() == bufcount_ , "Bufcount is now %i", bufcount_); + CHECKSERT(bufstore_.buffers_available() == bufcount_ , "Bufcount is now %i", bufcount_); INFO("Test 2","Create and chain packets, release one-by-one"); @@ -66,34 +66,35 @@ void Service::start() packet = std::make_shared(bufstore_.get_offset_buffer(), bufstore_.offset_bufsize(), 1500, release); - CHECK(bufstore_.buffers_available() == bufcount_ - 1, "Bufcount is now %i", bufcount_ -1); + CHECKSERT(bufstore_.buffers_available() == bufcount_ - 1, "Bufcount is now %i", bufcount_ -1); // Chain for (int i = 0; i < chain_size - 1; i++){ auto chained_packet = std::make_shared(bufstore_.get_offset_buffer(), bufstore_.offset_bufsize(), 1500, release); packet->chain(chained_packet); - CHECK(bufstore_.buffers_available() == bufcount_ - i -2, "Bufcount is now %i", bufcount_ - i -2); + CHECKSERT(bufstore_.buffers_available() == bufcount_ - i -2, "Bufcount is now %i", bufcount_ - i -2); } - INFO("Test 2","Releaseing packet-chain one-by-one"); + INFO("Test 2","Releasing packet-chain one-by-one"); // Release one-by-one auto tail = packet; size_t i = 0; while(tail && i < bufcount_ - 1 ) { tail = tail->detach_tail(); - CHECK(bufstore_.buffers_available() == i, + CHECKSERT(bufstore_.buffers_available() == i, "Bufcount is now %i == %i", i, bufstore_.buffers_available()); i++; } - INFO("Test 2","Releaseing last packet"); + INFO("Test 2","Releasing last packet"); tail = 0; packet = 0; - CHECK(bufstore_.buffers_available() == bufcount_ , "Bufcount is now %i", bufcount_); + CHECKSERT(bufstore_.buffers_available() == bufcount_ , "Bufcount is now %i", bufcount_); + INFO("Tests","SUCCESS"); } diff --git a/test/bufstore/test.sh b/test/bufstore/test.sh index 97187e5d5f..be950c23ec 100755 --- a/test/bufstore/test.sh +++ b/test/bufstore/test.sh @@ -1,4 +1,5 @@ #!/bin/bash source ../test_base -make SERVICE=Test FILES=service.cpp -start test_transmit.img "Network Transmission Tests" + +make +start test_bufstore.img "Test bufstore" From ecd515472da7d90a8859121d4761cfa19fea97bd Mon Sep 17 00:00:00 2001 From: Zackary Ayoun Date: Mon, 14 Mar 2016 02:29:41 +0100 Subject: [PATCH 069/311] hw/ide: asynchronous reading now works properly * Added it's own irq_entry to allow irq registering during `Service::start()` * IRQ queue created in order to have the treatment properly done after `Service::start()` * Some fixes to allow the PIT to work even if the IDE irq is activated * Be carefull to make the difference between the irq number and the idt entry! --- api/hw/ide.hpp | 16 +++++---- src/hw/ide.cpp | 66 ++++++++++++++++++++++---------------- src/kernel/interrupts.s | 31 +++--------------- src/kernel/irq_manager.cpp | 4 +-- 4 files changed, 54 insertions(+), 63 deletions(-) diff --git a/api/hw/ide.hpp b/api/hw/ide.hpp index 0d6ac60c4f..9e4d3b2760 100644 --- a/api/hw/ide.hpp +++ b/api/hw/ide.hpp @@ -19,6 +19,7 @@ #define HW_IDE_HPP #include +#include #include "disk.hpp" #include "pci_device.hpp" @@ -30,8 +31,8 @@ class IDE : public IDiskDevice { public: enum selector_t { - MASTER, - SLAVE + MASTER = 0x00, + SLAVE = 0x10 }; /** @@ -58,17 +59,18 @@ class IDE : public IDiskDevice { virtual block_t size() const noexcept override { return _nb_blk; } + static void set_irq_mode(const bool on) noexcept; + + static void wait_status_busy() noexcept; + static void wait_status_flags(const int flags, const bool set) noexcept; + private: void set_drive(const uint8_t drive) const noexcept; void set_nbsectors(const uint8_t cnt) const noexcept; void set_blocknum(block_t blk) const noexcept; void set_command(const uint16_t command) const noexcept; - void set_irq_mode(const bool on) const noexcept; - - void wait_status_busy() const noexcept; - void wait_status_flags(const int flags, const bool set) const noexcept; - void irq_handler(); + void callback_wrapper(); void enable_irq_handler(); private: diff --git a/src/hw/ide.cpp b/src/hw/ide.cpp index 8f0245ea63..33dea422dc 100644 --- a/src/hw/ide.cpp +++ b/src/hw/ide.cpp @@ -38,15 +38,13 @@ #define IDE_CMD_WRITE 0x30 #define IDE_CMD_IDENTIFY 0xEC -#define IDE_MASTER 0x00 -#define IDE_SLAVE 0x10 - #define IDE_DRQ (1 << 3) #define IDE_DRDY (1 << 6) #define IDE_BUSY (1 << 7) #define IDE_CTRL_IRQ 0x3F6 #define IDE_IRQN 14 +#define IDE_BLKSZ 512 #define IDE_VENDOR_ID PCI_Device::VENDOR_INTEL #define IDE_PRODUCT_ID 0x7010 @@ -57,7 +55,7 @@ namespace hw { IDE::IDE(hw::PCI_Device& pcidev, selector_t sel) : _pcidev {pcidev}, - _drive {(uint8_t) ((sel == MASTER) ? 0 : 1)}, + _drive {(uint8_t)sel}, _iobase {0U}, _nb_blk {0U} { @@ -108,12 +106,19 @@ IDE::IDE(hw::PCI_Device& pcidev, selector_t sel) : INFO("IDE", "Initialization complete"); } -/** - * FIXME: this is a simple trick as we actually can't properly access the private - * members of the class during the IRQ handling... - */ -static IDE::on_read_func _callback = nullptr; // Current callback for asynchronous read -static int _nb_irqs = 0; // Number of IRQs that we expect +struct ide_irq { + ide_irq(uint8_t* buff, IDE::on_read_func call) + : buffer(buff) + , callback(call) + {} + + uint8_t* buffer; // Reading buffer + IDE::on_read_func callback; // IRQ callback +}; + +static int _nb_irqs = 0; // Number of IRQs that we expect +static IDE::on_read_func _current_callback = nullptr; // Callback for the current irq +static std::list _ide_irqs; // IRQ queue void IDE::read(block_t blk, on_read_func callback) { if (blk >= _nb_blk) { @@ -122,16 +127,13 @@ void IDE::read(block_t blk, on_read_func callback) { return; } - callback(read_sync(blk)); - return; - set_irq_mode(true); set_drive(0xE0 | (_drive << 4) | ((blk >> 24) & 0x0F)); set_nbsectors(1); set_blocknum(blk); set_command(IDE_CMD_READ); - _callback = callback; + _current_callback = callback; _nb_irqs = 1; } @@ -149,7 +151,7 @@ void IDE::read(block_t blk, block_t count, on_read_func callback) set_blocknum(blk); set_command(IDE_CMD_READ); - _callback = callback; + _current_callback = callback; _nb_irqs = count; } @@ -179,12 +181,12 @@ IDE::buffer_t IDE::read_sync(block_t blk) return buffer_t(buffer, std::default_delete()); } -void IDE::wait_status_busy() const noexcept { +void IDE::wait_status_busy() noexcept { uint8_t ret; while (((ret = inb(IDE_STATUS)) & IDE_BUSY) == IDE_BUSY); } -void IDE::wait_status_flags(const int flags, const bool set) const noexcept { +void IDE::wait_status_flags(const int flags, const bool set) noexcept { wait_status_busy(); auto ret = inb(IDE_STATUS); @@ -228,37 +230,47 @@ void IDE::set_command(const uint16_t command) const noexcept { outb(IDE_CMD, command); } -void IDE::set_irq_mode(const bool on) const noexcept { +void IDE::set_irq_mode(const bool on) noexcept { wait_status_flags(IDE_DRDY, false); outb(IDE_CTRL_IRQ, on ? 0 : 1); } -void IDE::irq_handler() { - if (!_nb_irqs || _callback == nullptr) { - set_irq_mode(false); +extern "C" void ide_irq_handler() { + if (!_nb_irqs || _current_callback == nullptr) { + IDE::set_irq_mode(false); IRQ_manager::eoi(IDE_IRQN); return; } - auto* buffer = new uint8_t[block_size()]; + uint8_t* buffer = new uint8_t[IDE_BLKSZ]; - wait_status_flags(IDE_DRDY, false); + IDE::wait_status_flags(IDE_DRDY, false); uint16_t* wptr = (uint16_t*) buffer; - for (block_t i = 0; i < block_size() / sizeof (uint16_t); ++i) + for (IDE::block_t i = 0; i < IDE_BLKSZ / sizeof (uint16_t); ++i) wptr[i] = inw(IDE_DATA); - _callback(buffer_t(buffer, std::default_delete())); + _ide_irqs.push_back(ide_irq(buffer, _current_callback)); _nb_irqs--; + IRQ_manager::register_interrupt(IDE_IRQN); IRQ_manager::eoi(IDE_IRQN); } +extern "C" void ide_irq_entry(); + +void IDE::callback_wrapper() +{ + IDE::on_read_func callback = _ide_irqs.front().callback; + callback(IDE::buffer_t(_ide_irqs.front().buffer, std::default_delete())); + _ide_irqs.pop_front(); +} + void IDE::enable_irq_handler() { - auto del(delegate::from(this)); - IRQ_manager::enable_irq(IDE_IRQN); + auto del(delegate::from(this)); IRQ_manager::subscribe(IDE_IRQN, del); + IRQ_manager::set_handler(IDE_IRQN + 32, ide_irq_entry); } } //< namespace hw diff --git a/src/kernel/interrupts.s b/src/kernel/interrupts.s index 0a4f4a69cf..971fb1113a 100644 --- a/src/kernel/interrupts.s +++ b/src/kernel/interrupts.s @@ -46,6 +46,8 @@ .global irq_15_entry .global cpu_sampling_irq_entry +.global ide_irq_entry +.extern ide_irq_handler /* @@ -84,37 +86,14 @@ IRQ irq_13_entry irq_13_handler IRQ irq_14_entry irq_14_handler IRQ irq_15_entry irq_15_handler +IRQ ide_irq_entry ide_irq_handler +IRQ cpu_sampling_irq_entry cpu_sampling_irq_handler +IRQ irq_default_entry irq_default_handler exception_13_entry: cli call exception_13_handler - -cpu_sampling_irq_entry: - cli - pusha - call cpu_sampling_irq_handler - popa - sti - iret - - -irq_default_entry: - cli - pusha - call irq_default_handler - popa - sti - iret - - -//Send EOI for the timer -// movb PIC_PORT, %al -// movw SIG_EOI, %dx -// outb %al, %dx - - - irq_timer_entry: cli diff --git a/src/kernel/irq_manager.cpp b/src/kernel/irq_manager.cpp index 376b4ef331..5cc5859d96 100644 --- a/src/kernel/irq_manager.cpp +++ b/src/kernel/irq_manager.cpp @@ -219,8 +219,6 @@ void IRQ_manager::init() //Initialize the interrupt controller hw::PIC::init(); - - enable_irq(2); //Slave PIC irq enable_interrupts(); } @@ -254,7 +252,7 @@ void IRQ_manager::set_handler(uint8_t irq, void(*function_addr)()) { * previous interrupts won't have reported EOI and new handler * will never get called */ - eoi(irq); + eoi(irq - irq_base); } void (*IRQ_manager::get_handler(uint8_t irq))() { From 426beed3a72882e2887b6bc53e5210a16653924e Mon Sep 17 00:00:00 2001 From: Zackary Ayoun Date: Mon, 14 Mar 2016 02:33:46 +0100 Subject: [PATCH 070/311] test/IDE: tests updated --- test/IDE/service.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/test/IDE/service.cpp b/test/IDE/service.cpp index e607b2acb8..2639c6e95e 100644 --- a/test/IDE/service.cpp +++ b/test/IDE/service.cpp @@ -25,7 +25,7 @@ void Service::start() { printf("TESTING Disks\n\n"); - auto ide = hw::Dev::disk<0, hw::IDE>(); + auto ide = hw::Dev::disk<0, hw::IDE>(hw::IDE::MASTER); printf("Name : %s\n", ide.name()); printf("Size : %llu\n\n", ide.size()); @@ -44,4 +44,17 @@ void Service::start() printf("\n"); i++; }); + + printf("Reading sync:\n"); + mbr = (fs::MBR::mbr*)ide.read_sync(0).get(); + printf("Name: %.8s\n", mbr->oem_name); + printf("MAGIC sig: 0x%x\n\n", mbr->magic); + + ide.read(4, [] (hw::IDE::buffer_t data) { + uint8_t* buf = (uint8_t*)data.get(); + printf("Async read, Block %d:\n", 4); + for (int i = 0; i < 512; i++) + printf("%x ", buf[i]); + printf("\n"); + }); } From 2aa41635842efda18a4c96f5188c3a2ed33e0fdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Wed, 30 Mar 2016 18:31:09 +0200 Subject: [PATCH 071/311] terminal: updated to reflect changes in tcp --- src/kernel/terminal.cpp | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/src/kernel/terminal.cpp b/src/kernel/terminal.cpp index a0c3145255..fdf629547b 100644 --- a/src/kernel/terminal.cpp +++ b/src/kernel/terminal.cpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -25,26 +25,29 @@ Terminal::Terminal(Connection_ptr csock) : iac(false), newline(false), subcmd(0) { - csock->onReceive( + csock->read(1024, [this](auto, auto& buffer, bool){ + this->read((char*)buffer.begin(), buffer.size()); + }); + /*csock->onReceive( [this] (auto conn, bool) { char buffer[1024]; size_t bytes = conn->read(buffer, sizeof(buffer)); - + this->read(buffer, bytes); - }); - - on_write = + });*/ + + on_write = [csock] (const char* buffer, size_t len) { csock->write(buffer, len); }; - - on_exit = + + on_exit = [csock] { csock->close(); }; - + add_basic_commands(); intro(); } @@ -160,7 +163,7 @@ split(const std::string& text, std::string& command) { x = text.find(" ", p+1); size_t y = text.find(":", x+1); // find last param - + if (y == x+1) { // single argument @@ -180,9 +183,9 @@ split(const std::string& text, std::string& command) retv.push_back(text.substr(p)); } p = x+1; - + } while (x != std::string::npos); - + return retv; } @@ -193,7 +196,7 @@ void Terminal::run(const std::string& cmd_string) if (cmd_name.size()) { printf("Terminal::run(): %s\n", cmd_name.c_str()); - + auto it = commands.find(cmd_name); if (it != commands.end()) { @@ -229,11 +232,11 @@ void Terminal::add_basic_commands() this->on_exit(); return 0; }); - + } void Terminal::intro() { - std::string banana = + std::string banana = R"baaa( ____ ___ | _ \ ___ _ _.' _ `. @@ -248,10 +251,10 @@ void Terminal::intro() `..:;::;:.. ::;::;:;:;, :;::;' "-:;::;:;: ':;::;:'' ;.-' ""`---...________...---'"" - + > Banana Terminal v1 < )baaa"; - + write("%s", banana.c_str()); prompt(); } From 099715f369602c53fc7c27b16b1304f79e65ef27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Wed, 30 Mar 2016 19:09:06 +0200 Subject: [PATCH 072/311] tcp: hooked up to transmit queue event fed4289 --- src/net/tcp.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/net/tcp.cpp b/src/net/tcp.cpp index c141fb74d7..d58f9da6c1 100644 --- a/src/net/tcp.cpp +++ b/src/net/tcp.cpp @@ -30,7 +30,7 @@ TCP::TCP(IPStack& inet) : write_queue(), MAX_SEG_LIFETIME(30s) { - + inet.on_transmit_queue_available(transmit_avail_delg::from(this)); } /* @@ -198,8 +198,7 @@ size_t TCP::send(Connection_ptr conn, Connection::WriteBuffer& buffer) { size_t written{0}; if(write_queue.empty()) { - //auto packets = inet_->free_packets(); - size_t packets = 10; + auto packets = inet_.transmit_queue_available(); written = conn->send(buffer, packets); } From de7cb723740a67885ca85d90c2101360abb57d64 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Thu, 31 Mar 2016 15:09:44 +0200 Subject: [PATCH 073/311] cxxabi: Silence unused inline function warning --- src/crt/cxxabi/cxa_guard.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/crt/cxxabi/cxa_guard.cpp b/src/crt/cxxabi/cxa_guard.cpp index 1b4191713e..6e447de3c1 100644 --- a/src/crt/cxxabi/cxa_guard.cpp +++ b/src/crt/cxxabi/cxa_guard.cpp @@ -28,6 +28,8 @@ namespace __cxxabiv1 { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" namespace { @@ -162,6 +164,7 @@ set_lock(uint32_t& x, lock_type y) #endif // __APPLE__ } // unnamed namespace +#pragma GCC diagnostic pop extern "C" { From eda74cc503dc1fc2eacae0b7f113a5afff49cf05 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Thu, 31 Mar 2016 15:12:14 +0200 Subject: [PATCH 074/311] Updated transmission test to wait for ARP-resolution. Fix #456 --- test/transmit/service.cpp | 49 ++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/test/transmit/service.cpp b/test/transmit/service.cpp index dd7a2edfdd..9992ab4442 100644 --- a/test/transmit/service.cpp +++ b/test/transmit/service.cpp @@ -34,6 +34,7 @@ void Service::start() auto& mac = eth0.mac(); inet = std::make_shared>(eth0); + auto& timer = hw::PIT::instance(); inet->network_config({{ mac.part[2],mac.part[3],mac.part[4],mac.part[5] }}, {{ 255,255,0,0 }}, // Netmask @@ -46,41 +47,61 @@ void Service::start() UDP::port_t port = 4242; auto& sock = inet->udp().bind(port); - sock.onRead([] (UDP::Socket& conn, UDP::addr_t addr, UDP::port_t port, + sock.onRead([&] (UDP::Socket& conn, UDP::addr_t addr, UDP::port_t port, const char* data, int len) -> int { - INFO("Test 2","Starting UDP-test (got UDP data from %s: %i: %s", - addr.str().c_str(), port, data); - // send the same thing right back! + string received = std::string(data,len-1); + INFO("Test 2","Starting UDP-test (got UDP data from %s: %i: '%s')", + addr.str().c_str(), port, received.c_str()); + const int packets { 600 }; - INFO("TEST 2", "Trying to transmit %i UDP packets at maximum throttle", packets); - for (int i = 0; i < packets; i++) - conn.sendto(addr, port, data, len); + string first_reply {string("Received '") + received + + "'. Expect " + to_string(packets) + " packets in 1s\n" }; + + // Send the first packet, and then wait for ARP + conn.sendto(addr, port, first_reply.c_str(), first_reply.size()); + + timer.onTimeout(1s, [&conn, addr, port, data, len]() { + INFO("Test 2", "Trying to transmit %i UDP packets at maximum throttle", packets); + auto bufcount = inet->buffers_available(); + + for (int i = 0; i < packets; i++) + conn.sendto(addr, port, data, len); + + CHECK(1,"UDP-transmission didn't panic"); + auto bufcount2 = inet->buffers_available(); + + CHECKSERT(bufcount2 < bufcount, + "%i buffers available after transmission (Had %i). ", + bufcount2, bufcount); + + INFO("Transmision tests","SUCCESS"); + }); + return 0; + }); eth0.on_transmit_queue_available([](size_t s){ - CHECK(1,"There are now %i available buffers", s); + CHECKSERT(s,"There is now room for %i packets in transmit queue", s); }); - hw::PIT::instance().onTimeout(200ms,[=](){ + timer.onTimeout(200ms,[=](){ const int packets { 600 }; - INFO("TEST 1", "Trying to transmit %i ethernet packets at maximum throttle", packets); + INFO("Test 1", "Trying to transmit %i ethernet packets at maximum throttle", packets); for (int i=0; i < packets; i++){ auto pckt = inet->createPacket(inet->MTU()); Ethernet::header* hdr = reinterpret_cast(pckt->buffer()); hdr->dest.major = Ethernet::addr::BROADCAST_FRAME.major; hdr->dest.minor = Ethernet::addr::BROADCAST_FRAME.minor; hdr->type = Ethernet::ETH_ARP; - printf("\t Transmit Queue available: %i \n", - inet->transmit_queue_available()); - printf("\t Bufstore available: %i \n", - inet->buffers_available()); inet->link().transmit(pckt); } CHECK(1,"Transmission didn't panic"); + INFO("Test 1", "Done. Send some UDP-data to %s:%i to continue test", + inet->ip_addr().str().c_str(), port); }); From c28f8665cdf1fb5f19f3fe61c13a1d4ff358ee1f Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Thu, 31 Mar 2016 15:38:36 +0200 Subject: [PATCH 075/311] Tell people how to connect to terminalt --- test/term/term.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/test/term/term.cpp b/test/term/term.cpp index 0450b5752f..58fb7db560 100644 --- a/test/term/term.cpp +++ b/test/term/term.cpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -37,17 +37,17 @@ void Service::start() {{ 255,255,255,0 }}, // Netmask {{ 10,0,0,1 }}, // Gateway {{ 8,8,8,8 }} ); // DNS - + INFO("TERM", "Running tests for Terminal"); auto disk = fs::new_shared_memdisk(); assert(disk); - + // auto-mount filesystem disk->mount( [disk] (fs::error_t err) { assert(!err); - + /// terminal /// #define SERVICE_TELNET 23 auto& tcp = inet->tcp(); @@ -59,6 +59,9 @@ void Service::start() term = std::make_unique (client); term->add_disk_commands(disk); }); + + INFO("TERM", "Connect to terminal with $ telnet %s ", + inet->ip_addr().str().c_str()); /// terminal /// }); } From a257c71ab27cb906c1f8e162b2a8e7e0e0e83cdb Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Thu, 31 Mar 2016 21:04:58 +0200 Subject: [PATCH 076/311] fs: Fixes #457 for now --- api/fs/fat.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/fs/fat.hpp b/api/fs/fat.hpp index 424ce4e19e..132426d3d5 100644 --- a/api/fs/fat.hpp +++ b/api/fs/fat.hpp @@ -151,9 +151,9 @@ namespace fs } __attribute__((packed)); // helper functions - uint32_t cl_to_sector(uint32_t cl) + uint32_t cl_to_sector(uint32_t const cl) { - if (cl == 0) + if (cl <= 2) return lba_base + data_index + (this->root_cluster - 2) * sectors_per_cluster - this->root_dir_sectors; else return lba_base + data_index + (cl - 2) * sectors_per_cluster; From d69c752f200c4b7b0363cfe6f85c400e1f893eb9 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Thu, 31 Mar 2016 21:11:03 +0200 Subject: [PATCH 077/311] Fixed #444 --- test/exceptions/README.md | 5 +++++ test/exceptions/service.cpp | 40 ++++++++++++++++++------------------- test/exceptions/test.sh | 5 +++++ 3 files changed, 30 insertions(+), 20 deletions(-) create mode 100644 test/exceptions/README.md create mode 100755 test/exceptions/test.sh diff --git a/test/exceptions/README.md b/test/exceptions/README.md new file mode 100644 index 0000000000..fe988f440e --- /dev/null +++ b/test/exceptions/README.md @@ -0,0 +1,5 @@ +# Test exceptions + +Exceptions are usually taken for granted, but they require proper unwinding, which is not itself a part of the standard C++ library. + +These tests are internal only, so just running `test.sh` should be enough, and the output will be self explanatory. diff --git a/test/exceptions/service.cpp b/test/exceptions/service.cpp index 15a0123cce..7995016eff 100644 --- a/test/exceptions/service.cpp +++ b/test/exceptions/service.cpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -25,11 +25,11 @@ class CustomException : public std::runtime_error { void Service::start() { - + printf("TESTING Exceptions \n"); - + const char* error_msg = "Crazy Error!"; - + try { printf("[x] Inside try-block \n"); if (OS::uptime() > 0.1){ @@ -38,31 +38,31 @@ void Service::start() } }catch(std::runtime_error e){ - + printf("[%s] Caught runtime error: %s \n", std::string(e.what()) == std::string(error_msg) ? "x" : " " ,e.what()); - + }catch(...) { - + printf("[ ] Caught something - but not what we expected \n"); - + } - + std::string custom_msg = "Custom exceptions are useful"; - std::string cought_msg = ""; - + std::string caught_msg = ""; + try { // Trying to throw a custom exception throw CustomException(custom_msg); } catch (CustomException e){ - - cought_msg = e.what(); - + + caught_msg = e.what(); + } catch (...) { - + printf("[ ] Couldn't catch custom exception \n"); - + } - - assert(cought_msg == custom_msg); - printf("[x] Cought custom exception \n"); + + assert(caught_msg == custom_msg); + printf("[x] Caught custom exception \n"); } diff --git a/test/exceptions/test.sh b/test/exceptions/test.sh new file mode 100755 index 0000000000..afcad2103a --- /dev/null +++ b/test/exceptions/test.sh @@ -0,0 +1,5 @@ +#!/bin/bash +source ../test_base + +make +start test_exceptions.img From 5d45698118d49dc6a59300177cc8a7568aac1296 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Thu, 31 Mar 2016 21:22:43 +0200 Subject: [PATCH 078/311] Updated CRT-test, fix #443 --- test/crt/Makefile | 2 +- test/crt/README.md | 7 +++++++ test/crt/service.cpp | 48 ++++++++++++++++++++------------------------ 3 files changed, 30 insertions(+), 27 deletions(-) create mode 100644 test/crt/README.md diff --git a/test/crt/Makefile b/test/crt/Makefile index c662fdfbae..fb4fbda02d 100644 --- a/test/crt/Makefile +++ b/test/crt/Makefile @@ -3,7 +3,7 @@ ################################################# # The name of your service -SERVICE = Test_crt +SERVICE = test_crt SERVICE_NAME = C runtime test # Your service parts diff --git a/test/crt/README.md b/test/crt/README.md new file mode 100644 index 0000000000..20ed16402c --- /dev/null +++ b/test/crt/README.md @@ -0,0 +1,7 @@ +# Test C runtime +Essentially this tests global constructors, which needs crti.o, crtn.o etc. to be linked in properly to work. + +Internal test, self-explanatory output. + +Success: Outputs SUCCESS +Fail: Panic diff --git a/test/crt/service.cpp b/test/crt/service.cpp index c4f0d0f99a..7459772e22 100644 --- a/test/crt/service.cpp +++ b/test/crt/service.cpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,24 +16,25 @@ // limitations under the License. #include +#include class global { static int i; public: global(){ - printf("[*] Global constructor printing %i \n",++i); + CHECK(1,"Global constructor printing %i",++i); } - + void test(){ - printf("[*] C++ constructor finds %i instances \n",i); + CHECK(1,"C++ constructor finds %i instances",i); } - + int instances(){ return i; } - + ~global(){ - printf("[*] C++ destructor deleted 1 instance, %i remains \n",--i); + CHECK(1,"C++ destructor deleted 1 instance, %i remains",--i); } - + }; @@ -53,25 +54,20 @@ __attribute__ ((constructor)) void foo(void) void Service::start() { - - printf("TESTING C runtime \n"); - - printf("[%s] Global C constructors in service \n", - _test_glob3 == 0xfa7ca7 ? "x" : " "); - - printf("[%s] Global int initialization in service \n", - _test_glob2 == 1 ? "x" : " "); - - + + INFO("Test CRT","Testing C runtime \n"); + + CHECKSERT(_test_glob3 == 0xfa7ca7, "Global C constructors in service"); + CHECKSERT(_test_glob2 == 1, "Global int initialization in service"); + global* glob2 = new global();; glob1.test(); - printf("[%s] Local C++ constructors in service \n", glob1.instances() == 2 ? "x" : " "); + CHECKSERT(glob1.instances() == 2, "Local C++ constructors in service"); - delete glob2; - printf("[%s] C++ destructors in service \n", glob1.instances() == 1 ? "x" : " "); - - - - + CHECKSERT(glob1.instances() == 1, "C++ destructors in service"); + + + INFO("Test CRT", "SUCCESS"); + } From d9e7da7d816ded1fa0a1c78741c4fadc89b8d5e3 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Thu, 31 Mar 2016 21:24:28 +0200 Subject: [PATCH 079/311] Added explicit Success / Fail description --- test/exceptions/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/exceptions/README.md b/test/exceptions/README.md index fe988f440e..24b8991b42 100644 --- a/test/exceptions/README.md +++ b/test/exceptions/README.md @@ -3,3 +3,6 @@ Exceptions are usually taken for granted, but they require proper unwinding, which is not itself a part of the standard C++ library. These tests are internal only, so just running `test.sh` should be enough, and the output will be self explanatory. + +Sucess: Outputs SUCCESS if all tests pass +Fail: Panic if any test fails From 42388a1b6df0b5d524ecdebe123656cd2ed1d9b2 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Thu, 31 Mar 2016 22:52:33 +0200 Subject: [PATCH 080/311] test: Update FAT tests to use CHECKSERT --- src/seed/Makefile | 2 +- test/fat/fat16.cpp | 34 ++++++++++++---------------- test/fat/fat32.cpp | 56 ++++++++++++++++------------------------------ 3 files changed, 34 insertions(+), 58 deletions(-) diff --git a/src/seed/Makefile b/src/seed/Makefile index 4687746ad0..fd2e3e338d 100644 --- a/src/seed/Makefile +++ b/src/seed/Makefile @@ -138,7 +138,7 @@ crt%.o: $(INSTALL)/crt/crt%.s # General C++-files to object files %.o: %.cpp - @echo "\n>> Compiling OS object without header" + @echo "\n>> Compiling $<..." $(CPP) $(CPPOPTS) -o $@ $< # AS-assembled object files diff --git a/test/fat/fat16.cpp b/test/fat/fat16.cpp index a912a85432..7e7197d0c0 100644 --- a/test/fat/fat16.cpp +++ b/test/fat/fat16.cpp @@ -28,50 +28,44 @@ void Service::start() assert(disk); // verify that the size is indeed N sectors - CHECK(disk->dev().size() == 16500, "Disk size 16500 sectors"); - assert(disk->dev().size() == 16500); + CHECKSERT(disk->dev().size() == 16500, "Disk size 16500 sectors"); // which means that the disk can't be empty - CHECK(!disk->empty(), "Disk not empty"); - assert(!disk->empty()); + CHECKSERT(!disk->empty(), "Disk not empty"); // auto-mount filesystem disk->mount( [disk] (fs::error_t err) { - CHECK(!err, "Filesystem auto-mounted"); - assert(!err); + CHECKSERT(!err, "Filesystem auto-mounted"); auto& fs = disk->fs(); printf("\t\t%s filesystem\n", fs.name().c_str()); auto vec = fs::new_shared_vector(); err = fs.ls("/", vec); - CHECK(!err, "List root directory"); - assert(!err); + CHECKSERT(!err, "List root directory"); - CHECK(vec->size() == 1, "Exactly one ent in root dir"); - assert(vec->size() == 1); + CHECKSERT(vec->size() == 1, "Exactly one ent in root dir"); auto& e = vec->at(0); - CHECK(e.is_file(), "Ent is a file"); - CHECK(e.name() == "banana.txt", "Ent is 'banana.txt'"); + CHECKSERT(e.is_file(), "Ent is a file"); + CHECKSERT(e.name() == "banana.txt", "Ents name is 'banana.txt'"); }); // re-mount on VBR1 disk->mount(disk->VBR1, [disk] (fs::error_t err) { - CHECK(!err, "Filesystem mounted on VBR1"); - assert(!err); + CHECKSERT(!err, "Filesystem mounted on VBR1"); // verify that we can read file auto& fs = disk->fs(); auto ent = fs.stat("/banana.txt"); - CHECK(ent.is_valid(), "Stat file in root dir"); - CHECK(ent.is_file(), "Entity is file"); - CHECK(!ent.is_dir(), "Entity is not directory"); - CHECK(ent.name() == "banana.txt", "Name is 'banana.txt'"); + CHECKSERT(ent.is_valid(), "Stat file in root dir"); + CHECKSERT(ent.is_file(), "Entity is file"); + CHECKSERT(!ent.is_dir(), "Entity is not directory"); + CHECKSERT(ent.name() == "banana.txt", "Name is 'banana.txt'"); // try reading banana-file auto buf = fs.read(ent, 0, ent.size); @@ -93,11 +87,11 @@ void Service::start() ""`---...________...---'"" )"; printf("%s\n", internal_banana.c_str()); - CHECK(banana == internal_banana, "Correct banana #1"); + CHECKSERT(banana == internal_banana, "Correct banana #1"); buf = fs.readFile("/banana.txt"); banana = std::string((char*) buf.buffer.get(), buf.len); - CHECK(banana == internal_banana, "Correct banana #2"); + CHECKSERT(banana == internal_banana, "Correct banana #2"); }); INFO("FAT16", "SUCCESS"); diff --git a/test/fat/fat32.cpp b/test/fat/fat32.cpp index 972652e3bf..c8e560e964 100644 --- a/test/fat/fat32.cpp +++ b/test/fat/fat32.cpp @@ -48,34 +48,29 @@ void Service::start() // verify that the size is indeed N sectors const size_t SIZE = 4194304; - CHECK(disk->dev().size() == SIZE, "Disk size 4194304 sectors"); - assert(disk->dev().size() == SIZE); + CHECKSERT(disk->dev().size() == SIZE, "Disk size 4194304 sectors"); // which means that the disk can't be empty - CHECK(!disk->empty(), "Disk not empty"); - assert(!disk->empty()); + CHECKSERT(!disk->empty(), "Disk not empty"); // auto-mount filesystem disk->mount(disk->MBR, [] (fs::error_t err) { - CHECK(!err, "Filesystem auto-mounted"); - assert(!err); + CHECKSERT(!err, "Filesystem auto-mounted"); auto& fs = disk->fs(); printf("\t\t%s filesystem\n", fs.name().c_str()); auto vec = fs::new_shared_vector(); err = fs.ls("/", vec); - CHECK(!err, "List root directory"); - assert(!err); + CHECKSERT(!err, "List root directory"); - CHECK(vec->size() == 2, "Exactly two ents in root dir"); - assert(vec->size() == 2); + CHECKSERT(vec->size() == 2, "Exactly two ents in root dir"); auto& e = vec->at(0); - CHECK(e.is_file(), "Ent is a file"); - CHECK(e.name() == "banana.txt", "Ent is 'banana.txt'"); + CHECKSERT(e.is_file(), "Ent is a file"); + CHECKSERT(e.name() == "banana.txt", "Ents name is 'banana.txt'"); }); // re-mount on VBR1 disk->mount(disk->VBR1, @@ -86,30 +81,17 @@ void Service::start() auto& fs = disk->fs(); auto ent = fs.stat("/banana.txt"); - CHECK(ent.is_valid(), "Stat file in root dir"); - assert(ent.is_valid()); - - CHECK(ent.is_file(), "Entity is file"); - assert(ent.is_file()); - - CHECK(!ent.is_dir(), "Entity is not directory"); - assert(!ent.is_dir()); - - CHECK(ent.name() == "banana.txt", "Name is 'banana.txt'"); - assert(ent.name() == "banana.txt"); + CHECKSERT(ent.is_valid(), "Stat file in root dir"); + CHECKSERT(ent.is_file(), "Entity is file"); + CHECKSERT(!ent.is_dir(), "Entity is not directory"); + CHECKSERT(ent.name() == "banana.txt", "Name is 'banana.txt'"); ent = fs.stat("/dir1/dir2/dir3/dir4/dir5/dir6/banana.txt"); - CHECK(ent.is_valid(), "Stat file in deep dir"); - assert(ent.is_valid()); - - CHECK(ent.is_file(), "Entity is file"); - assert(ent.is_file()); - - CHECK(!ent.is_dir(), "Entity is not directory"); - assert(!ent.is_dir()); + CHECKSERT(ent.is_valid(), "Stat file in deep dir"); + CHECKSERT(ent.is_file(), "Entity is file"); + CHECKSERT(!ent.is_dir(), "Entity is not directory"); - CHECK(ent.name() == "banana.txt", "Name is 'banana.txt'"); - assert(ent.name() == "banana.txt"); + CHECKSERT(ent.name() == "banana.txt", "Name is 'banana.txt'"); printf("%s\n", internal_banana.c_str()); @@ -117,26 +99,26 @@ void Service::start() fs.read(ent, 0, ent.size, [&fs] (fs::error_t err, fs::buffer_t buf, uint64_t len) { - CHECK(!err, "read: Read 'banana.txt' asynchronously"); + CHECKSERT(!err, "read: Read 'banana.txt' asynchronously"); if (err) { panic("Failed to read file async"); } std::string banana((char*) buf.get(), len); - CHECK(banana == internal_banana, "Correct banana #1"); + CHECKSERT(banana == internal_banana, "Correct banana #1"); fs.readFile("/banana.txt", [&fs] (fs::error_t err, fs::buffer_t buf, uint64_t len) { - CHECK(!err, "readFile: Read 'banana.txt' asynchronously"); + CHECKSERT(!err, "readFile: Read 'banana.txt' asynchronously"); if (err) { panic("Failed to read file async"); } std::string banana((char*) buf.get(), len); - CHECK(banana == internal_banana, "Correct banana #2"); + CHECKSERT(banana == internal_banana, "Correct banana #2"); }); }); }); From 30f58a7a12b1248d74ec8f19464682f4fc1cc520 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Thu, 31 Mar 2016 23:02:36 +0200 Subject: [PATCH 081/311] test: CHECKSERT on terminal test --- test/term/term.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/term/term.cpp b/test/term/term.cpp index 58fb7db560..a1710ff0fe 100644 --- a/test/term/term.cpp +++ b/test/term/term.cpp @@ -46,8 +46,8 @@ void Service::start() disk->mount( [disk] (fs::error_t err) { - assert(!err); - + CHECKSERT(!err, "Filesystem auto-mounted"); + /// terminal /// #define SERVICE_TELNET 23 auto& tcp = inet->tcp(); From fb778db03b194d8e6ce3da9ede1d8d56af99c321 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Thu, 31 Mar 2016 23:17:06 +0200 Subject: [PATCH 082/311] test: FAT read every byte for random access read --- src/fs/fat_sync.cpp | 2 +- test/fat/fat16.cpp | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/fs/fat_sync.cpp b/src/fs/fat_sync.cpp index 6a446d3712..6661104929 100644 --- a/src/fs/fat_sync.cpp +++ b/src/fs/fat_sync.cpp @@ -31,7 +31,7 @@ namespace fs // keep track of total bytes uint64_t total = n; // calculate bytes to read before moving on to next sector - uint32_t rest = device.block_size() - (pos - internal_ofs); + uint32_t rest = device.block_size() - internal_ofs; // if what we want to read is larger than the rest, exit early if (rest > n) diff --git a/test/fat/fat16.cpp b/test/fat/fat16.cpp index 7e7197d0c0..3777431b5c 100644 --- a/test/fat/fat16.cpp +++ b/test/fat/fat16.cpp @@ -89,6 +89,23 @@ void Service::start() printf("%s\n", internal_banana.c_str()); CHECKSERT(banana == internal_banana, "Correct banana #1"); + bool test = true; + + for (size_t i = 0; i < internal_banana.size(); i++) + { + // read one byte at a time + buf = fs.read(ent, i, 1); + + // verify that it matches the same location in test-string + test = ((char) buf.buffer.get()[0] == internal_banana[i]); + if (!test) + { + printf("!! Random access read test failed on i = %u\n", i); + break; + } + } + CHECKSERT(test, "Validate random access sync read"); + buf = fs.readFile("/banana.txt"); banana = std::string((char*) buf.buffer.get(), buf.len); CHECKSERT(banana == internal_banana, "Correct banana #2"); From 1e3aa244e1955cb15f94cac65e797266aee4eea5 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Fri, 1 Apr 2016 09:07:37 +0200 Subject: [PATCH 083/311] Minor updates to UDP test --- test/UDP/Makefile | 4 ++-- test/UDP/service.cpp | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/test/UDP/Makefile b/test/UDP/Makefile index 3a9cc498c1..ddce4f3bb1 100644 --- a/test/UDP/Makefile +++ b/test/UDP/Makefile @@ -3,8 +3,8 @@ ################################################# # The name of your service -SERVICE = "Test_UDP" -SERVICE_NAME = "IncludeOS\ UDP\ test" +SERVICE = test_udp +SERVICE_NAME = IncludeOS UDP test # Your service parts FILES = service.cpp diff --git a/test/UDP/service.cpp b/test/UDP/service.cpp index f789db5da5..a4c9ae1480 100644 --- a/test/UDP/service.cpp +++ b/test/UDP/service.cpp @@ -43,15 +43,16 @@ void Service::start() UDP::port_t port = 4242; auto& sock = inet.udp().bind(port); - sock.onRead([] (UDP::Socket& conn, UDP::addr_t addr, UDP::port_t port, const char* data, int len) -> int + sock.onRead([] (UDP::Socket& conn, UDP::addr_t addr, UDP::port_t port, + const char* data, int len) -> int { - printf("Getting UDP data from %s: %i: %s\n", - addr.str().c_str(), port, data); + CHECK(1,"Getting UDP data from %s: %i: %s", + addr.str().c_str(), port, data); // send the same thing right back! conn.sendto(addr, port, data, len); return 0; }); - printf("UDP server listening to port %i \n",port); + INFO("UDP test", "listening to %i \n",port); } From 0139ea032ad739c21e11371c9c78b89325696de0 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Fri, 1 Apr 2016 09:08:26 +0200 Subject: [PATCH 084/311] Explicit fail/success description --- test/crt/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/crt/README.md b/test/crt/README.md index 20ed16402c..00e32646f9 100644 --- a/test/crt/README.md +++ b/test/crt/README.md @@ -3,5 +3,5 @@ Essentially this tests global constructors, which needs crti.o, crtn.o etc. to b Internal test, self-explanatory output. -Success: Outputs SUCCESS -Fail: Panic +Success: Outputs SUCCESS if all tests pass +Fail: Panic on any failed tests From de3ca91b8df08a74454c7d4c386e5e04f082ddcc Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Fri, 1 Apr 2016 09:53:56 +0200 Subject: [PATCH 085/311] Editorconfig / indentation Nuke --- api/fs/common.hpp | 10 +- api/fs/disk.hpp | 124 +- api/fs/ext4.hpp | 20 +- api/fs/fat.hpp | 20 +- api/fs/filesystem.hpp | 168 +- api/fs/mbr.hpp | 84 +- api/fs/memdisk.hpp | 42 +- api/fs/path.hpp | 108 +- api/fs/vbr.hpp | 4 +- api/hw/dev.hpp | 94 +- api/hw/disk.hpp | 82 +- api/hw/disk_device.hpp | 52 +- api/hw/ide.hpp | 84 +- api/hw/pci.hpp | 88 +- api/hw/pci_device.hpp | 396 ++--- api/hw/pic.hpp | 22 +- api/hw/pit.hpp | 274 +-- api/kernel/irq_manager.hpp | 20 +- api/kernel/os.hpp | 4 +- api/kernel/service.hpp | 2 +- api/kernel/terminal.hpp | 20 +- api/net/arp.hpp | 210 +-- api/net/buffer_store.hpp | 148 +- api/net/dns/client.hpp | 4 +- api/net/dns/dns.hpp | 42 +- api/net/inet.hpp | 68 +- api/net/inet4.hpp | 2 +- api/net/inet64.hpp | 14 +- api/net/ip4.hpp | 226 +-- api/net/ip4/icmpv4.hpp | 60 +- api/net/ip4/packet_ip4.hpp | 100 +- api/net/ip4/udp.hpp | 108 +- api/net/ip6/icmp6.hpp | 2 +- api/net/ip6/ip6.hpp | 86 +- api/net/ip6/udp6.hpp | 4 +- api/net/tcp.hpp | 2310 +++++++++++++------------- api/net/tcp_connection_states.hpp | 360 ++-- api/net/util.hpp | 48 +- api/utility/async_loop.hpp | 26 +- api/utility/delegate.hpp | 74 +- api/utility/membitmap.hpp | 20 +- api/utility/ringbuffer.hpp | 174 +- api/utility/signal.hpp | 52 +- api/virtio/console.hpp | 4 +- api/virtio/virtio.hpp | 56 +- etc/batch_apply_editorconfig.sh | 9 + examples/demo_service/service.cpp | 80 +- examples/tcp/service.cpp | 90 +- src/crt/cxx_abi.cpp | 2 +- src/crt/mman.cpp | 28 +- src/debug/ircd.cpp | 188 +-- src/debug/ircsplit.hpp | 60 +- src/debug/test_disk.cpp | 200 +-- src/debug/test_ipv6.cpp | 56 +- src/debug/test_service.cpp | 48 +- src/debug/test_tcp.cpp | 20 +- src/fs/disk.cpp | 204 +-- src/fs/ext4.cpp | 22 +- src/fs/fat.cpp | 280 ++-- src/fs/fat_async.cpp | 308 ++-- src/fs/fat_sync.cpp | 158 +- src/fs/mbr.cpp | 136 +- src/fs/memdisk.cpp | 74 +- src/fs/path.cpp | 174 +- src/hw/cpu_freq_sampling.cpp | 108 +- src/hw/ide.cpp | 248 +-- src/hw/nic.cpp | 24 +- src/hw/pci_device.cpp | 264 +-- src/hw/pit.cpp | 344 ++-- src/include/hw/cpu_freq_sampling.hpp | 18 +- src/kernel/cpuid.cpp | 24 +- src/kernel/irq_manager.cpp | 116 +- src/kernel/os.cpp | 16 +- src/kernel/pci_manager.cpp | 10 +- src/kernel/rdrand.cpp | 12 +- src/kernel/syscalls.cpp | 2 +- src/kernel/terminal.cpp | 310 ++-- src/kernel/terminal_disk.cpp | 198 +-- src/kernel/vga.cpp | 4 +- src/net/arp.cpp | 316 ++-- src/net/buffer_store.cpp | 118 +- src/net/dhcp/dh4client.cpp | 148 +- src/net/dns/client.cpp | 16 +- src/net/dns/dns.cpp | 214 +-- src/net/ethernet.cpp | 134 +- src/net/inet.cpp | 8 +- src/net/inet_common.cpp | 34 +- src/net/ip4.cpp | 124 +- src/net/ip4/icmpv4.cpp | 92 +- src/net/ip4/udp.cpp | 102 +- src/net/ip4/udp_socket.cpp | 58 +- src/net/ip6/icmp6.cpp | 242 +-- src/net/ip6/ip6.cpp | 78 +- src/net/ip6/udp6.cpp | 12 +- src/net/tcp.cpp | 306 ++-- src/net/tcp_connection.cpp | 576 +++---- src/net/tcp_connection_states.cpp | 1742 +++++++++---------- src/virtio/block.cpp | 86 +- src/virtio/console.cpp | 96 +- src/virtio/virtio.cpp | 20 +- src/virtio/virtionet.cpp | 6 +- test/IDE/service.cpp | 16 +- test/IRQ_PIC/service.cpp | 20 +- test/STL/service.cpp | 102 +- test/bufstore/service.cpp | 6 +- test/fat/fat16.cpp | 70 +- test/fat/fat32.cpp | 8 +- test/memdisk/bigdisk.cpp | 6 +- test/memdisk/twosector.cpp | 8 +- test/tcp/service.cpp | 312 ++-- test/term/term.cpp | 44 +- test/transmit/service.cpp | 2 +- test/vga/vga.cpp | 28 +- vmbuild/vmbuild.cpp | 20 +- 114 files changed, 7465 insertions(+), 7456 deletions(-) create mode 100644 etc/batch_apply_editorconfig.sh diff --git a/api/fs/common.hpp b/api/fs/common.hpp index c09fb25c96..6ef7dc11c3 100644 --- a/api/fs/common.hpp +++ b/api/fs/common.hpp @@ -23,13 +23,13 @@ namespace fs { -typedef std::shared_ptr buffer_t; + typedef std::shared_ptr buffer_t; -// TODO: transform this into a class with a bool operator -using error_t = bool; + // TODO: transform this into a class with a bool operator + using error_t = bool; -/** @var no_error: Always returns boolean false when used in expressions */ -extern error_t no_error; + /** @var no_error: Always returns boolean false when used in expressions */ + extern error_t no_error; } //< namespace fs diff --git a/api/fs/disk.hpp b/api/fs/disk.hpp index d49137cde8..72ad7f7757 100644 --- a/api/fs/disk.hpp +++ b/api/fs/disk.hpp @@ -29,87 +29,87 @@ namespace fs { -class Disk { -public: - struct Partition; //< Representation of a disk partition + class Disk { + public: + struct Partition; //< Representation of a disk partition - /** Callbacks */ - using on_parts_func = std::function&)>; - using on_mount_func = std::function; + /** Callbacks */ + using on_parts_func = std::function&)>; + using on_mount_func = std::function; - /** Constructor */ - explicit Disk(hw::IDiskDevice&); + /** Constructor */ + explicit Disk(hw::IDiskDevice&); - enum partition_t { - MBR = 0, //< Master Boot Record (0) - /** extended partitions (1-4) */ - VBR1, - VBR2, - VBR3, - VBR4, + enum partition_t { + MBR = 0, //< Master Boot Record (0) + /** extended partitions (1-4) */ + VBR1, + VBR2, + VBR3, + VBR4, - INVALID - }; //< enum partition_t + INVALID + }; //< enum partition_t - struct Partition { - explicit Partition(const uint8_t fl, const uint8_t Id, - const uint32_t LBA, const uint32_t sz) noexcept : - flags {fl}, - id {Id}, - lba_begin {LBA}, - sectors {sz} - {} + struct Partition { + explicit Partition(const uint8_t fl, const uint8_t Id, + const uint32_t LBA, const uint32_t sz) noexcept : + flags {fl}, + id {Id}, + lba_begin {LBA}, + sectors {sz} + {} - uint8_t flags; - uint8_t id; - uint32_t lba_begin; - uint32_t sectors; + uint8_t flags; + uint8_t id; + uint32_t lba_begin; + uint32_t sectors; - // true if the partition has boot code / is bootable - bool is_boot() const noexcept - { return flags & 0x1; } + // true if the partition has boot code / is bootable + bool is_boot() const noexcept + { return flags & 0x1; } - // human-readable name of partition id - std::string name() const; + // human-readable name of partition id + std::string name() const; - // logical block address of beginning of partition - uint32_t lba() const - { return lba_begin; } + // logical block address of beginning of partition + uint32_t lba() const + { return lba_begin; } - }; //< struct Partition + }; //< struct Partition - /** Return a reference to the specified filesystem */ - FileSystem& fs() noexcept - { return *filesys; } + /** Return a reference to the specified filesystem */ + FileSystem& fs() noexcept + { return *filesys; } - //************** disk functions **************// + //************** disk functions **************// - hw::IDiskDevice& dev() noexcept - { return device; } + hw::IDiskDevice& dev() noexcept + { return device; } - // Returns true if the disk has no sectors - bool empty() const noexcept - { return device.size() == 0; } + // Returns true if the disk has no sectors + bool empty() const noexcept + { return device.size() == 0; } - // Mounts the first partition detected (MBR -> VBR1-4 -> ext) - void mount(on_mount_func func); + // Mounts the first partition detected (MBR -> VBR1-4 -> ext) + void mount(on_mount_func func); - // Mount partition @part as the filesystem FS - void mount(partition_t part, on_mount_func func); + // Mount partition @part as the filesystem FS + void mount(partition_t part, on_mount_func func); - /** - * Returns a vector of the partitions on a disk - * - * The disk does not need to be mounted beforehand - */ - void partitions(on_parts_func func); + /** + * Returns a vector of the partitions on a disk + * + * The disk does not need to be mounted beforehand + */ + void partitions(on_parts_func func); -private: - hw::IDiskDevice& device; - std::unique_ptr filesys; -}; //< class Disk + private: + hw::IDiskDevice& device; + std::unique_ptr filesys; + }; //< class Disk -using Disk_ptr = std::shared_ptr; + using Disk_ptr = std::shared_ptr; } //< namespace fs diff --git a/api/fs/ext4.hpp b/api/fs/ext4.hpp index d6f73782e5..ca289b95d0 100644 --- a/api/fs/ext4.hpp +++ b/api/fs/ext4.hpp @@ -32,16 +32,16 @@ namespace fs struct EXT4 : public FileSystem { /** - Blocks 2^32 2^32 2^32 2^32 - Inodes 2^32 2^32 2^32 2^32 - File System Size 4TiB 8TiB 16TiB 256PiB - Blocks Per Block Group 8,192 16,384 32,768 524,288 - Inodes Per Block Group 8,192 16,384 32,768 524,288 - Block Group Size 8MiB 32MiB 128MiB 32GiB - Blocks Per File, Extents 2^32 2^32 2^32 2^32 - Blocks Per File, Block Maps 16,843,020 134,480,396 1,074,791,436 4,398,314,962,956 - File Size, Extents 4TiB 8TiB 16TiB 256TiB - File Size, Block Maps 16GiB 256GiB 4TiB 256PiB + Blocks 2^32 2^32 2^32 2^32 + Inodes 2^32 2^32 2^32 2^32 + File System Size 4TiB 8TiB 16TiB 256PiB + Blocks Per Block Group 8,192 16,384 32,768 524,288 + Inodes Per Block Group 8,192 16,384 32,768 524,288 + Block Group Size 8MiB 32MiB 128MiB 32GiB + Blocks Per File, Extents 2^32 2^32 2^32 2^32 + Blocks Per File, Block Maps 16,843,020 134,480,396 1,074,791,436 4,398,314,962,956 + File Size, Extents 4TiB 8TiB 16TiB 256TiB + File Size, Block Maps 16GiB 256GiB 4TiB 256PiB **/ // 0 = Mount MBR diff --git a/api/fs/fat.hpp b/api/fs/fat.hpp index 424ce4e19e..18a1e4e0e2 100644 --- a/api/fs/fat.hpp +++ b/api/fs/fat.hpp @@ -54,14 +54,14 @@ namespace fs virtual std::string name() const override { switch (this->fat_type) - { - case T_FAT12: + { + case T_FAT12: return "FAT12"; - case T_FAT16: + case T_FAT16: return "FAT16"; - case T_FAT32: + case T_FAT32: return "FAT32"; - } + } return "Invalid fat type"; } /// ----------------------------------------------------- /// @@ -121,7 +121,7 @@ namespace fs uint32_t size() const { - return filesize; + return filesize; } } __attribute__((packed)); @@ -162,16 +162,16 @@ namespace fs uint16_t cl_to_entry_offset(uint32_t cl) { if (fat_type == T_FAT16) - return (cl * 2) % sector_size; + return (cl * 2) % sector_size; else // T_FAT32 - return (cl * 4) % sector_size; + return (cl * 4) % sector_size; } uint16_t cl_to_entry_sector(uint32_t cl) { if (fat_type == T_FAT16) - return reserved + (cl * 2 / sector_size); + return reserved + (cl * 2 / sector_size); else // T_FAT32 - return reserved + (cl * 4 / sector_size); + return reserved + (cl * 4 / sector_size); } // initialize filesystem by providing base sector diff --git a/api/fs/filesystem.hpp b/api/fs/filesystem.hpp index 215e0cb9b2..498f642f74 100644 --- a/api/fs/filesystem.hpp +++ b/api/fs/filesystem.hpp @@ -28,99 +28,99 @@ namespace fs { -class FileSystem { -public: - struct Dirent; //< Generic structure for directory entries + class FileSystem { + public: + struct Dirent; //< Generic structure for directory entries - using dirvector = std::vector; - using dirvec_t = std::shared_ptr; - using buffer_t = std::shared_ptr; + using dirvector = std::vector; + using dirvec_t = std::shared_ptr; + using buffer_t = std::shared_ptr; - using on_mount_func = std::function; - using on_ls_func = std::function; - using on_read_func = std::function; - using on_stat_func = std::function; + using on_mount_func = std::function; + using on_ls_func = std::function; + using on_read_func = std::function; + using on_stat_func = std::function; - struct Buffer - { - error_t err; - buffer_t buffer; - uint64_t len; + struct Buffer + { + error_t err; + buffer_t buffer; + uint64_t len; - Buffer(error_t e, buffer_t b, size_t l) - : err(e), buffer(b), len(l) {} - }; + Buffer(error_t e, buffer_t b, size_t l) + : err(e), buffer(b), len(l) {} + }; - enum Enttype { - FILE, - DIR, - /** FAT puts disk labels in the root directory, hence: */ - VOLUME_ID, - SYM_LINK, + enum Enttype { + FILE, + DIR, + /** FAT puts disk labels in the root directory, hence: */ + VOLUME_ID, + SYM_LINK, - INVALID_ENTITY - }; //< enum Enttype + INVALID_ENTITY + }; //< enum Enttype - /** Generic structure for directory entries */ - struct Dirent { - /** Default constructor */ - explicit Dirent(const Enttype t = INVALID_ENTITY, const std::string& n = "", - const uint64_t blk = 0U, const uint64_t pr = 0U, - const uint64_t sz = 0U, const uint32_t attr = 0U) : - ftype {t}, - fname {n}, - block {blk}, - parent {pr}, - size {sz}, - attrib {attr}, - timestamp {0} - {} + /** Generic structure for directory entries */ + struct Dirent { + /** Default constructor */ + explicit Dirent(const Enttype t = INVALID_ENTITY, const std::string& n = "", + const uint64_t blk = 0U, const uint64_t pr = 0U, + const uint64_t sz = 0U, const uint32_t attr = 0U) : + ftype {t}, + fname {n}, + block {blk}, + parent {pr}, + size {sz}, + attrib {attr}, + timestamp {0} + {} - Enttype ftype; - std::string fname; - uint64_t block; - uint64_t parent; //< Parent's block# - uint64_t size; - uint32_t attrib; - int64_t timestamp; + Enttype ftype; + std::string fname; + uint64_t block; + uint64_t parent; //< Parent's block# + uint64_t size; + uint32_t attrib; + int64_t timestamp; - Enttype type() const noexcept - { return ftype; } + Enttype type() const noexcept + { return ftype; } - // true if this dirent is valid - // if not, it means don't read any values from the Dirent as they are not - bool is_valid() const - { return ftype != INVALID_ENTITY; } + // true if this dirent is valid + // if not, it means don't read any values from the Dirent as they are not + bool is_valid() const + { return ftype != INVALID_ENTITY; } - // most common types - bool is_file() const noexcept - { return ftype == FILE; } - bool is_dir() const noexcept - { return ftype == DIR; } + // most common types + bool is_file() const noexcept + { return ftype == FILE; } + bool is_dir() const noexcept + { return ftype == DIR; } - // the entrys name - const std::string& name() const noexcept - { return fname; } + // the entrys name + const std::string& name() const noexcept + { return fname; } - // type converted to human-readable string - std::string type_string() const { - switch (ftype) { - case FILE: - return "File"; - case DIR: - return "Directory"; - case VOLUME_ID: - return "Volume ID"; + // type converted to human-readable string + std::string type_string() const { + switch (ftype) { + case FILE: + return "File"; + case DIR: + return "Directory"; + case VOLUME_ID: + return "Volume ID"; - case INVALID_ENTITY: - return "Invalid entity"; - default: - return "Unknown type"; - } //< switch (type) - } - }; //< struct Dirent + case INVALID_ENTITY: + return "Invalid entity"; + default: + return "Unknown type"; + } //< switch (type) + } + }; //< struct Dirent - /** Mount this filesystem with LBA at @base_sector */ + /** Mount this filesystem with LBA at @base_sector */ virtual void mount(uint64_t lba, uint64_t size, on_mount_func on_mount) = 0; /** @param path: Path in the mounted filesystem */ @@ -144,13 +144,13 @@ class FileSystem { /** Default destructor */ virtual ~FileSystem() noexcept = default; -}; //< class FileSystem + }; //< class FileSystem -// simplify initializing shared vector -inline FileSystem::dirvec_t new_shared_vector() -{ - return std::make_shared (); -} + // simplify initializing shared vector + inline FileSystem::dirvec_t new_shared_vector() + { + return std::make_shared (); + } } //< namespace fs diff --git a/api/fs/mbr.hpp b/api/fs/mbr.hpp index d36d539544..f888162e0d 100644 --- a/api/fs/mbr.hpp +++ b/api/fs/mbr.hpp @@ -24,53 +24,53 @@ namespace fs { -struct MBR { - static constexpr int PARTITIONS {4}; + struct MBR { + static constexpr int PARTITIONS {4}; - struct partition { - uint8_t flags; - uint8_t CHS_BEG[3]; - uint8_t type; - uint8_t CHS_END[3]; - uint32_t lba_begin; - uint32_t sectors; - } __attribute__((packed)); + struct partition { + uint8_t flags; + uint8_t CHS_BEG[3]; + uint8_t type; + uint8_t CHS_END[3]; + uint32_t lba_begin; + uint32_t sectors; + } __attribute__((packed)); - /** Legacy BIOS Parameter Block */ - struct BPB { - uint16_t bytes_per_sector; - uint8_t sectors_per_cluster; - uint16_t reserved_sectors; - uint8_t fa_tables; - uint16_t root_entries; - uint16_t small_sectors; - uint8_t media_type; // 0xF8 == hard drive - uint16_t sectors_per_fat; - uint16_t sectors_per_track; - uint16_t num_heads; - uint32_t hidden_sectors; - uint32_t large_sectors; // Used if small_sectors == 0 - uint8_t disk_number; // Starts at 0x80 - uint8_t current_head; - uint8_t signature; // Must be 0x28 or 0x29 - uint32_t serial_number; // Unique ID created by mkfs - char volume_label[11]; // Deprecated - char system_id[8]; // FAT12 or FAT16 - } __attribute__((packed)); + /** Legacy BIOS Parameter Block */ + struct BPB { + uint16_t bytes_per_sector; + uint8_t sectors_per_cluster; + uint16_t reserved_sectors; + uint8_t fa_tables; + uint16_t root_entries; + uint16_t small_sectors; + uint8_t media_type; // 0xF8 == hard drive + uint16_t sectors_per_fat; + uint16_t sectors_per_track; + uint16_t num_heads; + uint32_t hidden_sectors; + uint32_t large_sectors; // Used if small_sectors == 0 + uint8_t disk_number; // Starts at 0x80 + uint8_t current_head; + uint8_t signature; // Must be 0x28 or 0x29 + uint32_t serial_number; // Unique ID created by mkfs + char volume_label[11]; // Deprecated + char system_id[8]; // FAT12 or FAT16 + } __attribute__((packed)); - struct mbr { - uint8_t jump[3]; - char oem_name[8]; - uint8_t boot[435]; // Boot-code - partition part[PARTITIONS]; - uint16_t magic; // 0xAA55 + struct mbr { + uint8_t jump[3]; + char oem_name[8]; + uint8_t boot[435]; // Boot-code + partition part[PARTITIONS]; + uint16_t magic; // 0xAA55 - inline BPB* bpb() noexcept - { return reinterpret_cast(boot); } - } __attribute__((packed)); + inline BPB* bpb() noexcept + { return reinterpret_cast(boot); } + } __attribute__((packed)); - static std::string id_to_name(uint8_t); -}; //< struct MBR + static std::string id_to_name(uint8_t); + }; //< struct MBR } //< namespace fs diff --git a/api/fs/memdisk.hpp b/api/fs/memdisk.hpp index d5397a74d4..cab44d12f2 100644 --- a/api/fs/memdisk.hpp +++ b/api/fs/memdisk.hpp @@ -25,35 +25,35 @@ namespace fs { -class MemDisk : public hw::IDiskDevice { -public: - static constexpr size_t SECTOR_SIZE = 512; + class MemDisk : public hw::IDiskDevice { + public: + static constexpr size_t SECTOR_SIZE = 512; - MemDisk() noexcept; + MemDisk() noexcept; - /** Returns the optimal block size for this device. */ - virtual block_t block_size() const noexcept override - { return SECTOR_SIZE; } + /** Returns the optimal block size for this device. */ + virtual block_t block_size() const noexcept override + { return SECTOR_SIZE; } - virtual const char* name() const noexcept override - { - return "MemDisk"; - } + virtual const char* name() const noexcept override + { + return "MemDisk"; + } - virtual void - read(block_t blk, on_read_func reader) override; + virtual void + read(block_t blk, on_read_func reader) override; - virtual void - read(block_t start, block_t cnt, on_read_func reader) override; + virtual void + read(block_t start, block_t cnt, on_read_func reader) override; - virtual buffer_t read_sync(block_t blk) override; + virtual buffer_t read_sync(block_t blk) override; - virtual block_t size() const noexcept override; + virtual block_t size() const noexcept override; -private: - void* image_start; - void* image_end; -}; //< class MemDisk + private: + void* image_start; + void* image_end; + }; //< class MemDisk } //< namespace fs diff --git a/api/fs/path.hpp b/api/fs/path.hpp index 55bcf088db..2abd3e7449 100644 --- a/api/fs/path.hpp +++ b/api/fs/path.hpp @@ -24,79 +24,79 @@ namespace fs { -class Path { -public: - //! constructs Path to the current directory - Path(); + class Path { + public: + //! constructs Path to the current directory + Path(); - //! constructs Path to @path - Path(const std::string& path); + //! constructs Path to @path + Path(const std::string& path); - size_t size() const noexcept - { return stk.size(); } + size_t size() const noexcept + { return stk.size(); } - const std::string& operator [] (const int i) const noexcept - { return stk[i]; } + const std::string& operator [] (const int i) const noexcept + { return stk[i]; } - int getState() const noexcept - { return state; } + int getState() const noexcept + { return state; } - Path& operator = (const std::string& p) { - stk.clear(); - this->state = parse(p); - return *this; - } + Path& operator = (const std::string& p) { + stk.clear(); + this->state = parse(p); + return *this; + } - Path& operator += (const std::string& p) { - this->state = parse(p); - return *this; - } + Path& operator += (const std::string& p) { + this->state = parse(p); + return *this; + } - Path operator + (const std::string& p) const { - Path np = Path(*this); - np.state = np.parse(p); - return np; - } + Path operator + (const std::string& p) const { + Path np = Path(*this); + np.state = np.parse(p); + return np; + } - bool operator == (const Path& p) const { - if (stk.size() not_eq p.stk.size()) return false; - return this->to_string() == p.to_string(); - } + bool operator == (const Path& p) const { + if (stk.size() not_eq p.stk.size()) return false; + return this->to_string() == p.to_string(); + } - bool operator != (const Path& p) const - { return not this->operator == (p); } + bool operator != (const Path& p) const + { return not this->operator == (p); } - bool operator == (const std::string& p) const - { return *this == Path(p); } + bool operator == (const std::string& p) const + { return *this == Path(p); } - bool empty() const noexcept - { return stk.empty(); } + bool empty() const noexcept + { return stk.empty(); } - std::string front() const - { return stk.front(); } + std::string front() const + { return stk.front(); } - std::string back() const - { return stk.back(); } + std::string back() const + { return stk.back(); } - Path& pop_front() noexcept - { stk.pop_front(); return *this; } + Path& pop_front() noexcept + { stk.pop_front(); return *this; } - Path& pop_back() noexcept - { stk.pop_back(); return *this; } + Path& pop_back() noexcept + { stk.pop_back(); return *this; } - Path& up() - { if (not stk.empty()) stk.pop_back(); return *this; } + Path& up() + { if (not stk.empty()) stk.pop_back(); return *this; } - std::string to_string() const; + std::string to_string() const; -private: - int parse(const std::string& path); - void name_added(const std::string& name); - std::string real_path() const; + private: + int parse(const std::string& path); + void name_added(const std::string& name); + std::string real_path() const; - int state; - std::deque stk; -}; //< class Path + int state; + std::deque stk; + }; //< class Path } //< namespace fs diff --git a/api/fs/vbr.hpp b/api/fs/vbr.hpp index bef8b24129..dbb145b7bf 100644 --- a/api/fs/vbr.hpp +++ b/api/fs/vbr.hpp @@ -21,9 +21,9 @@ namespace fs { -class VBR { + class VBR { -}; //< class VBR + }; //< class VBR } //< namespace fs diff --git a/api/hw/dev.hpp b/api/hw/dev.hpp index 5571982d1d..559d72982f 100644 --- a/api/hw/dev.hpp +++ b/api/hw/dev.hpp @@ -30,58 +30,58 @@ namespace hw { -/** @Todo: Implement */ -class Serial; -class APIC; -class HPET; + /** @Todo: Implement */ + class Serial; + class APIC; + class HPET; -/** - * Access point for devices - * - * Get a nic by calling `Dev::eth<0, Virtio_Net>(n)`, a disk by calling `Dev::disk<0, VirtioBlk>(n)` etc. - */ -class Dev { -public: - /** Get ethernet device n */ - template - static Nic& eth() { - static Nic eth_ {PCI_manager::device(N)}; - return eth_; - } - - /** Get disk N using driver DRIVER */ - template - static Disk& disk(Args&&... args) { - static Disk - disk_ { - PCI_manager::device(N), - std::forward(args)... - }; - return disk_; - } - - /** Get console N using driver DRIVER */ - template - static DRIVER& console() { - static DRIVER con_ {PCI_manager::device(N)}; - return con_; - } - /** - * Get serial port n - * - * @Todo: Make a serial port class, and move rsprint / rswrite etc. from OS out to it. + * Access point for devices * - * @Note: The DRIVER parameter is there to support virtio serial ports. + * Get a nic by calling `Dev::eth<0, Virtio_Net>(n)`, a disk by calling `Dev::disk<0, VirtioBlk>(n)` etc. */ - template - static PCI_Device& serial(int n); + class Dev { + public: + /** Get ethernet device n */ + template + static Nic& eth() { + static Nic eth_ {PCI_manager::device(N)}; + return eth_; + } + + /** Get disk N using driver DRIVER */ + template + static Disk& disk(Args&&... args) { + static Disk + disk_ { + PCI_manager::device(N), + std::forward(args)... + }; + return disk_; + } + + /** Get console N using driver DRIVER */ + template + static DRIVER& console() { + static DRIVER con_ {PCI_manager::device(N)}; + return con_; + } + + /** + * Get serial port n + * + * @Todo: Make a serial port class, and move rsprint / rswrite etc. from OS out to it. + * + * @Note: The DRIVER parameter is there to support virtio serial ports. + */ + template + static PCI_Device& serial(int n); - /** Programmable Interval Timer device, with ~ms-precision asynchronous timers. */ - static PIT& basic_timer() { - return PIT::instance(); - } -}; //< class Dev + /** Programmable Interval Timer device, with ~ms-precision asynchronous timers. */ + static PIT& basic_timer() { + return PIT::instance(); + } + }; //< class Dev } //< namespace hw diff --git a/api/hw/disk.hpp b/api/hw/disk.hpp index b616613fef..548fc8ca94 100644 --- a/api/hw/disk.hpp +++ b/api/hw/disk.hpp @@ -23,55 +23,55 @@ namespace hw { -template -class Disk : public IDiskDevice { -public: - /** optimal block size for this device */ - virtual block_t block_size() const noexcept override - { return driver.block_size(); } + template + class Disk : public IDiskDevice { + public: + /** optimal block size for this device */ + virtual block_t block_size() const noexcept override + { return driver.block_size(); } - /** Human readable name */ - const char* name() const noexcept override - { - return driver.name(); - } + /** Human readable name */ + const char* name() const noexcept override + { + return driver.name(); + } - virtual void - read(block_t blk, on_read_func del) override - { - driver.read(blk, del); - } - virtual void - read(block_t blk, block_t count, on_read_func del) override - { - driver.read(blk, count, del); - } + virtual void + read(block_t blk, on_read_func del) override + { + driver.read(blk, del); + } + virtual void + read(block_t blk, block_t count, on_read_func del) override + { + driver.read(blk, count, del); + } - virtual buffer_t read_sync(block_t blk) override - { - return driver.read_sync(blk); - } + virtual buffer_t read_sync(block_t blk) override + { + return driver.read_sync(blk); + } - virtual block_t size() const noexcept override - { - return driver.size(); - } + virtual block_t size() const noexcept override + { + return driver.size(); + } - virtual ~Disk() = default; + virtual ~Disk() = default; -private: - DRIVER driver; + private: + DRIVER driver; - /** - * Just a wrapper around the driver constructor - * @note The Dev-class is a friend and will call this - */ - template - explicit Disk(PCI_Device& d, Args&&... args): - driver{d, std::forward(args)... } {} + /** + * Just a wrapper around the driver constructor + * @note The Dev-class is a friend and will call this + */ + template + explicit Disk(PCI_Device& d, Args&&... args): + driver{d, std::forward(args)... } {} - friend class Dev; -}; //< class Disk + friend class Dev; + }; //< class Disk } //< namespace hw diff --git a/api/hw/disk_device.hpp b/api/hw/disk_device.hpp index 0612356c3c..909165f41a 100644 --- a/api/hw/disk_device.hpp +++ b/api/hw/disk_device.hpp @@ -26,39 +26,39 @@ namespace hw { -class IDiskDevice { -public: - using block_t = uint64_t; //< Disk device block size - using buffer_t = std::shared_ptr; + class IDiskDevice { + public: + using block_t = uint64_t; //< Disk device block size + using buffer_t = std::shared_ptr; - // Delegate for result of reading a disk sector - using on_read_func = std::function; + // Delegate for result of reading a disk sector + using on_read_func = std::function; - /** Human-readable name of this disk controller */ - virtual const char* name() const noexcept = 0; + /** Human-readable name of this disk controller */ + virtual const char* name() const noexcept = 0; - /** The size of the disk in whole sectors */ - virtual block_t size() const noexcept = 0; + /** The size of the disk in whole sectors */ + virtual block_t size() const noexcept = 0; - /** Returns the optimal block size for this device */ - virtual block_t block_size() const noexcept = 0; + /** Returns the optimal block size for this device */ + virtual block_t block_size() const noexcept = 0; - /** - * Read block(s) from blk and call func with result - * A null-pointer is passed to result if something bad happened - * Validate using !buffer_t: - * if (!buffer) - * error("Device failed to read sector"); - **/ - virtual void read(block_t blk, on_read_func func) = 0; - virtual void read(block_t blk, block_t count, on_read_func) = 0; + /** + * Read block(s) from blk and call func with result + * A null-pointer is passed to result if something bad happened + * Validate using !buffer_t: + * if (!buffer) + * error("Device failed to read sector"); + **/ + virtual void read(block_t blk, on_read_func func) = 0; + virtual void read(block_t blk, block_t count, on_read_func) = 0; - /** read synchronously the block @blk */ - virtual buffer_t read_sync(block_t blk) = 0; + /** read synchronously the block @blk */ + virtual buffer_t read_sync(block_t blk) = 0; - /** Default destructor */ - virtual ~IDiskDevice() noexcept = default; -}; //< class IDiskDevice + /** Default destructor */ + virtual ~IDiskDevice() noexcept = default; + }; //< class IDiskDevice } //< namespace hw diff --git a/api/hw/ide.hpp b/api/hw/ide.hpp index 0d6ac60c4f..76bb08b0c6 100644 --- a/api/hw/ide.hpp +++ b/api/hw/ide.hpp @@ -25,58 +25,58 @@ namespace hw { -/** IDE device driver */ -class IDE : public IDiskDevice { -public: - enum selector_t - { - MASTER, - SLAVE - }; + /** IDE device driver */ + class IDE : public IDiskDevice { + public: + enum selector_t + { + MASTER, + SLAVE + }; - /** - * Constructor - * - * @param pcidev: An initialized PCI device - */ - explicit IDE(hw::PCI_Device& pcidev, selector_t); + /** + * Constructor + * + * @param pcidev: An initialized PCI device + */ + explicit IDE(hw::PCI_Device& pcidev, selector_t); - /** Human-readable name of this disk controller */ - virtual const char* name() const noexcept override - { return "IDE Controller"; } + /** Human-readable name of this disk controller */ + virtual const char* name() const noexcept override + { return "IDE Controller"; } - /** Returns the optimal block size for this device. */ - virtual block_t block_size() const noexcept override - { return 512; } + /** Returns the optimal block size for this device. */ + virtual block_t block_size() const noexcept override + { return 512; } - virtual void read(block_t blk, on_read_func reader) override; - virtual void read(block_t blk, block_t count, on_read_func reader) override; + virtual void read(block_t blk, on_read_func reader) override; + virtual void read(block_t blk, block_t count, on_read_func reader) override; - /** read synchronously from IDE disk */ - virtual buffer_t read_sync(block_t blk) override; + /** read synchronously from IDE disk */ + virtual buffer_t read_sync(block_t blk) override; - virtual block_t size() const noexcept override - { return _nb_blk; } + virtual block_t size() const noexcept override + { return _nb_blk; } -private: - void set_drive(const uint8_t drive) const noexcept; - void set_nbsectors(const uint8_t cnt) const noexcept; - void set_blocknum(block_t blk) const noexcept; - void set_command(const uint16_t command) const noexcept; - void set_irq_mode(const bool on) const noexcept; + private: + void set_drive(const uint8_t drive) const noexcept; + void set_nbsectors(const uint8_t cnt) const noexcept; + void set_blocknum(block_t blk) const noexcept; + void set_command(const uint16_t command) const noexcept; + void set_irq_mode(const bool on) const noexcept; - void wait_status_busy() const noexcept; - void wait_status_flags(const int flags, const bool set) const noexcept; + void wait_status_busy() const noexcept; + void wait_status_flags(const int flags, const bool set) const noexcept; - void irq_handler(); - void enable_irq_handler(); + void irq_handler(); + void enable_irq_handler(); -private: - hw::PCI_Device& _pcidev; // PCI device - uint8_t _drive; // Drive id (IDE_MASTER or IDE_SLAVE) - uint32_t _iobase; // PCI device io base address - block_t _nb_blk; // Max nb blocks of the device -}; //< class IDE + private: + hw::PCI_Device& _pcidev; // PCI device + uint8_t _drive; // Drive id (IDE_MASTER or IDE_SLAVE) + uint32_t _iobase; // PCI device io base address + block_t _nb_blk; // Max nb blocks of the device + }; //< class IDE } //< namespace hw diff --git a/api/hw/pci.hpp b/api/hw/pci.hpp index f839eae85d..fbd0b5a975 100644 --- a/api/hw/pci.hpp +++ b/api/hw/pci.hpp @@ -5,53 +5,53 @@ namespace hw { -typedef uint16_t port_t; + typedef uint16_t port_t; -static inline int inp(port_t port) -{ - int ret; + static inline int inp(port_t port) + { + int ret; - __asm__ volatile("xorl %eax,%eax"); - __asm__ volatile("inb %%dx,%%al" - :"=a"(ret) - :"d"(port)); - return ret; -} - -static inline uint16_t inpw(port_t port) -{ - uint16_t ret; - __asm__ volatile("xorl %eax,%eax"); - __asm__ volatile("inw %%dx,%%ax" - :"=a"(ret) - :"d"(port)); - return ret; -} - -static inline uint32_t inpd(port_t port) -{ - uint32_t ret; - __asm__ volatile("xorl %eax,%eax"); - __asm__ volatile("inl %%dx,%%eax" - :"=a"(ret) - :"d"(port)); + __asm__ volatile("xorl %eax,%eax"); + __asm__ volatile("inb %%dx,%%al" + :"=a"(ret) + :"d"(port)); + return ret; + } + + static inline uint16_t inpw(port_t port) + { + uint16_t ret; + __asm__ volatile("xorl %eax,%eax"); + __asm__ volatile("inw %%dx,%%ax" + :"=a"(ret) + :"d"(port)); + return ret; + } + + static inline uint32_t inpd(port_t port) + { + uint32_t ret; + __asm__ volatile("xorl %eax,%eax"); + __asm__ volatile("inl %%dx,%%eax" + :"=a"(ret) + :"d"(port)); - return ret; -} - - -static inline void outp(port_t port, uint8_t data) -{ - __asm__ volatile ("outb %%al,%%dx"::"a" (data), "d"(port)); -} -static inline void outpw(port_t port, uint16_t data) -{ - __asm__ volatile ("outw %%ax,%%dx"::"a" (data), "d"(port)); -} -static inline void outpd(port_t port, uint32_t data) -{ - __asm__ volatile ("outl %%eax,%%dx"::"a" (data), "d"(port)); -} + return ret; + } + + + static inline void outp(port_t port, uint8_t data) + { + __asm__ volatile ("outb %%al,%%dx"::"a" (data), "d"(port)); + } + static inline void outpw(port_t port, uint16_t data) + { + __asm__ volatile ("outw %%ax,%%dx"::"a" (data), "d"(port)); + } + static inline void outpd(port_t port, uint32_t data) + { + __asm__ volatile ("outl %%eax,%%dx"::"a" (data), "d"(port)); + } } //< namespace hw diff --git a/api/hw/pci_device.hpp b/api/hw/pci_device.hpp index 4e200fa1a3..fb55a09972 100644 --- a/api/hw/pci_device.hpp +++ b/api/hw/pci_device.hpp @@ -23,244 +23,244 @@ namespace PCI { -static const uint16_t CONFIG_ADDR {0xCF8U}; -static const uint16_t CONFIG_DATA {0xCFCU}; -static const uint8_t CONFIG_INTR {0x3CU}; + static const uint16_t CONFIG_ADDR {0xCF8U}; + static const uint16_t CONFIG_DATA {0xCFCU}; + static const uint8_t CONFIG_INTR {0x3CU}; -static const uint8_t CONFIG_VENDOR {0x00U}; -static const uint8_t CONFIG_CLASS_REV {0x08U}; + static const uint8_t CONFIG_VENDOR {0x00U}; + static const uint8_t CONFIG_CLASS_REV {0x08U}; -static const uint8_t CONFIG_BASE_ADDR_0 {0x10U}; + static const uint8_t CONFIG_BASE_ADDR_0 {0x10U}; -static const uint32_t BASE_ADDRESS_MEM_MASK {~0x0FUL}; -static const uint32_t BASE_ADDRESS_IO_MASK {~0x03UL}; + static const uint32_t BASE_ADDRESS_MEM_MASK {~0x0FUL}; + static const uint32_t BASE_ADDRESS_IO_MASK {~0x03UL}; -static const uint32_t WTF {0xffffffffU}; + static const uint32_t WTF {0xffffffffU}; -/** - * @brief PCI device message format - * - * Used to communicate with PCI devices - */ -union msg { - - //! The whole message - uint32_t data; - - /** - * Packed attribtues, ordered low to high. - * - * @note: Doxygen thinks this is a function - it's not + /** + * @brief PCI device message format * - * it's a GCC-directive. + * Used to communicate with PCI devices */ - struct __attribute__((packed)) { - //! The PCI register - uint8_t reg; + union msg { + + //! The whole message + uint32_t data; + + /** + * Packed attribtues, ordered low to high. + * + * @note: Doxygen thinks this is a function - it's not + * + * it's a GCC-directive. + */ + struct __attribute__((packed)) { + //! The PCI register + uint8_t reg; - //! The 16-bit PCI-address @see pci_addr() - uint16_t addr; - uint8_t code; - }; -}; //< union msg + //! The 16-bit PCI-address @see pci_addr() + uint16_t addr; + uint8_t code; + }; + }; //< union msg -/** Relevant class codes (many more) */ -enum classcode_t { - OLD, - STORAGE, - NIC, - DISPLAY, - MULTIMEDIA, - MEMORY, - BRIDGE, - COMMUNICATION, - BASE_SYSTEM_PER, - INPUT_DEVICE, - DOCKING_STATION, - PROCESSOR, - SERIAL_BUS, - WIRELESS, - IO_CTL, - SATELLITE, - ENCRYPTION, - SIGPRO, - OTHER=255 -}; //< enum classcode_t + /** Relevant class codes (many more) */ + enum classcode_t { + OLD, + STORAGE, + NIC, + DISPLAY, + MULTIMEDIA, + MEMORY, + BRIDGE, + COMMUNICATION, + BASE_SYSTEM_PER, + INPUT_DEVICE, + DOCKING_STATION, + PROCESSOR, + SERIAL_BUS, + WIRELESS, + IO_CTL, + SATELLITE, + ENCRYPTION, + SIGPRO, + OTHER=255 + }; //< enum classcode_t } //< namespace PCI namespace hw { -/** - * @brief Communication class for all PCI devices - * - * All low level communication with PCI devices should (ideally) go here. - * - * @todo - * - Consider if we ever need to separate the address into 'bus/dev/func' parts. - * - Do we ever need anything but PCI Devices? -*/ -class PCI_Device { // public Device //Why not? A PCI device is too general to be accessible? -public: - - enum { - VENDOR_AMD = 0x1022, - VENDOR_INTEL = 0x8086, - VENDOR_CIRRUS = 0x1013, - VENDOR_VIRTIO = 0x1AF4, - VENDOR_REALTEK = 0x10EC - }; - /** - * Constructor - * - * @param pci_addr: A 16-bit PCI address. - * @param device_id: A device ID, consisting of PCI vendor and product ID's. - * - * @see pci_addr() for more about the address + * @brief Communication class for all PCI devices + * + * All low level communication with PCI devices should (ideally) go here. + * + * @todo + * - Consider if we ever need to separate the address into 'bus/dev/func' parts. + * - Do we ever need anything but PCI Devices? */ - explicit PCI_Device(const uint16_t pci_addr, const uint32_t device_id) noexcept; + class PCI_Device { // public Device //Why not? A PCI device is too general to be accessible? + public: - //! @brief Read from device with implicit pci_address (e.g. used by Nic) - uint32_t read_dword(const uint8_t reg) noexcept; + enum { + VENDOR_AMD = 0x1022, + VENDOR_INTEL = 0x8086, + VENDOR_CIRRUS = 0x1013, + VENDOR_VIRTIO = 0x1AF4, + VENDOR_REALTEK = 0x10EC + }; - //! @brief Read from device with explicit pci_addr - static uint32_t read_dword(const uint16_t pci_addr, const uint8_t reg) noexcept; + /** + * Constructor + * + * @param pci_addr: A 16-bit PCI address. + * @param device_id: A device ID, consisting of PCI vendor and product ID's. + * + * @see pci_addr() for more about the address + */ + explicit PCI_Device(const uint16_t pci_addr, const uint32_t device_id) noexcept; + + //! @brief Read from device with implicit pci_address (e.g. used by Nic) + uint32_t read_dword(const uint8_t reg) noexcept; - /** - * Probe for a device on the given address - * - * @param pci_addr: the address to probe - * - * @deprecated We got a 20% performance degradation using this for probing - * - * @see PCI_Device() - */ - static PCI_Device* Create(uint16_t pci_addr); + //! @brief Read from device with explicit pci_addr + static uint32_t read_dword(const uint16_t pci_addr, const uint8_t reg) noexcept; - // @brief Get a device by address. @see pci_addr(). - static PCI_Device* get(uint16_t pci_addr); + /** + * Probe for a device on the given address + * + * @param pci_addr: the address to probe + * + * @deprecated We got a 20% performance degradation using this for probing + * + * @see PCI_Device() + */ + static PCI_Device* Create(uint16_t pci_addr); - // @brief Get a device by individual address parts. - // @todo Will we ever need this? - static PCI_Device* get(int busno, int devno, int funcno); + // @brief Get a device by address. @see pci_addr(). + static PCI_Device* get(uint16_t pci_addr); + + // @brief Get a device by individual address parts. + // @todo Will we ever need this? + static PCI_Device* get(int busno, int devno, int funcno); - /** A descriptive name */ - inline const char* name(); + /** A descriptive name */ + inline const char* name(); - /** - * Get the PCI address of device. - * - * The address is a composite of 'bus', 'device' and 'function', usually used - * (i.e. by Linux) to designate a PCI device. - * - * @return: The address of the device - */ - inline uint16_t pci_addr() const noexcept - { return pci_addr_; }; + /** + * Get the PCI address of device. + * + * The address is a composite of 'bus', 'device' and 'function', usually used + * (i.e. by Linux) to designate a PCI device. + * + * @return: The address of the device + */ + inline uint16_t pci_addr() const noexcept + { return pci_addr_; }; - /** Get the pci class code. */ - inline PCI::classcode_t classcode() const noexcept - { return static_cast(devtype_.classcode); } + /** Get the pci class code. */ + inline PCI::classcode_t classcode() const noexcept + { return static_cast(devtype_.classcode); } - inline uint16_t rev_id() const noexcept - { return devtype_.rev_id; } + inline uint16_t rev_id() const noexcept + { return devtype_.rev_id; } - /** Get the pci vendor and product id */ - inline uint16_t vendor_id() const noexcept - { return device_id_.vendor; } + /** Get the pci vendor and product id */ + inline uint16_t vendor_id() const noexcept + { return device_id_.vendor; } - inline uint16_t product_id() const noexcept - { return device_id_.product; } + inline uint16_t product_id() const noexcept + { return device_id_.product; } - /** - * Parse all Base Address Registers (BAR's) - * - * Used to determine how to communicate with the device. - * - * This function adds resources to the PCI_Device. - */ - void probe_resources() noexcept; + /** + * Parse all Base Address Registers (BAR's) + * + * Used to determine how to communicate with the device. + * + * This function adds resources to the PCI_Device. + */ + void probe_resources() noexcept; - /** The base address of the (first) I/O resource */ - uint32_t iobase() const noexcept; + /** The base address of the (first) I/O resource */ + uint32_t iobase() const noexcept; -private: - // @brief The 3-part PCI address - uint16_t pci_addr_; + private: + // @brief The 3-part PCI address + uint16_t pci_addr_; - //@brief The three address parts derived (if needed) - uint8_t busno_ {0}; - uint8_t devno_ {0}; - uint8_t funcno_ {0}; + //@brief The three address parts derived (if needed) + uint8_t busno_ {0}; + uint8_t devno_ {0}; + uint8_t funcno_ {0}; - // @brief The 2-part ID retrieved from the device - union vendor_product { - uint32_t __value; - struct __attribute__((packed)) { - uint16_t vendor; - uint16_t product; - }; - } device_id_; + // @brief The 2-part ID retrieved from the device + union vendor_product { + uint32_t __value; + struct __attribute__((packed)) { + uint16_t vendor; + uint16_t product; + }; + } device_id_; - // @brief The class code (device type) - union class_revision { - uint32_t reg; - struct __attribute__((packed)) { - uint8_t rev_id; - uint8_t prog_if; - uint8_t subclass; - uint8_t classcode; - }; - struct __attribute__((packed)) { - uint16_t class_subclass; - uint8_t __prog_if; //Overlaps the above - uint8_t revision; - }; - } devtype_; + // @brief The class code (device type) + union class_revision { + uint32_t reg; + struct __attribute__((packed)) { + uint8_t rev_id; + uint8_t prog_if; + uint8_t subclass; + uint8_t classcode; + }; + struct __attribute__((packed)) { + uint16_t class_subclass; + uint8_t __prog_if; //Overlaps the above + uint8_t revision; + }; + } devtype_; - // @brief Printable names - const char* classname_; - const char* vendorname_; - const char* productname_; + // @brief Printable names + const char* classname_; + const char* vendorname_; + const char* productname_; - // Device Resources + // Device Resources - //! @brief Resource types, "Memory" or "I/O" - enum resource_t { RES_MEM, RES_IO }; + //! @brief Resource types, "Memory" or "I/O" + enum resource_t { RES_MEM, RES_IO }; - /** A device resource - possibly a list */ - template - struct Resource { - const resource_t type {RT}; - uint32_t start_; - uint32_t len_; - Resource* next {nullptr}; - Resource(const uint32_t start, const uint32_t len) : start_{start}, len_{len} {}; - }; + /** A device resource - possibly a list */ + template + struct Resource { + const resource_t type {RT}; + uint32_t start_; + uint32_t len_; + Resource* next {nullptr}; + Resource(const uint32_t start, const uint32_t len) : start_{start}, len_{len} {}; + }; - //! @brief Resource lists. Members added by add_resource(); - Resource* res_mem_ {nullptr}; - Resource* res_io_ {nullptr}; + //! @brief Resource lists. Members added by add_resource(); + Resource* res_mem_ {nullptr}; + Resource* res_io_ {nullptr}; - //! @brief Write to device with implicit pci_address (e.g. used by Nic) - void write_dword(const uint8_t reg, const uint32_t value) noexcept; + //! @brief Write to device with implicit pci_address (e.g. used by Nic) + void write_dword(const uint8_t reg, const uint32_t value) noexcept; - /** - * Add a resource to a resource queue. - * - * (This seems pretty dirty; private class, reference to pointer etc.) */ - template - void add_resource(Resource* res, Resource*& Q) noexcept { - Resource* q; - if (Q) { - q = Q; - while (q->next) q = q->next; - q->next = res; - } else { - Q = res; + /** + * Add a resource to a resource queue. + * + * (This seems pretty dirty; private class, reference to pointer etc.) */ + template + void add_resource(Resource* res, Resource*& Q) noexcept { + Resource* q; + if (Q) { + q = Q; + while (q->next) q = q->next; + q->next = res; + } else { + Q = res; + } } - } -}; //< class PCI_Device + }; //< class PCI_Device } //< namespace hw diff --git a/api/hw/pic.hpp b/api/hw/pic.hpp index 392e7f6600..c08b346f77 100644 --- a/api/hw/pic.hpp +++ b/api/hw/pic.hpp @@ -27,7 +27,7 @@ namespace hw { /** Programmable Interrupt Controller implementation according to Intel 8259A / 8259A-2 1988 whitepaper - */ + */ class PIC { public: static void init() noexcept; @@ -49,19 +49,19 @@ namespace hw { } /** - @brief End of Interrupt. Master IRQ-lines (0-7) currently use Auto EOI, - but the user should assume that IRQ-specific EOI's are necessary. + @brief End of Interrupt. Master IRQ-lines (0-7) currently use Auto EOI, + but the user should assume that IRQ-specific EOI's are necessary. - @note: - According to Intel 8259A / 8259A-2 whitepaper p. 15 - "The AEOI mode can only be used in a master 8259A and not a slave. - 8259As with a copyright date of 1985 or later will operate in the AEOI - mode as a master or a slave" + @note: + According to Intel 8259A / 8259A-2 whitepaper p. 15 + "The AEOI mode can only be used in a master 8259A and not a slave. + 8259As with a copyright date of 1985 or later will operate in the AEOI + mode as a master or a slave" - If I enable auto-eoi for slave, everything seems to freeze in Qemu, - the moment I get the first network interrupt (IRQ 11). + If I enable auto-eoi for slave, everything seems to freeze in Qemu, + the moment I get the first network interrupt (IRQ 11). - I'm assuming this means that I have an old chip :-) + I'm assuming this means that I have an old chip :-) */ inline static void eoi(const uint8_t irq) noexcept { diff --git a/api/hw/pit.hpp b/api/hw/pit.hpp index 7e29aff3a6..5d21588c9d 100644 --- a/api/hw/pit.hpp +++ b/api/hw/pit.hpp @@ -23,165 +23,165 @@ namespace hw { -/** - Programmable Interval Timer class. A singleton. + /** + Programmable Interval Timer class. A singleton. - @TODO - ...It has timer-functionality, which should probably be super-classed, - so that i.e. the HPET could be used with the same interface. -*/ -class PIT{ -public: - - typedef delegate timeout_handler; - typedef std::function repeat_condition; - - /** Create a one-shot timer. - @param ms: Expiration time. Compatible with all std::chrono durations. - @param handler: A delegate or function to be called on timeout. */ - void onTimeout(std::chrono::milliseconds ms, timeout_handler handler); - - /** Create a repeating timer. - @param ms: Expiration time. Compatible with all std::chrono durations. - @param handler: A delegate or function to be called every ms interval. - @param cond: The timer ends when cond() returns false. Default to true. */ - void onRepeatedTimeout(std::chrono::milliseconds ms, - timeout_handler handler, - repeat_condition cond = forever); - - /** No copy or move. The OS owns one instance forever. */ - PIT(PIT&) = delete; - PIT(PIT&&) = delete; - - /** Get the (single) instance. */ - static PIT& instance() { - static PIT instance_; - return instance_; - }; - - /** Initialize the hardware. */ - static void init(); - - /** The constant frequency of the PIT-hardware, before frequency dividers */ - static constexpr MHz frequency() { return frequency_; } - - static inline MHz current_frequency(){ return frequency() / current_freq_divider_; } - - /** Estimate cpu frequency based on the fixed PIT frequency and rdtsc. - @Note This is an asynchronous function. Once finished the result can be - fetched by CPUFrequency() (below) */ - static void estimateCPUFrequency(); - - /** Get the last estimated CPU frequency. May trigger frequency sampling */ - static MHz CPUFrequency(); - -private: - // Default repeat-condition - static std::function forever; + @TODO + ...It has timer-functionality, which should probably be super-classed, + so that i.e. the HPET could be used with the same interface. + */ + class PIT{ + public: - enum Mode { ONE_SHOT = 0, - HW_ONESHOT = 1 << 1, - RATE_GEN = 2 << 1, - SQ_WAVE = 3 << 1, - SW_STROBE = 4 << 1, - HW_STROBE = 5 << 1, - NONE = 256}; + typedef delegate timeout_handler; + typedef std::function repeat_condition; - // The PIT-chip runs at this fixed frequency (in MHz) , according to OSDev.org */ - static constexpr MHz frequency_ = MHz(14.31818 / 12); + /** Create a one-shot timer. + @param ms: Expiration time. Compatible with all std::chrono durations. + @param handler: A delegate or function to be called on timeout. */ + void onTimeout(std::chrono::milliseconds ms, timeout_handler handler); + + /** Create a repeating timer. + @param ms: Expiration time. Compatible with all std::chrono durations. + @param handler: A delegate or function to be called every ms interval. + @param cond: The timer ends when cond() returns false. Default to true. */ + void onRepeatedTimeout(std::chrono::milliseconds ms, + timeout_handler handler, + repeat_condition cond = forever); + + /** No copy or move. The OS owns one instance forever. */ + PIT(PIT&) = delete; + PIT(PIT&&) = delete; + + /** Get the (single) instance. */ + static PIT& instance() { + static PIT instance_; + return instance_; + }; + + /** Initialize the hardware. */ + static void init(); + + /** The constant frequency of the PIT-hardware, before frequency dividers */ + static constexpr MHz frequency() { return frequency_; } + + static inline MHz current_frequency(){ return frequency() / current_freq_divider_; } + + /** Estimate cpu frequency based on the fixed PIT frequency and rdtsc. + @Note This is an asynchronous function. Once finished the result can be + fetched by CPUFrequency() (below) */ + static void estimateCPUFrequency(); + + /** Get the last estimated CPU frequency. May trigger frequency sampling */ + static MHz CPUFrequency(); + + private: + // Default repeat-condition + static std::function forever; + + enum Mode { ONE_SHOT = 0, + HW_ONESHOT = 1 << 1, + RATE_GEN = 2 << 1, + SQ_WAVE = 3 << 1, + SW_STROBE = 4 << 1, + HW_STROBE = 5 << 1, + NONE = 256}; + + // The PIT-chip runs at this fixed frequency (in MHz) , according to OSDev.org */ + static constexpr MHz frequency_ = MHz(14.31818 / 12); - /** Disable regular timer interrupts- which are turned on at boot-time. */ - static void disable_regular_interrupts(); + /** Disable regular timer interrupts- which are turned on at boot-time. */ + static void disable_regular_interrupts(); - /** The default (soft)handler for timer interrupts */ - void irq_handler(); + /** The default (soft)handler for timer interrupts */ + void irq_handler(); - // Private constructor / destructor. It's a singleton. - PIT(); - ~PIT(); + // Private constructor / destructor. It's a singleton. + PIT(); + ~PIT(); - // State-keeping - static Mode temp_mode_; - static uint16_t temp_freq_divider_; - static uint8_t status_byte_; - static uint16_t current_freq_divider_; - static Mode current_mode_; - static uint64_t IRQ_counter_; + // State-keeping + static Mode temp_mode_; + static uint16_t temp_freq_divider_; + static uint8_t status_byte_; + static uint16_t current_freq_divider_; + static Mode current_mode_; + static uint64_t IRQ_counter_; - // The closest we can get to a millisecond interval, with the PIT-frequency - static constexpr uint16_t millisec_interval = KHz(frequency_).count(); + // The closest we can get to a millisecond interval, with the PIT-frequency + static constexpr uint16_t millisec_interval = KHz(frequency_).count(); - // Count the "milliseconds" - static uint64_t millisec_counter; + // Count the "milliseconds" + static uint64_t millisec_counter; - // Access mode bits are bits 4- and 5 in the Mode register - enum AccessMode { LATCH_COUNT = 0x0, LO_ONLY=0x10, HI_ONLY=0x20, LO_HI=0x30 }; + // Access mode bits are bits 4- and 5 in the Mode register + enum AccessMode { LATCH_COUNT = 0x0, LO_ONLY=0x10, HI_ONLY=0x20, LO_HI=0x30 }; - /** Physically set the PIT-mode */ - static void set_mode(Mode); + /** Physically set the PIT-mode */ + static void set_mode(Mode); - /** Physiclally set the PIT frequency divider */ - static void set_freq_divider(uint16_t); + /** Physiclally set the PIT frequency divider */ + static void set_freq_divider(uint16_t); - /** Set mode to one-shot, and frequency-divider to t */ - static void oneshot(uint16_t t); + /** Set mode to one-shot, and frequency-divider to t */ + static void oneshot(uint16_t t); - /** Read back the PIT status from hardware */ - static uint8_t read_back(uint8_t channel); + /** Read back the PIT status from hardware */ + static uint8_t read_back(uint8_t channel); - /** A timer is a handler and an expiration time (interval). - @todo The timer also keeps a pre-computed rdtsc-value, which is currently unused.*/ - class Timer { - public: - enum Type { ONE_SHOT, REPEAT, REPEAT_WHILE} type_; + /** A timer is a handler and an expiration time (interval). + @todo The timer also keeps a pre-computed rdtsc-value, which is currently unused.*/ + class Timer { + public: + enum Type { ONE_SHOT, REPEAT, REPEAT_WHILE} type_; - Timer() = delete; - Timer(Type, timeout_handler, std::chrono::milliseconds, repeat_condition = forever); - Timer(const Timer&) = default; - Timer(Timer&&) = default; - Timer& operator=(Timer&) = default; - Timer& operator=(Timer&&) = default; - virtual ~Timer() = default; + Timer() = delete; + Timer(Type, timeout_handler, std::chrono::milliseconds, repeat_condition = forever); + Timer(const Timer&) = default; + Timer(Timer&&) = default; + Timer& operator=(Timer&) = default; + Timer& operator=(Timer&&) = default; + virtual ~Timer() = default; - inline Type type(){ return type_; } - inline std::chrono::milliseconds interval(){ return interval_; } - inline uint64_t start() { return timestamp_start_; } - inline uint64_t end() { return timestamp_end_; } - inline void setStart(uint64_t s) { timestamp_start_ = s; } - inline void setEnd(uint64_t e) { timestamp_end_ = e; } - inline timeout_handler handler(){ return handler_; } - inline const repeat_condition cond() { return cond_; } - inline uint32_t id(){ return id_; } - - private: - static uint32_t timers_count_; - uint32_t id_ = 0; - timeout_handler handler_; - uint64_t timestamp_start_; - uint64_t timestamp_end_; - std::chrono::milliseconds interval_; + inline Type type(){ return type_; } + inline std::chrono::milliseconds interval(){ return interval_; } + inline uint64_t start() { return timestamp_start_; } + inline uint64_t end() { return timestamp_end_; } + inline void setStart(uint64_t s) { timestamp_start_ = s; } + inline void setEnd(uint64_t e) { timestamp_end_ = e; } + inline timeout_handler handler(){ return handler_; } + inline const repeat_condition cond() { return cond_; } + inline uint32_t id(){ return id_; } + + private: + static uint32_t timers_count_; + uint32_t id_ = 0; + timeout_handler handler_; + uint64_t timestamp_start_; + uint64_t timestamp_end_; + std::chrono::milliseconds interval_; - /* This Could be a reference in the default case of "forever", but then the - case of a normal lambda being passed in, the user would have to be in charge - of storage. */ - const repeat_condition cond_; - }; - - /** A map of timers. - @note {Performance: We take advantage of the fact that std::map have sorted keys. - * Timers soonest to expire are in the front, so we only iterate over those - * Deletion of finished timers in amortized constant time, via iterators - * Timer insertion is log(n) } - @note This is why we want to instantiate PIT, and why it's a singleton: - If you don't use PIT-timers, you won't pay for them. */ - std::multimap timers_; + /* This Could be a reference in the default case of "forever", but then the + case of a normal lambda being passed in, the user would have to be in charge + of storage. */ + const repeat_condition cond_; + }; + + /** A map of timers. + @note {Performance: We take advantage of the fact that std::map have sorted keys. + * Timers soonest to expire are in the front, so we only iterate over those + * Deletion of finished timers in amortized constant time, via iterators + * Timer insertion is log(n) } + @note This is why we want to instantiate PIT, and why it's a singleton: + If you don't use PIT-timers, you won't pay for them. */ + std::multimap timers_; - /** Queue the timer. This will update timestamps in the timer */ - void start_timer(Timer t, std::chrono::milliseconds); + /** Queue the timer. This will update timestamps in the timer */ + void start_timer(Timer t, std::chrono::milliseconds); -}; + }; } //< namespace hw diff --git a/api/kernel/irq_manager.hpp b/api/kernel/irq_manager.hpp index 77b4911b6d..74dfc5d1ff 100644 --- a/api/kernel/irq_manager.hpp +++ b/api/kernel/irq_manager.hpp @@ -54,14 +54,14 @@ extern "C" { NOTES: * All IRQ-callbacks are in charge of calling End-Of-Interrupt - eoi. - Why? Because this makes it possible to prevent further interrupts until - a condition of your choice is met. And, interrupts are costly as they - always cause vm-exit. + Why? Because this makes it possible to prevent further interrupts until + a condition of your choice is met. And, interrupts are costly as they + always cause vm-exit. * IRQ-numbering: 0 or 32? @TODO: Remove all dependencies on old SanOS code. In particular, eoi is now in global scope - */ +*/ class IRQ_manager { public: using irq_delegate = delegate; @@ -90,7 +90,7 @@ class IRQ_manager { * Failure to do so will keep the interrupt from firing and cause a * stack overflow or similar badness. * } - */ + */ static void set_handler(uint8_t irq, void(*function_addr)()); /** Get handler from inside the IDT. */ @@ -100,7 +100,7 @@ class IRQ_manager { * Subscribe to an IRQ * @param irq: The IRQ to subscribe to - * @param del: A delegate to attach to the IRQ DPC-system + * @param del: A delegate to attach to the IRQ DPC-system * The delegate will be called a.s.a.p. after @param irq gets triggered * @@ -116,7 +116,7 @@ class IRQ_manager { * Get the current subscriber of an IRQ-line * * @param irq: The IRQ to get subscriber for - */ + */ static irq_delegate get_subscriber(uint8_t irq); /** @@ -169,9 +169,9 @@ class IRQ_manager { * Use "set_handler" for a simpler version using defaults */ static void create_gate(IDTDescr* idt_entry, - void (*function_addr)(), - uint16_t segment_sel, - char attributes); + void (*function_addr)(), + uint16_t segment_sel, + char attributes); /** The OS will call the following : */ friend class OS; diff --git a/api/kernel/os.hpp b/api/kernel/os.hpp index 7f64e49f4b..58f4e3fdf0 100644 --- a/api/kernel/os.hpp +++ b/api/kernel/os.hpp @@ -56,7 +56,7 @@ class OS { * Write a cstring to serial port. @todo Should be moved to Dev::serial(n). * * @param ptr: The string to write to serial port - */ + */ static size_t rsprint(const char* ptr); static size_t rsprint(const char* ptr, const size_t len); @@ -69,7 +69,7 @@ class OS { /** * Write to serial port with rswrite. - */ + */ static void default_rsprint(const char*, size_t); /** Start the OS. @todo Should be `init()` - and not accessible from ABI */ diff --git a/api/kernel/service.hpp b/api/kernel/service.hpp index 84f57f0e2f..e4c1c2e1fe 100644 --- a/api/kernel/service.hpp +++ b/api/kernel/service.hpp @@ -26,7 +26,7 @@ extern "C" const char* service_name__; * This is where you take over * * The service gets started whenever the OS is done initializing -*/ + */ class Service { public: /** diff --git a/api/kernel/terminal.hpp b/api/kernel/terminal.hpp index 21180b13ce..79257a620b 100644 --- a/api/kernel/terminal.hpp +++ b/api/kernel/terminal.hpp @@ -50,16 +50,16 @@ class Terminal using Connection_ptr = std::shared_ptr; using Disk_ptr = std::shared_ptr; enum - { - NUL = 0, - BELL = 7, - BS = 8, - HTAB = 9, - LF = 10, - VTAB = 11, - FF = 12, - CR = 13 - }; + { + NUL = 0, + BELL = 7, + BS = 8, + HTAB = 9, + LF = 10, + VTAB = 11, + FF = 12, + CR = 13 + }; using on_write_func = std::function; diff --git a/api/net/arp.hpp b/api/net/arp.hpp index b0c81c1c2b..76317161b6 100644 --- a/api/net/arp.hpp +++ b/api/net/arp.hpp @@ -27,127 +27,127 @@ namespace net { -class PacketArp; + class PacketArp; -/** ARP manager, including an ARP-Cache. */ -class Arp { -private: - /** ARP cache expires after cache_exp_t_ seconds */ - static constexpr uint16_t cache_exp_t_ {60 * 60 * 12}; - - /** Cache entries are just MAC's and timestamps */ - struct cache_entry { - Ethernet::addr mac_; - uint64_t timestamp_; + /** ARP manager, including an ARP-Cache. */ + class Arp { + private: + /** ARP cache expires after cache_exp_t_ seconds */ + static constexpr uint16_t cache_exp_t_ {60 * 60 * 12}; + + /** Cache entries are just MAC's and timestamps */ + struct cache_entry { + Ethernet::addr mac_; + uint64_t timestamp_; - /** Map needs empty constructor (we have no emplace yet) */ - cache_entry() noexcept = default; + /** Map needs empty constructor (we have no emplace yet) */ + cache_entry() noexcept = default; - cache_entry(Ethernet::addr mac) noexcept - : mac_(mac), timestamp_(OS::uptime()) {} + cache_entry(Ethernet::addr mac) noexcept + : mac_(mac), timestamp_(OS::uptime()) {} - cache_entry(const cache_entry& cpy) noexcept - : mac_(cpy.mac_), timestamp_(cpy.timestamp_) {} + cache_entry(const cache_entry& cpy) noexcept + : mac_(cpy.mac_), timestamp_(cpy.timestamp_) {} - void update() noexcept { timestamp_ = OS::uptime(); } - }; //< struct cache_entry - - using Cache = std::map; - using PacketQueue = std::map; -public: - /** - * You can assign your own ARP-resolution delegate - * - * We're doing this to keep the Hårek Haugerud mapping (HH_MAP) - */ - using Arp_resolver = delegate; - - enum Opcode { H_request = 0x100, H_reply = 0x200 }; - - /** Arp opcodes (Big-endian) */ - static constexpr uint16_t H_htype_eth {0x0100}; - static constexpr uint16_t H_ptype_ip4 {0x0008}; - static constexpr uint16_t H_hlen_plen {0x0406}; - - /** Constructor */ - explicit Arp(Inet&) noexcept; - - struct __attribute__((packed)) header { - Ethernet::header ethhdr; // Ethernet header - uint16_t htype; // Hardware type - uint16_t ptype; // Protocol type - uint16_t hlen_plen; // Protocol address length - uint16_t opcode; // Opcode - Ethernet::addr shwaddr; // Source mac - IP4::addr sipaddr; // Source ip - Ethernet::addr dhwaddr; // Target mac - IP4::addr dipaddr; // Target ip - }; - - /** Handle incoming ARP packet. */ - void bottom(Packet_ptr pckt); - - /** Roll your own arp-resolution system. */ - void set_resolver(Arp_resolver ar) - { arp_resolver_ = ar; } - - enum Resolver_name { DEFAULT, HH_MAP }; - - void set_resolver(Resolver_name nm) { - // @TODO: Add HÅREK-mapping here - switch (nm) { - case HH_MAP: - arp_resolver_ = Arp_resolver::from(*this); - break; - default: - arp_resolver_ = Arp_resolver::from(*this); - } - } - - /** Delegate link-layer output. */ - void set_linklayer_out(downstream link) - { linklayer_out_ = link; } - - /** Downstream transmission. */ - void transmit(Packet_ptr); - -private: - Inet& inet_; - - /** Needs to know which mac address to put in header->swhaddr */ - Ethernet::addr mac_; + void update() noexcept { timestamp_ = OS::uptime(); } + }; //< struct cache_entry + + using Cache = std::map; + using PacketQueue = std::map; + public: + /** + * You can assign your own ARP-resolution delegate + * + * We're doing this to keep the Hårek Haugerud mapping (HH_MAP) + */ + using Arp_resolver = delegate; + + enum Opcode { H_request = 0x100, H_reply = 0x200 }; + + /** Arp opcodes (Big-endian) */ + static constexpr uint16_t H_htype_eth {0x0100}; + static constexpr uint16_t H_ptype_ip4 {0x0008}; + static constexpr uint16_t H_hlen_plen {0x0406}; + + /** Constructor */ + explicit Arp(Inet&) noexcept; + + struct __attribute__((packed)) header { + Ethernet::header ethhdr; // Ethernet header + uint16_t htype; // Hardware type + uint16_t ptype; // Protocol type + uint16_t hlen_plen; // Protocol address length + uint16_t opcode; // Opcode + Ethernet::addr shwaddr; // Source mac + IP4::addr sipaddr; // Source ip + Ethernet::addr dhwaddr; // Target mac + IP4::addr dipaddr; // Target ip + }; + + /** Handle incoming ARP packet. */ + void bottom(Packet_ptr pckt); + + /** Roll your own arp-resolution system. */ + void set_resolver(Arp_resolver ar) + { arp_resolver_ = ar; } + + enum Resolver_name { DEFAULT, HH_MAP }; + + void set_resolver(Resolver_name nm) { + // @TODO: Add HÅREK-mapping here + switch (nm) { + case HH_MAP: + arp_resolver_ = Arp_resolver::from(*this); + break; + default: + arp_resolver_ = Arp_resolver::from(*this); + } + } + + /** Delegate link-layer output. */ + void set_linklayer_out(downstream link) + { linklayer_out_ = link; } + + /** Downstream transmission. */ + void transmit(Packet_ptr); + + private: + Inet& inet_; + + /** Needs to know which mac address to put in header->swhaddr */ + Ethernet::addr mac_; - /** Outbound data goes through here */ - downstream linklayer_out_; + /** Outbound data goes through here */ + downstream linklayer_out_; - /** The ARP cache */ - Cache cache_; + /** The ARP cache */ + Cache cache_; - /** Cache IP resolution. */ - void cache(IP4::addr, Ethernet::addr); + /** Cache IP resolution. */ + void cache(IP4::addr, Ethernet::addr); - /** Check if an IP is cached and not expired */ - bool is_valid_cached(IP4::addr); + /** Check if an IP is cached and not expired */ + bool is_valid_cached(IP4::addr); - /** ARP resolution. */ - Ethernet::addr resolve(IP4::addr); + /** ARP resolution. */ + Ethernet::addr resolve(IP4::addr); - void arp_respond(header* hdr_in); + void arp_respond(header* hdr_in); - // two different ARP resolvers - void arp_resolve(Packet_ptr); - void hh_map(Packet_ptr); + // two different ARP resolvers + void arp_resolve(Packet_ptr); + void hh_map(Packet_ptr); - Arp_resolver arp_resolver_ = Arp_resolver::from(*this); + Arp_resolver arp_resolver_ = Arp_resolver::from(*this); - PacketQueue waiting_packets_; + PacketQueue waiting_packets_; - /** Add a packet to waiting queue, to be sent when IP is resolved */ - void await_resolution(Packet_ptr, IP4::addr); + /** Add a packet to waiting queue, to be sent when IP is resolved */ + void await_resolution(Packet_ptr, IP4::addr); - /** Create a default initialized ARP-packet */ - Packet_ptr createPacket(); -}; //< class Arp + /** Create a default initialized ARP-packet */ + Packet_ptr createPacket(); + }; //< class Arp } //< namespace net diff --git a/api/net/buffer_store.hpp b/api/net/buffer_store.hpp index f552f4b31b..c215e5dcd6 100644 --- a/api/net/buffer_store.hpp +++ b/api/net/buffer_store.hpp @@ -25,80 +25,80 @@ namespace net{ -/** - * Network buffer storage for uniformly sized buffers. - * - * @note : The buffer store is intended to be used by Packet, which is - * a semi-intelligent buffer wrapper, used throughout the IP-stack. - * - * There shouldn't be any need for raw buffers in services. - **/ -class BufferStore { -public: - using buffer_t = uint8_t*; - using release_del = delegate; - - BufferStore(size_t num, size_t bufsize, size_t device_offset); - - /** Free all the buffers **/ - ~BufferStore(); - - /** Get a free buffer */ - buffer_t get_raw_buffer(); - - /** Get a free buffer, offset by device-offset */ - buffer_t get_offset_buffer(); - - /** Return a buffer. */ - void release_raw_buffer(buffer_t b, size_t); - - /** Return a buffer, offset by offset_ bytes from actual buffer. */ - void release_offset_buffer(buffer_t b, size_t); - - /** Get size of a raw buffer **/ - inline size_t raw_bufsize() - { return bufsize_; } - - inline size_t offset_bufsize() - { return bufsize_ - device_offset_; } - - /** @return the total buffer capacity in bytes */ - inline size_t capacity() - { return available_buffers_.size() * bufsize_; } - - /** Check if a buffer belongs here */ - inline bool address_is_from_pool(buffer_t addr) - { return addr >= pool_ and addr < pool_ + (bufcount_ * bufsize_); } - - /** Check if an address is the start of a buffer */ - inline bool address_is_bufstart(buffer_t addr) - { return (addr - pool_) % bufsize_ == 0; } - - /** Check if an address is the start of a buffer */ - inline bool address_is_offset_bufstart(buffer_t addr) - { return (addr - pool_ - device_offset_) % bufsize_ == 0; } - - inline size_t buffers_available() - { return available_buffers_.size(); } - -private: - size_t bufcount_; - const size_t bufsize_; - size_t device_offset_; - buffer_t pool_; - std::deque available_buffers_; - - /** Delete move and copy operations **/ - BufferStore(BufferStore&) = delete; - BufferStore(BufferStore&&) = delete; - BufferStore& operator=(BufferStore&) = delete; - BufferStore operator=(BufferStore&&) = delete; - - /** Prohibit default construction **/ - BufferStore() = delete; - - void increaseStorage(); -}; //< class BufferStore + /** + * Network buffer storage for uniformly sized buffers. + * + * @note : The buffer store is intended to be used by Packet, which is + * a semi-intelligent buffer wrapper, used throughout the IP-stack. + * + * There shouldn't be any need for raw buffers in services. + **/ + class BufferStore { + public: + using buffer_t = uint8_t*; + using release_del = delegate; + + BufferStore(size_t num, size_t bufsize, size_t device_offset); + + /** Free all the buffers **/ + ~BufferStore(); + + /** Get a free buffer */ + buffer_t get_raw_buffer(); + + /** Get a free buffer, offset by device-offset */ + buffer_t get_offset_buffer(); + + /** Return a buffer. */ + void release_raw_buffer(buffer_t b, size_t); + + /** Return a buffer, offset by offset_ bytes from actual buffer. */ + void release_offset_buffer(buffer_t b, size_t); + + /** Get size of a raw buffer **/ + inline size_t raw_bufsize() + { return bufsize_; } + + inline size_t offset_bufsize() + { return bufsize_ - device_offset_; } + + /** @return the total buffer capacity in bytes */ + inline size_t capacity() + { return available_buffers_.size() * bufsize_; } + + /** Check if a buffer belongs here */ + inline bool address_is_from_pool(buffer_t addr) + { return addr >= pool_ and addr < pool_ + (bufcount_ * bufsize_); } + + /** Check if an address is the start of a buffer */ + inline bool address_is_bufstart(buffer_t addr) + { return (addr - pool_) % bufsize_ == 0; } + + /** Check if an address is the start of a buffer */ + inline bool address_is_offset_bufstart(buffer_t addr) + { return (addr - pool_ - device_offset_) % bufsize_ == 0; } + + inline size_t buffers_available() + { return available_buffers_.size(); } + + private: + size_t bufcount_; + const size_t bufsize_; + size_t device_offset_; + buffer_t pool_; + std::deque available_buffers_; + + /** Delete move and copy operations **/ + BufferStore(BufferStore&) = delete; + BufferStore(BufferStore&&) = delete; + BufferStore& operator=(BufferStore&) = delete; + BufferStore operator=(BufferStore&&) = delete; + + /** Prohibit default construction **/ + BufferStore() = delete; + + void increaseStorage(); + }; //< class BufferStore } //< namespace net #endif //< NET_BUFFER_STORE_HPP diff --git a/api/net/dns/client.hpp b/api/net/dns/client.hpp index 93b61d59c8..f8b76bdeb6 100644 --- a/api/net/dns/client.hpp +++ b/api/net/dns/client.hpp @@ -30,12 +30,12 @@ namespace net using Stack = Inet; DNSClient(Stack& stk) - : stack(stk) {} + : stack(stk) {} /** * @func a delegate that provides a hostname and its address, which is 0 if the * name @hostname was not found. Note: Test with INADDR_ANY for a 0-address. - **/ + **/ void resolve(IP4::addr dns_server, const std::string& hostname, Stack::resolve_func func); diff --git a/api/net/dns/dns.hpp b/api/net/dns/dns.hpp index d54a11c02a..f15bf3ea22 100644 --- a/api/net/dns/dns.hpp +++ b/api/net/dns/dns.hpp @@ -116,14 +116,14 @@ namespace net #pragma pack(pop) enum resp_code - { - NO_ERROR = 0, - FORMAT_ERROR = 1, - SERVER_FAIL = 2, - NAME_ERROR = 3, - NOT_IMPL = 4, // unimplemented feature - OP_REFUSED = 5, // for political reasons - }; + { + NO_ERROR = 0, + FORMAT_ERROR = 1, + SERVER_FAIL = 2, + NAME_ERROR = 3, + NOT_IMPL = 4, // unimplemented feature + OP_REFUSED = 5, // for political reasons + }; typedef std::function* (const std::string&)> lookup_func; @@ -132,18 +132,18 @@ namespace net static std::string question_string(unsigned short type) { switch (type) - { - case DNS_TYPE_A: - return "IPv4 address"; - case DNS_TYPE_ALIAS: - return "Alias"; - case DNS_TYPE_MX: - return "Mail exchange"; - case DNS_TYPE_NS: - return "Name server"; - default: - return "FIXME DNS::question_string(type = " + std::to_string(type) + ")"; - } + { + case DNS_TYPE_A: + return "IPv4 address"; + case DNS_TYPE_ALIAS: + return "Alias"; + case DNS_TYPE_MX: + return "Mail exchange"; + case DNS_TYPE_NS: + return "Name server"; + default: + return "FIXME DNS::question_string(type = " + std::to_string(type) + ")"; + } } class Request @@ -161,7 +161,7 @@ namespace net { IP4::addr result{{0}}; if (answers.size()) - result = answers[0].getIP4(); + result = answers[0].getIP4(); return result; } diff --git a/api/net/inet.hpp b/api/net/inet.hpp index 198b153d4d..761d64614f 100644 --- a/api/net/inet.hpp +++ b/api/net/inet.hpp @@ -22,54 +22,54 @@ namespace net { -class TCP; -class UDP; -class DHClient; + class TCP; + class UDP; + class DHClient; -/** An abstract IP-stack interface */ -template -class Inet { -public: - using Stack = Inet; + /** An abstract IP-stack interface */ + template + class Inet { + public: + using Stack = Inet; - template - using resolve_func = delegate; + template + using resolve_func = delegate; - virtual typename IPV::addr ip_addr() = 0; - virtual typename IPV::addr netmask() = 0; - virtual typename IPV::addr router() = 0; - virtual typename LINKLAYER::addr link_addr() = 0; + virtual typename IPV::addr ip_addr() = 0; + virtual typename IPV::addr netmask() = 0; + virtual typename IPV::addr router() = 0; + virtual typename LINKLAYER::addr link_addr() = 0; - virtual LINKLAYER& link() = 0; - virtual IPV& ip_obj() = 0; - virtual TCP& tcp() = 0; - virtual UDP& udp() = 0; + virtual LINKLAYER& link() = 0; + virtual IPV& ip_obj() = 0; + virtual TCP& tcp() = 0; + virtual UDP& udp() = 0; - virtual std::shared_ptr dhclient() = 0; + virtual std::shared_ptr dhclient() = 0; - virtual uint16_t MTU() const = 0; + virtual uint16_t MTU() const = 0; - virtual Packet_ptr createPacket(size_t size) = 0; + virtual Packet_ptr createPacket(size_t size) = 0; - virtual void resolve(const std::string& hostname, resolve_func func) = 0; + virtual void resolve(const std::string& hostname, resolve_func func) = 0; - virtual void set_dns_server(typename IPV::addr server) = 0; + virtual void set_dns_server(typename IPV::addr server) = 0; - virtual void network_config(typename IPV::addr ip, - typename IPV::addr nmask, - typename IPV::addr router, - typename IPV::addr dnssrv) = 0; + virtual void network_config(typename IPV::addr ip, + typename IPV::addr nmask, + typename IPV::addr router, + typename IPV::addr dnssrv) = 0; - /** Event triggered when there are available buffers in the transmit queue */ - virtual void on_transmit_queue_available(transmit_avail_delg del) = 0; + /** Event triggered when there are available buffers in the transmit queue */ + virtual void on_transmit_queue_available(transmit_avail_delg del) = 0; - /** Number of packets the transmit queue has room for */ - virtual size_t transmit_queue_available() = 0; + /** Number of packets the transmit queue has room for */ + virtual size_t transmit_queue_available() = 0; - /** Number of buffers available in the bufstore */ - virtual size_t buffers_available() = 0; + /** Number of buffers available in the bufstore */ + virtual size_t buffers_available() = 0; -}; //< class Inet + }; //< class Inet } //< namespace net #endif diff --git a/api/net/inet4.hpp b/api/net/inet4.hpp index 36f0a3db10..83ec392339 100644 --- a/api/net/inet4.hpp +++ b/api/net/inet4.hpp @@ -93,7 +93,7 @@ namespace net { /** * @func a delegate that provides a hostname and its address, which is 0 if the * name @hostname was not found. Note: Test with INADDR_ANY for a 0-address. - **/ + **/ inline virtual void resolve(const std::string& hostname, resolve_func func) override diff --git a/api/net/inet64.hpp b/api/net/inet64.hpp index 471f603762..dc323cc365 100644 --- a/api/net/inet64.hpp +++ b/api/net/inet64.hpp @@ -62,7 +62,7 @@ namespace net { } /// send an UDPv6 packet, hopefully (please dont lie!) std::shared_ptr udp6_create( - Ethernet::addr ether_dest, const IP6::addr& ip_dest, UDPv6::port_t port) + Ethernet::addr ether_dest, const IP6::addr& ip_dest, UDPv6::port_t port) { return _udp6.create(ether_dest, ip_dest, port); } @@ -79,13 +79,13 @@ namespace net { } /** Bind an IP and a netmask to a given device. - The function expects the given device to exist.*/ + The function expects the given device to exist.*/ static void ifconfig( - netdev nic, - IP4::addr ip, - IP4::addr netmask, - IP6::addr ip6); + netdev nic, + IP4::addr ip, + IP4::addr netmask, + IP6::addr ip6); inline static IP4::addr ip4(netdev nic) { return _ip4_list[nic]; } @@ -125,7 +125,7 @@ namespace net { /** Don't think we *want* copy construction. @todo: Fix this with a singleton or something. - */ + */ Inet(Inet& UNUSED(cpy)) = delete; Inet(std::vector ips); diff --git a/api/net/ip4.hpp b/api/net/ip4.hpp index 85905ddadd..4414c88836 100644 --- a/api/net/ip4.hpp +++ b/api/net/ip4.hpp @@ -26,147 +26,147 @@ namespace net { -// Default delegate assignments -void ignore_ip4_up(Packet_ptr); -void ignore_ip4_down(Packet_ptr); + // Default delegate assignments + void ignore_ip4_up(Packet_ptr); + void ignore_ip4_down(Packet_ptr); -/** IP4 layer */ -class IP4 { -public: - /** Initialize. Sets a dummy linklayer out. */ - explicit IP4(Inet&) noexcept; + /** IP4 layer */ + class IP4 { + public: + /** Initialize. Sets a dummy linklayer out. */ + explicit IP4(Inet&) noexcept; - /** Known transport layer protocols. */ - enum proto { IP4_ICMP=1, IP4_UDP=17, IP4_TCP=6 }; + /** Known transport layer protocols. */ + enum proto { IP4_ICMP=1, IP4_UDP=17, IP4_TCP=6 }; - /** IP4 address representation */ - union __attribute__((packed)) addr { - uint8_t part[4]; - uint32_t whole; + /** IP4 address representation */ + union __attribute__((packed)) addr { + uint8_t part[4]; + uint32_t whole; - /** - * NOTE: Constructors - * Can't have them - removes the packed-attribute - */ + /** + * NOTE: Constructors + * Can't have them - removes the packed-attribute + */ - inline addr& operator=(addr cpy) noexcept { - whole = cpy.whole; - return *this; - } + inline addr& operator=(addr cpy) noexcept { + whole = cpy.whole; + return *this; + } - /** Standard comparison operators */ - inline bool operator==(addr rhs) const noexcept - { return whole == rhs.whole; } + /** Standard comparison operators */ + inline bool operator==(addr rhs) const noexcept + { return whole == rhs.whole; } - inline bool operator==(const uint32_t rhs) const noexcept - { return whole == rhs; } + inline bool operator==(const uint32_t rhs) const noexcept + { return whole == rhs; } - inline bool operator<(const addr rhs) const noexcept - { return whole < rhs.whole; } + inline bool operator<(const addr rhs) const noexcept + { return whole < rhs.whole; } - inline bool operator<(const uint32_t rhs) const noexcept - { return whole < rhs; } + inline bool operator<(const uint32_t rhs) const noexcept + { return whole < rhs; } - inline bool operator>(const addr rhs) const noexcept - { return whole > rhs.whole; } + inline bool operator>(const addr rhs) const noexcept + { return whole > rhs.whole; } - inline bool operator>(const uint32_t rhs) const noexcept - { return whole > rhs; } + inline bool operator>(const uint32_t rhs) const noexcept + { return whole > rhs; } - inline bool operator!=(const addr rhs) const noexcept - { return whole != rhs.whole; } + inline bool operator!=(const addr rhs) const noexcept + { return whole != rhs.whole; } - inline bool operator!=(const uint32_t rhs) const noexcept - { return whole != rhs; } + inline bool operator!=(const uint32_t rhs) const noexcept + { return whole != rhs; } - /** x.x.x.x string representation */ - std::string str() const { - char ip_addr[16]; - sprintf(ip_addr, "%1i.%1i.%1i.%1i", - part[0], part[1], part[2], part[3]); - return ip_addr; - } - }; //< union addr + /** x.x.x.x string representation */ + std::string str() const { + char ip_addr[16]; + sprintf(ip_addr, "%1i.%1i.%1i.%1i", + part[0], part[1], part[2], part[3]); + return ip_addr; + } + }; //< union addr - static const addr INADDR_ANY; - static const addr INADDR_BCAST; + static const addr INADDR_ANY; + static const addr INADDR_BCAST; - /** IP4 header representation */ - struct ip_header { - uint8_t version_ihl; - uint8_t tos; - uint16_t tot_len; - uint16_t id; - uint16_t frag_off_flags; - uint8_t ttl; - uint8_t protocol; - uint16_t check; - addr saddr; - addr daddr; - }; + /** IP4 header representation */ + struct ip_header { + uint8_t version_ihl; + uint8_t tos; + uint16_t tot_len; + uint16_t id; + uint16_t frag_off_flags; + uint8_t ttl; + uint8_t protocol; + uint16_t check; + addr saddr; + addr daddr; + }; - /** - * The full header including IP - * - * @Note: This might be removed if we decide to isolate layers more - */ - struct full_header { - uint8_t link_hdr[sizeof(typename LinkLayer::header)]; - ip_header ip_hdr; - }; + /** + * The full header including IP + * + * @Note: This might be removed if we decide to isolate layers more + */ + struct full_header { + uint8_t link_hdr[sizeof(typename LinkLayer::header)]; + ip_header ip_hdr; + }; - /** Upstream: Input from link layer */ - void bottom(Packet_ptr); + /** Upstream: Input from link layer */ + void bottom(Packet_ptr); - /** Upstream: Outputs to transport layer */ - inline void set_icmp_handler(upstream s) - { icmp_handler_ = s; } + /** Upstream: Outputs to transport layer */ + inline void set_icmp_handler(upstream s) + { icmp_handler_ = s; } - inline void set_udp_handler(upstream s) - { udp_handler_ = s; } + inline void set_udp_handler(upstream s) + { udp_handler_ = s; } - inline void set_tcp_handler(upstream s) - { tcp_handler_ = s; } + inline void set_tcp_handler(upstream s) + { tcp_handler_ = s; } - /** Downstream: Delegate linklayer out */ - void set_linklayer_out(downstream s) - { linklayer_out_ = s; }; + /** Downstream: Delegate linklayer out */ + void set_linklayer_out(downstream s) + { linklayer_out_ = s; }; - /** - * Downstream: Receive data from above and transmit - * - * @note: The following *must be set* in the packet: - * - * * Destination IP - * * Protocol - * - * Source IP *can* be set - if it's not, IP4 will set it - */ - void transmit(Packet_ptr); + /** + * Downstream: Receive data from above and transmit + * + * @note: The following *must be set* in the packet: + * + * * Destination IP + * * Protocol + * + * Source IP *can* be set - if it's not, IP4 will set it + */ + void transmit(Packet_ptr); - /** Compute the IP4 header checksum */ - uint16_t checksum(ip_header*); + /** Compute the IP4 header checksum */ + uint16_t checksum(ip_header*); - /** - * \brief - * - * Returns the IPv4 address associated with this interface - **/ - const addr local_ip() const { - return stack_.ip_addr(); - } + /** + * \brief + * + * Returns the IPv4 address associated with this interface + **/ + const addr local_ip() const { + return stack_.ip_addr(); + } -private: - Inet& stack_; + private: + Inet& stack_; - /** Downstream: Linklayer output delegate */ - downstream linklayer_out_ {ignore_ip4_down}; + /** Downstream: Linklayer output delegate */ + downstream linklayer_out_ {ignore_ip4_down}; - /** Upstream delegates */ - upstream icmp_handler_ {ignore_ip4_up}; - upstream udp_handler_ {ignore_ip4_up}; - upstream tcp_handler_ {ignore_ip4_up}; -}; //< class IP4 + /** Upstream delegates */ + upstream icmp_handler_ {ignore_ip4_up}; + upstream udp_handler_ {ignore_ip4_up}; + upstream tcp_handler_ {ignore_ip4_up}; + }; //< class IP4 } //< namespace net #endif diff --git a/api/net/ip4/icmpv4.hpp b/api/net/ip4/icmpv4.hpp index d0787fd783..084f2b0860 100644 --- a/api/net/ip4/icmpv4.hpp +++ b/api/net/ip4/icmpv4.hpp @@ -23,44 +23,44 @@ namespace net { -void icmp_default_out(Packet_ptr); + void icmp_default_out(Packet_ptr); -class ICMPv4 { -public: - // Initialize - ICMPv4(Inet&); + class ICMPv4 { + public: + // Initialize + ICMPv4(Inet&); - // Known ICMP types - enum icmp_types { ICMP_ECHO_REPLY, ICMP_ECHO = 8 }; + // Known ICMP types + enum icmp_types { ICMP_ECHO_REPLY, ICMP_ECHO = 8 }; - struct icmp_header { - uint8_t type; - uint8_t code; - uint16_t checksum; - uint16_t identifier; - uint16_t sequence; - uint8_t payload[0]; - }__attribute__((packed)); + struct icmp_header { + uint8_t type; + uint8_t code; + uint16_t checksum; + uint16_t identifier; + uint16_t sequence; + uint8_t payload[0]; + }__attribute__((packed)); - struct full_header { - LinkLayer::header link_hdr; - IP4::ip_header ip_hdr; - icmp_header icmp_hdr; - }__attribute__((packed)); + struct full_header { + LinkLayer::header link_hdr; + IP4::ip_header ip_hdr; + icmp_header icmp_hdr; + }__attribute__((packed)); - // Input from network layer - void bottom(Packet_ptr); + // Input from network layer + void bottom(Packet_ptr); - // Delegate output to network layer - inline void set_network_out(downstream s) - { network_layer_out_ = s; }; + // Delegate output to network layer + inline void set_network_out(downstream s) + { network_layer_out_ = s; }; -private: - Inet& inet_; - downstream network_layer_out_ {icmp_default_out}; + private: + Inet& inet_; + downstream network_layer_out_ {icmp_default_out}; - void ping_reply(full_header* full_hdr, uint16_t size); -}; //< class ICMPv4 + void ping_reply(full_header* full_hdr, uint16_t size); + }; //< class ICMPv4 } //< namespace net #endif //< NET_IP4_ICMPv4_HPP diff --git a/api/net/ip4/packet_ip4.hpp b/api/net/ip4/packet_ip4.hpp index 7076fce840..918ec77f1d 100644 --- a/api/net/ip4/packet_ip4.hpp +++ b/api/net/ip4/packet_ip4.hpp @@ -25,70 +25,70 @@ namespace net { -class PacketIP4 : public Packet, // might work as upcast: - public std::enable_shared_from_this -{ -public: - static constexpr size_t DEFAULT_TTL {64}; + class PacketIP4 : public Packet, // might work as upcast: + public std::enable_shared_from_this + { + public: + static constexpr size_t DEFAULT_TTL {64}; - const IP4::addr& src() const noexcept - { return ip4_header().saddr; } + const IP4::addr& src() const noexcept + { return ip4_header().saddr; } - void set_src(const IP4::addr& addr) noexcept - { ip4_header().saddr = addr; } + void set_src(const IP4::addr& addr) noexcept + { ip4_header().saddr = addr; } - const IP4::addr& dst() const noexcept - { return ip4_header().daddr; } + const IP4::addr& dst() const noexcept + { return ip4_header().daddr; } - void set_dst(const IP4::addr& addr) noexcept - { ip4_header().daddr = addr; } + void set_dst(const IP4::addr& addr) noexcept + { ip4_header().daddr = addr; } - void set_protocol(IP4::proto p) noexcept - { ip4_header().protocol = p; } + void set_protocol(IP4::proto p) noexcept + { ip4_header().protocol = p; } - uint8_t protocol() const noexcept - { return ip4_header().protocol; } + uint8_t protocol() const noexcept + { return ip4_header().protocol; } - uint16_t ip4_segment_size() const noexcept - { return ntohs(ip4_header().tot_len); } + uint16_t ip4_segment_size() const noexcept + { return ntohs(ip4_header().tot_len); } - /** Last modifications before transmission */ - void make_flight_ready() noexcept { - assert( ip4_header().protocol ); - set_segment_length(); - set_ip4_checksum(); - } + /** Last modifications before transmission */ + void make_flight_ready() noexcept { + assert( ip4_header().protocol ); + set_segment_length(); + set_ip4_checksum(); + } - void init() noexcept { - ip4_header().version_ihl = 0x45; - ip4_header().tos = 0; - ip4_header().id = 0; - ip4_header().frag_off_flags = 0; - ip4_header().ttl = DEFAULT_TTL; - } + void init() noexcept { + ip4_header().version_ihl = 0x45; + ip4_header().tos = 0; + ip4_header().id = 0; + ip4_header().frag_off_flags = 0; + ip4_header().ttl = DEFAULT_TTL; + } -private: - const IP4::ip_header& ip4_header() const noexcept - { return (reinterpret_cast(buffer()))->ip_hdr; } + private: + const IP4::ip_header& ip4_header() const noexcept + { return (reinterpret_cast(buffer()))->ip_hdr; } - IP4::ip_header& ip4_header() noexcept - { return (reinterpret_cast(buffer()))->ip_hdr; } + IP4::ip_header& ip4_header() noexcept + { return (reinterpret_cast(buffer()))->ip_hdr; } - /** - * Set IP4 header length - * - * Inferred from packet size and linklayer header size - */ - void set_segment_length() noexcept - { ip4_header().tot_len = htons(size() - sizeof(LinkLayer::header)); } + /** + * Set IP4 header length + * + * Inferred from packet size and linklayer header size + */ + void set_segment_length() noexcept + { ip4_header().tot_len = htons(size() - sizeof(LinkLayer::header)); } - void set_ip4_checksum() noexcept { - auto& hdr = ip4_header(); - hdr.check = 0; - hdr.check = net::checksum(&hdr, sizeof(IP4::ip_header)); - } + void set_ip4_checksum() noexcept { + auto& hdr = ip4_header(); + hdr.check = 0; + hdr.check = net::checksum(&hdr, sizeof(IP4::ip_header)); + } -}; //< class PacketIP4 + }; //< class PacketIP4 } //< namespace net #endif //< IP4_PACKET_IP4_HPP diff --git a/api/net/ip4/udp.hpp b/api/net/ip4/udp.hpp index be016c3b87..21c6245d6a 100644 --- a/api/net/ip4/udp.hpp +++ b/api/net/ip4/udp.hpp @@ -25,77 +25,77 @@ namespace net { -class PacketUDP; + class PacketUDP; -template -class Socket; + template + class Socket; -void ignore_udp(Packet_ptr); + void ignore_udp(Packet_ptr); -/** Basic UDP support. @todo Implement UDP sockets. */ -class UDP { -public: - using addr_t = IP4::addr; + /** Basic UDP support. @todo Implement UDP sockets. */ + class UDP { + public: + using addr_t = IP4::addr; - /** UDP port number */ - using port_t = uint16_t; + /** UDP port number */ + using port_t = uint16_t; - using Socket = Socket; - using Stack = Inet; + using Socket = Socket; + using Stack = Inet; - /** UDP header */ - struct udp_header { - port_t sport; - port_t dport; - uint16_t length; - uint16_t checksum; - }; + /** UDP header */ + struct udp_header { + port_t sport; + port_t dport; + uint16_t length; + uint16_t checksum; + }; - /** Full UDP Header with all sub-headers */ - struct full_header { - IP4::full_header full_hdr; - udp_header udp_hdr; - }__attribute__((packed)); + /** Full UDP Header with all sub-headers */ + struct full_header { + IP4::full_header full_hdr; + udp_header udp_hdr; + }__attribute__((packed)); - //////////////////////////////////////////// + //////////////////////////////////////////// - inline addr_t local_ip() const - { return stack_.ip_addr(); } + inline addr_t local_ip() const + { return stack_.ip_addr(); } - /** Input from network layer */ - void bottom(Packet_ptr); + /** Input from network layer */ + void bottom(Packet_ptr); - /** Delegate output to network layer */ - inline void set_network_out(downstream del) - { network_layer_out_ = del; } + /** Delegate output to network layer */ + inline void set_network_out(downstream del) + { network_layer_out_ = del; } - /** Send UDP datagram from source ip/port to destination ip/port. + /** Send UDP datagram from source ip/port to destination ip/port. - @param sip Local IP-address - @param sport Local port - @param dip Remote IP-address - @param dport Remote port */ - void transmit(std::shared_ptr udp); + @param sip Local IP-address + @param sport Local port + @param dip Remote IP-address + @param dport Remote port */ + void transmit(std::shared_ptr udp); - //! @param port local port - Socket& bind(port_t port); + //! @param port local port + Socket& bind(port_t port); - //! returns a new UDP socket bound to a random port - Socket& bind(); + //! returns a new UDP socket bound to a random port + Socket& bind(); - //! construct this UDP module with @inet - UDP(Stack& inet) : - network_layer_out_ {ignore_udp}, - stack_ {inet} - { } -private: - downstream network_layer_out_; - Stack& stack_; - std::map ports_; - port_t current_port_ {1024}; + //! construct this UDP module with @inet + UDP(Stack& inet) : + network_layer_out_ {ignore_udp}, + stack_ {inet} + { } + private: + downstream network_layer_out_; + Stack& stack_; + std::map ports_; + port_t current_port_ {1024}; - friend class SocketUDP; -}; //< class UDP + friend class SocketUDP; + }; //< class UDP } //< namespace net #include "packet_udp.hpp" diff --git a/api/net/ip6/icmp6.hpp b/api/net/ip6/icmp6.hpp index eb4d48d0e4..b26d28e5c5 100644 --- a/api/net/ip6/icmp6.hpp +++ b/api/net/ip6/icmp6.hpp @@ -144,6 +144,6 @@ namespace net size_ = sizeof(IP6::full_header) + icmp_len; } - }; + }; } diff --git a/api/net/ip6/ip6.hpp b/api/net/ip6/ip6.hpp index 31db6d09f0..1378c2021d 100644 --- a/api/net/ip6/ip6.hpp +++ b/api/net/ip6/ip6.hpp @@ -43,17 +43,17 @@ namespace net public: /** Known transport layer protocols. */ enum proto - { - PROTO_HOPOPT = 0, // IPv6 hop-by-hop + { + PROTO_HOPOPT = 0, // IPv6 hop-by-hop - PROTO_ICMPv4 = 1, - PROTO_TCP = 6, - PROTO_UDP = 17, + PROTO_ICMPv4 = 1, + PROTO_TCP = 6, + PROTO_UDP = 17, - PROTO_ICMPv6 = 58, // IPv6 ICMP - PROTO_NoNext = 59, // no next-header - PROTO_OPTSv6 = 60, // dest options - }; + PROTO_ICMPv6 = 58, // IPv6 ICMP + PROTO_NoNext = 59, // no next-header + PROTO_OPTSv6 = 60, // dest options + }; struct addr { @@ -64,11 +64,11 @@ namespace net uint16_t c1, uint16_t c2, uint16_t d1, uint16_t d2) { i128 = _mm_set_epi16( - //d2, d1, c2, c1, b2, b1, a2, a1); - htons(d2), htons(d1), - htons(c2), htons(c1), - htons(b2), htons(b1), - htons(a2), htons(a1)); + //d2, d1, c2, c1, b2, b1, a2, a1); + htons(d2), htons(d1), + htons(c2), htons(c1), + htons(b2), htons(b1), + htons(a2), htons(a1)); } addr(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { @@ -121,15 +121,15 @@ namespace net bool is_multicast() const { /** - RFC 4291 2.7 Multicast Addresses + RFC 4291 2.7 Multicast Addresses - An IPv6 multicast address is an identifier for a group of interfaces - (typically on different nodes). An interface may belong to any - number of multicast groups. Multicast addresses have the following format: - | 8 | 4 | 4 | 112 bits | - +------ -+----+----+---------------------------------------------+ - |11111111|flgs|scop| group ID | - +--------+----+----+---------------------------------------------+ + An IPv6 multicast address is an identifier for a group of interfaces + (typically on different nodes). An interface may belong to any + number of multicast groups. Multicast addresses have the following format: + | 8 | 4 | 4 | 112 bits | + +------ -+----+----+---------------------------------------------+ + |11111111|flgs|scop| group ID | + +--------+----+----+---------------------------------------------+ **/ return i8[0] == 0xFF; } @@ -142,7 +142,7 @@ namespace net }; } __attribute__((aligned(alignof(__m128i)))); - #pragma pack(push, 1) +#pragma pack(push, 1) class header { public: @@ -153,7 +153,7 @@ namespace net uint8_t tclass() const { return ((scanline[0] & 0xF000) >> 12) + - (scanline[0] & 0xF); + (scanline[0] & 0xF); } // initializes the first scanline with the IPv6 version void init_scan0() @@ -164,7 +164,7 @@ namespace net uint16_t size() const { return ((scanline[1] & 0x00FF) << 8) + - ((scanline[1] & 0xFF00) >> 8); + ((scanline[1] & 0xFF00) >> 8); } void set_size(uint16_t newsize) { @@ -218,7 +218,7 @@ namespace net return hdr_ext_len; } }; - #pragma pack(pop) +#pragma pack(pop) struct full_header { @@ -243,25 +243,25 @@ namespace net static std::string protocol_name(uint8_t protocol) { switch (protocol) - { - case PROTO_HOPOPT: - return "IPv6 Hop-By-Hop (0)"; + { + case PROTO_HOPOPT: + return "IPv6 Hop-By-Hop (0)"; - case PROTO_TCP: - return "TCPv6 (6)"; - case PROTO_UDP: - return "UDPv6 (17)"; + case PROTO_TCP: + return "TCPv6 (6)"; + case PROTO_UDP: + return "UDPv6 (17)"; - case PROTO_ICMPv6: - return "ICMPv6 (58)"; - case PROTO_NoNext: - return "No next header (59)"; - case PROTO_OPTSv6: - return "IPv6 destination options (60)"; + case PROTO_ICMPv6: + return "ICMPv6 (58)"; + case PROTO_NoNext: + return "No next header (59)"; + case PROTO_OPTSv6: + return "IPv6 destination options (60)"; - default: - return "Unknown: " + std::to_string(protocol); - } + default: + return "Unknown: " + std::to_string(protocol); + } } // handler for upstream IPv6 packets @@ -283,7 +283,7 @@ namespace net // creates a new IPv6 packet to be sent over the ether static std::shared_ptr create(uint8_t proto, - Ethernet::addr ether_dest, const IP6::addr& dest); + Ethernet::addr ether_dest, const IP6::addr& dest); private: addr local; diff --git a/api/net/ip6/udp6.hpp b/api/net/ip6/udp6.hpp index 66ac4ec510..30ca33a5f8 100644 --- a/api/net/ip6/udp6.hpp +++ b/api/net/ip6/udp6.hpp @@ -72,7 +72,7 @@ namespace net // creates a new packet to be sent over the ether std::shared_ptr create( - Ethernet::addr ether_dest, const IP6::addr& dest, port_t port); + Ethernet::addr ether_dest, const IP6::addr& dest, port_t port); private: std::map listeners; @@ -125,7 +125,7 @@ namespace net header().length = htons(sizeof(UDPv6::header) + newlen); // new total IPv6 payload length ip6_header().set_size( - sizeof(IP6::header) + sizeof(UDPv6::header) + newlen); + sizeof(IP6::header) + sizeof(UDPv6::header) + newlen); // new total packet length size_ = sizeof(IP6::full_header) + sizeof(UDPv6::header) + newlen; } diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index de585587be..a29dbed345 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -29,1206 +29,1206 @@ #include // enable_shared_from_this inline unsigned round_up(unsigned n, unsigned div) { - assert(n); - return (n + div - 1) / div; + assert(n); + return (n + div - 1) / div; } namespace net { -class TCP { -public: - using Address = IP4::addr; - using Port = uint16_t; - /* - A Sequence number (SYN/ACK) (32 bits) - */ - using Seq = uint32_t; + class TCP { + public: + using Address = IP4::addr; + using Port = uint16_t; + /* + A Sequence number (SYN/ACK) (32 bits) + */ + using Seq = uint32_t; - class Packet; - using Packet_ptr = std::shared_ptr; + class Packet; + using Packet_ptr = std::shared_ptr; - class TCPException; - class TCPBadOptionException; + class TCPException; + class TCPBadOptionException; - class Connection; - using Connection_ptr = std::shared_ptr; - using IPStack = Inet; + class Connection; + using Connection_ptr = std::shared_ptr; + using IPStack = Inet; -public: - /* - An IP address and a Port. - */ - class Socket { - public: - /* - Intialize an empty socket. - */ - inline Socket() : address_(), port_(0) { address_.whole = 0; }; - - /* - Create a socket with a Address and Port. - */ - inline Socket(Address address, Port port) : address_(address), port_(port) {}; - - /* - Returns the Socket's address. - */ - inline const TCP::Address address() const { return address_; } - - /* - Returns the Socket's port. - */ - inline TCP::Port port() const { return port_; } - - /* - Returns a string in the format "Address:Port". - */ - std::string to_string() const { - std::stringstream ss; - ss << address_.str() << ":" << port_; - return ss.str(); - } - - inline bool is_empty() const { return (address_.whole == 0 and port_ == 0); } - - /* - Comparator used for vector. - */ - inline bool operator ==(const Socket &s2) const { - return address().whole == s2.address().whole - and port() == s2.port(); - } - - /* - Comparator used for map. - */ - inline bool operator <(const Socket& s2) const { - return address().whole < s2.address().whole - or (address().whole == s2.address().whole and port() < s2.port()); - } - - private: - //SocketID id_; // Maybe a hash or something. Not sure if needed (yet) - TCP::Address address_; - TCP::Port port_; - - }; // << class TCP::Socket - - - /////// TCP Stuff - Relevant to the protocol ///// + public: + /* + An IP address and a Port. + */ + class Socket { + public: + /* + Intialize an empty socket. + */ + inline Socket() : address_(), port_(0) { address_.whole = 0; }; + + /* + Create a socket with a Address and Port. + */ + inline Socket(Address address, Port port) : address_(address), port_(port) {}; + + /* + Returns the Socket's address. + */ + inline const TCP::Address address() const { return address_; } + + /* + Returns the Socket's port. + */ + inline TCP::Port port() const { return port_; } + + /* + Returns a string in the format "Address:Port". + */ + std::string to_string() const { + std::stringstream ss; + ss << address_.str() << ":" << port_; + return ss.str(); + } + + inline bool is_empty() const { return (address_.whole == 0 and port_ == 0); } + + /* + Comparator used for vector. + */ + inline bool operator ==(const Socket &s2) const { + return address().whole == s2.address().whole + and port() == s2.port(); + } + + /* + Comparator used for map. + */ + inline bool operator <(const Socket& s2) const { + return address().whole < s2.address().whole + or (address().whole == s2.address().whole and port() < s2.port()); + } + + private: + //SocketID id_; // Maybe a hash or something. Not sure if needed (yet) + TCP::Address address_; + TCP::Port port_; + + }; // << class TCP::Socket + + + /////// TCP Stuff - Relevant to the protocol ///// - static constexpr uint16_t default_window_size = 0xffff; + static constexpr uint16_t default_window_size = 0xffff; - static constexpr uint16_t default_mss = 536; + static constexpr uint16_t default_mss = 536; - /* - Flags (Control bits) in the TCP Header. - */ - enum Flag { - NS = (1 << 8), // Nounce (Experimental: see RFC 3540) - CWR = (1 << 7), // Congestion Window Reduced - ECE = (1 << 6), // ECN-Echo - URG = (1 << 5), // Urgent - ACK = (1 << 4), // Acknowledgement - PSH = (1 << 3), // Push - RST = (1 << 2), // Reset - SYN = (1 << 1), // Syn(chronize) - FIN = 1, // Fin(ish) + /* + Flags (Control bits) in the TCP Header. + */ + enum Flag { + NS = (1 << 8), // Nounce (Experimental: see RFC 3540) + CWR = (1 << 7), // Congestion Window Reduced + ECE = (1 << 6), // ECN-Echo + URG = (1 << 5), // Urgent + ACK = (1 << 4), // Acknowledgement + PSH = (1 << 3), // Push + RST = (1 << 2), // Reset + SYN = (1 << 1), // Syn(chronize) + FIN = 1, // Fin(ish) }; /* - Representation of the TCP Header. - - RFC 793, (p.15): - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Source Port | Destination Port | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Sequence Number | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Acknowledgment Number | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Data | |U|A|P|R|S|F| | - | Offset| Reserved |R|C|S|S|Y|I| Window | - | | |G|K|H|T|N|N| | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Checksum | Urgent Pointer | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Options | Padding | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | data | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Representation of the TCP Header. + + RFC 793, (p.15): + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Source Port | Destination Port | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Sequence Number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Acknowledgment Number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Data | |U|A|P|R|S|F| | + | Offset| Reserved |R|C|S|S|Y|I| Window | + | | |G|K|H|T|N|N| | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Checksum | Urgent Pointer | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Options | Padding | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | data | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ - struct Header { - TCP::Port source_port; // Source port - TCP::Port destination_port; // Destination port - uint32_t seq_nr; // Sequence number - uint32_t ack_nr; // Acknowledge number - union { - uint16_t whole; // Reference to offset_reserved & flags together. - struct { - uint8_t offset_reserved; // Offset (4 bits) + Reserved (3 bits) + NS (1 bit) - uint8_t flags; // All Flags (Control bits) except NS (9 bits - 1 bit) - }; - } offset_flags; // Data offset + Reserved + Flags (16 bits) - uint16_t window_size; // Window size - uint16_t checksum; // Checksum - uint16_t urgent; // Urgent pointer offset - uint8_t options[0]; // Options - }__attribute__((packed)); // << struct TCP::Header - - - /* - TCP Pseudo header, for checksum calculation - */ - struct Pseudo_header { - IP4::addr saddr; - IP4::addr daddr; - uint8_t zero; - uint8_t proto; - uint16_t tcp_length; - }__attribute__((packed)); + struct Header { + TCP::Port source_port; // Source port + TCP::Port destination_port; // Destination port + uint32_t seq_nr; // Sequence number + uint32_t ack_nr; // Acknowledge number + union { + uint16_t whole; // Reference to offset_reserved & flags together. + struct { + uint8_t offset_reserved; // Offset (4 bits) + Reserved (3 bits) + NS (1 bit) + uint8_t flags; // All Flags (Control bits) except NS (9 bits - 1 bit) + }; + } offset_flags; // Data offset + Reserved + Flags (16 bits) + uint16_t window_size; // Window size + uint16_t checksum; // Checksum + uint16_t urgent; // Urgent pointer offset + uint8_t options[0]; // Options + }__attribute__((packed)); // << struct TCP::Header + + + /* + TCP Pseudo header, for checksum calculation + */ + struct Pseudo_header { + IP4::addr saddr; + IP4::addr daddr; + uint8_t zero; + uint8_t proto; + uint16_t tcp_length; + }__attribute__((packed)); - /* - TCP Checksum-header (TCP-header + pseudo-header) - */ - struct Checksum_header { - TCP::Pseudo_header pseudo; - TCP::Header tcp; - }__attribute__((packed)); + /* + TCP Checksum-header (TCP-header + pseudo-header) + */ + struct Checksum_header { + TCP::Pseudo_header pseudo; + TCP::Header tcp; + }__attribute__((packed)); - /* - To extract the TCP part from a Packet_ptr and calculate size. (?) - */ - struct Full_header { - Ethernet::header ethernet; - IP4::ip_header ip4; - TCP::Header tcp; - }__attribute__((packed)); + /* + To extract the TCP part from a Packet_ptr and calculate size. (?) + */ + struct Full_header { + Ethernet::header ethernet; + IP4::ip_header ip4; + TCP::Header tcp; + }__attribute__((packed)); - /* - TCP Header Option - */ - struct Option { - uint8_t kind; - uint8_t length; - uint8_t data[0]; - - enum Kind { - END = 0x00, // End of option list - NOP = 0x01, // No-Opeartion - MSS = 0x02, // Maximum Segment Size [RFC 793] Rev: [879, 6691] - }; - - static std::string kind_string(Kind kind) { - switch(kind) { - case MSS: - return {"MSS"}; - - default: - return {"Unknown Option"}; - } - } - - struct opt_mss { - uint8_t kind; - uint8_t length; - uint16_t mss; - - opt_mss(uint16_t mss) - : kind(MSS), length(4), mss(htons(mss)) {} - }; - - struct opt_timestamp { - uint8_t kind; - uint8_t length; - uint32_t ts_val; - uint32_t ts_ecr; - }; - }; + /* + TCP Header Option + */ + struct Option { + uint8_t kind; + uint8_t length; + uint8_t data[0]; + + enum Kind { + END = 0x00, // End of option list + NOP = 0x01, // No-Opeartion + MSS = 0x02, // Maximum Segment Size [RFC 793] Rev: [879, 6691] + }; + + static std::string kind_string(Kind kind) { + switch(kind) { + case MSS: + return {"MSS"}; + + default: + return {"Unknown Option"}; + } + } + + struct opt_mss { + uint8_t kind; + uint8_t length; + uint16_t mss; + + opt_mss(uint16_t mss) + : kind(MSS), length(4), mss(htons(mss)) {} + }; + + struct opt_timestamp { + uint8_t kind; + uint8_t length; + uint32_t ts_val; + uint32_t ts_ecr; + }; + }; - /* - A Wrapper for a TCP Packet. Is everything as a IP4 Packet, - in addition to the TCP Header and functions to modify this and the control bits (FLAGS). - */ - class Packet : public PacketIP4 { - public: + /* + A Wrapper for a TCP Packet. Is everything as a IP4 Packet, + in addition to the TCP Header and functions to modify this and the control bits (FLAGS). + */ + class Packet : public PacketIP4 { + public: - inline TCP::Header& header() const - { - return ((TCP::Full_header*) buffer())->tcp; - } + inline TCP::Header& header() const + { + return ((TCP::Full_header*) buffer())->tcp; + } - static const size_t HEADERS_SIZE = sizeof(TCP::Full_header); + static const size_t HEADERS_SIZE = sizeof(TCP::Full_header); - //! initializes to a default, empty TCP packet, given - //! a valid MTU-sized buffer - void init() - { - // Erase all headers (smart? necessary? ...well, convenient) - memset(buffer(), 0, HEADERS_SIZE); - PacketIP4::init(); + //! initializes to a default, empty TCP packet, given + //! a valid MTU-sized buffer + void init() + { + // Erase all headers (smart? necessary? ...well, convenient) + memset(buffer(), 0, HEADERS_SIZE); + PacketIP4::init(); - set_protocol(IP4::IP4_TCP); - set_win_size(TCP::default_window_size); - set_offset(5); + set_protocol(IP4::IP4_TCP); + set_win_size(TCP::default_window_size); + set_offset(5); - // set TCP payload location (!?) - set_payload(buffer() + all_headers_len()); - } + // set TCP payload location (!?) + set_payload(buffer() + all_headers_len()); + } - // GETTERS - inline TCP::Port src_port() const { return ntohs(header().source_port); } + // GETTERS + inline TCP::Port src_port() const { return ntohs(header().source_port); } - inline TCP::Port dst_port() const { return ntohs(header().destination_port); } + inline TCP::Port dst_port() const { return ntohs(header().destination_port); } - inline TCP::Seq seq() const { return ntohl(header().seq_nr); } + inline TCP::Seq seq() const { return ntohl(header().seq_nr); } - inline TCP::Seq ack() const { return ntohl(header().ack_nr); } + inline TCP::Seq ack() const { return ntohl(header().ack_nr); } - inline uint16_t win() const { return ntohs(header().window_size); } + inline uint16_t win() const { return ntohs(header().window_size); } - inline TCP::Socket source() const { return TCP::Socket{src(), src_port()}; } + inline TCP::Socket source() const { return TCP::Socket{src(), src_port()}; } - inline TCP::Socket destination() const { return TCP::Socket{dst(), dst_port()}; } + inline TCP::Socket destination() const { return TCP::Socket{dst(), dst_port()}; } - // SETTERS - inline TCP::Packet& set_src_port(TCP::Port p) { - header().source_port = htons(p); - return *this; - } + // SETTERS + inline TCP::Packet& set_src_port(TCP::Port p) { + header().source_port = htons(p); + return *this; + } - inline TCP::Packet& set_dst_port(TCP::Port p) { - header().destination_port = htons(p); - return *this; - } + inline TCP::Packet& set_dst_port(TCP::Port p) { + header().destination_port = htons(p); + return *this; + } - inline TCP::Packet& set_seq(TCP::Seq n) { - header().seq_nr = htonl(n); - return *this; - } + inline TCP::Packet& set_seq(TCP::Seq n) { + header().seq_nr = htonl(n); + return *this; + } - inline TCP::Packet& set_ack(TCP::Seq n) { - header().ack_nr = htonl(n); - return *this; - } + inline TCP::Packet& set_ack(TCP::Seq n) { + header().ack_nr = htonl(n); + return *this; + } - inline TCP::Packet& set_win_size(uint16_t size) { - header().window_size = htons(size); - return *this; - } + inline TCP::Packet& set_win_size(uint16_t size) { + header().window_size = htons(size); + return *this; + } - inline TCP::Packet& set_checksum(uint16_t checksum) { - header().checksum = checksum; - return *this; - } + inline TCP::Packet& set_checksum(uint16_t checksum) { + header().checksum = checksum; + return *this; + } - inline TCP::Packet& set_source(const TCP::Socket& src) { - set_src(src.address()); // PacketIP4::set_src - set_src_port(src.port()); - return *this; - } + inline TCP::Packet& set_source(const TCP::Socket& src) { + set_src(src.address()); // PacketIP4::set_src + set_src_port(src.port()); + return *this; + } - inline TCP::Packet& set_destination(const TCP::Socket& dest) { - set_dst(dest.address()); // PacketIP4::set_dst - set_dst_port(dest.port()); - return *this; - } + inline TCP::Packet& set_destination(const TCP::Socket& dest) { + set_dst(dest.address()); // PacketIP4::set_dst + set_dst_port(dest.port()); + return *this; + } - /// FLAGS / CONTROL BITS /// + /// FLAGS / CONTROL BITS /// - inline TCP::Packet& set_flag(TCP::Flag f) { - header().offset_flags.whole |= htons(f); - return *this; - } + inline TCP::Packet& set_flag(TCP::Flag f) { + header().offset_flags.whole |= htons(f); + return *this; + } - inline TCP::Packet& set_flags(uint16_t f) { - header().offset_flags.whole |= htons(f); - return *this; - } + inline TCP::Packet& set_flags(uint16_t f) { + header().offset_flags.whole |= htons(f); + return *this; + } - inline TCP::Packet& clear_flag(TCP::Flag f) { - header().offset_flags.whole &= ~ htons(f); - return *this; - } + inline TCP::Packet& clear_flag(TCP::Flag f) { + header().offset_flags.whole &= ~ htons(f); + return *this; + } - inline TCP::Packet& clear_flags() { - header().offset_flags.whole &= 0x00ff; - return *this; - } + inline TCP::Packet& clear_flags() { + header().offset_flags.whole &= 0x00ff; + return *this; + } - inline bool isset(TCP::Flag f) { return ntohs(header().offset_flags.whole) & f; } + inline bool isset(TCP::Flag f) { return ntohs(header().offset_flags.whole) & f; } - /// OFFSET, OPTIONS, DATA /// + /// OFFSET, OPTIONS, DATA /// - // Get the raw tcp offset, in quadruples - inline uint8_t offset() const { return (uint8_t)(header().offset_flags.offset_reserved >> 4); } + // Get the raw tcp offset, in quadruples + inline uint8_t offset() const { return (uint8_t)(header().offset_flags.offset_reserved >> 4); } - // Set raw TCP offset in quadruples - inline void set_offset(uint8_t offset) { header().offset_flags.offset_reserved = (offset << 4); } + // Set raw TCP offset in quadruples + inline void set_offset(uint8_t offset) { header().offset_flags.offset_reserved = (offset << 4); } - // The actaul TCP header size (including options). - inline uint8_t header_size() const { return offset() * 4; } + // The actaul TCP header size (including options). + inline uint8_t header_size() const { return offset() * 4; } - // Calculate the full header length, down to linklayer, in bytes - uint8_t all_headers_len() const { return (HEADERS_SIZE - sizeof(TCP::Header)) + header_size(); } + // Calculate the full header length, down to linklayer, in bytes + uint8_t all_headers_len() const { return (HEADERS_SIZE - sizeof(TCP::Header)) + header_size(); } - // Where data starts - inline char* data() { return (char*) (buffer() + all_headers_len()); } + // Where data starts + inline char* data() { return (char*) (buffer() + all_headers_len()); } - inline uint16_t data_length() const { return size() - all_headers_len(); } - - inline bool has_data() const { return data_length() > 0; } - - inline uint16_t tcp_length() const { return header_size() + data_length(); } - - template - inline void add_option(Args&&... args) { - // to avoid headache, options need to be added BEFORE any data. - assert(!has_data()); - // option address - auto* addr = options()+options_length(); - new (addr) T(args...); - // update offset - set_offset(offset() + round_up( ((T*)addr)->length, 4 )); - set_length(); // update - } - - inline void clear_options() { - // clear existing options - // move data (if any) (??) - set_offset(5); - set_length(); // update - } - - inline uint8_t* options() { return (uint8_t*) header().options; } - - inline uint8_t options_length() const { return header_size() - sizeof(TCP::Header); } - - inline bool has_options() const { return options_length() > 0; } - - // sets the correct length for all the protocols up to IP4 - void set_length(uint16_t newlen = 0) { - // new total packet length - set_size( all_headers_len() + newlen ); - } - - //! assuming the packet has been properly initialized, - //! this will fill bytes from @buffer into this packets buffer, - //! then return the number of bytes written. buffer is unmodified - size_t fill(const char* buffer, size_t length) { - size_t rem = capacity() - all_headers_len(); - size_t total = (length < rem) ? length : rem; - // copy from buffer to packet buffer - memcpy(data() + data_length(), buffer, total); - // set new packet length - set_length(data_length() + total); - return total; - } - - inline std::string to_string() { - std::ostringstream os; - os << "[ S:" << source().to_string() << " D:" << destination().to_string() - << " SEQ:" << seq() << " ACK:" << ack() - << " HEAD-LEN:" << (int)header_size() << " OPT-LEN:" << (int)options_length() << " DATA-LEN:" << data_length() - << " WIN:" << win() << " FLAGS:" << std::bitset<8>{header().offset_flags.flags} << " ]"; - return os.str(); - } - - }; // << class TCP::Packet + inline uint16_t data_length() const { return size() - all_headers_len(); } + + inline bool has_data() const { return data_length() > 0; } + + inline uint16_t tcp_length() const { return header_size() + data_length(); } + + template + inline void add_option(Args&&... args) { + // to avoid headache, options need to be added BEFORE any data. + assert(!has_data()); + // option address + auto* addr = options()+options_length(); + new (addr) T(args...); + // update offset + set_offset(offset() + round_up( ((T*)addr)->length, 4 )); + set_length(); // update + } + + inline void clear_options() { + // clear existing options + // move data (if any) (??) + set_offset(5); + set_length(); // update + } + + inline uint8_t* options() { return (uint8_t*) header().options; } + + inline uint8_t options_length() const { return header_size() - sizeof(TCP::Header); } + + inline bool has_options() const { return options_length() > 0; } + + // sets the correct length for all the protocols up to IP4 + void set_length(uint16_t newlen = 0) { + // new total packet length + set_size( all_headers_len() + newlen ); + } + + //! assuming the packet has been properly initialized, + //! this will fill bytes from @buffer into this packets buffer, + //! then return the number of bytes written. buffer is unmodified + size_t fill(const char* buffer, size_t length) { + size_t rem = capacity() - all_headers_len(); + size_t total = (length < rem) ? length : rem; + // copy from buffer to packet buffer + memcpy(data() + data_length(), buffer, total); + // set new packet length + set_length(data_length() + total); + return total; + } + + inline std::string to_string() { + std::ostringstream os; + os << "[ S:" << source().to_string() << " D:" << destination().to_string() + << " SEQ:" << seq() << " ACK:" << ack() + << " HEAD-LEN:" << (int)header_size() << " OPT-LEN:" << (int)options_length() << " DATA-LEN:" << data_length() + << " WIN:" << win() << " FLAGS:" << std::bitset<8>{header().offset_flags.flags} << " ]"; + return os.str(); + } + + }; // << class TCP::Packet - /* - TODO: Does this need to be better? (faster? stronger?) - */ - class TCPException : public std::runtime_error { - public: - TCPException(const std::string& error) : std::runtime_error(error) {}; - virtual ~TCPException() {}; - }; + /* + TODO: Does this need to be better? (faster? stronger?) + */ + class TCPException : public std::runtime_error { + public: + TCPException(const std::string& error) : std::runtime_error(error) {}; + virtual ~TCPException() {}; + }; - /* - Exception for Bad TCP Header Option (TCP::Option) - */ - class TCPBadOptionException : public TCPException { - public: - TCPBadOptionException(Option::Kind kind, const std::string& error) : - TCPException("Bad Option [" + Option::kind_string(kind) + "]: " + error), - kind_(kind) {}; - - Option::Kind kind(); - private: - Option::Kind kind_; - }; + /* + Exception for Bad TCP Header Option (TCP::Option) + */ + class TCPBadOptionException : public TCPException { + public: + TCPBadOptionException(Option::Kind kind, const std::string& error) : + TCPException("Bad Option [" + Option::kind_string(kind) + "]: " + error), + kind_(kind) {}; + + Option::Kind kind(); + private: + Option::Kind kind_; + }; - /* - Buffer for TCP::Packet_ptr - */ - template> - class PacketBuffer { - public: + /* + Buffer for TCP::Packet_ptr + */ + template> + class PacketBuffer { + public: - PacketBuffer(typename Buffer::size_type limit) : - buffer_(), data_length_(0), - data_offset_(0), limit_(limit) - { - - } - /* Number of packets */ - inline auto size() const { return buffer_.size(); } + PacketBuffer(typename Buffer::size_type limit) : + buffer_(), data_length_(0), + data_offset_(0), limit_(limit) + { + + } + /* Number of packets */ + inline auto size() const { return buffer_.size(); } - /* Amount of data */ - inline size_t data_size() const { return data_length_; } + /* Amount of data */ + inline size_t data_size() const { return data_length_; } - inline void push(const T& packet) { - buffer_.push(packet); - data_length_ += (size_t)packet->data_length(); - } + inline void push(const T& packet) { + buffer_.push(packet); + data_length_ += (size_t)packet->data_length(); + } - inline bool add(T packet) { - if(full()) return false; - push(packet); - return true; - } + inline bool add(T packet) { + if(full()) return false; + push(packet); + return true; + } - inline void pop() { - data_length_ -= (size_t)buffer_.front()->data_length(); - buffer_.pop(); - } + inline void pop() { + data_length_ -= (size_t)buffer_.front()->data_length(); + buffer_.pop(); + } - inline const T& front() const { return buffer_.front(); } + inline const T& front() const { return buffer_.front(); } - inline const T& back() const { return buffer_.back(); } + inline const T& back() const { return buffer_.back(); } - inline bool empty() const { return buffer_.empty(); } + inline bool empty() const { return buffer_.empty(); } - inline auto limit() const { return limit_; } + inline auto limit() const { return limit_; } - inline bool full() const { return size() >= limit(); } + inline bool full() const { return size() >= limit(); } - inline auto data_offset() const { return data_offset_; } + inline auto data_offset() const { return data_offset_; } - inline void set_data_offset(uint32_t offset) { data_offset_ = offset; } + inline void set_data_offset(uint32_t offset) { data_offset_ = offset; } - inline void clear() { - while(!buffer_.empty()) - buffer_.pop(); - data_length_ = {0}; - data_offset_ = {0}; - } + inline void clear() { + while(!buffer_.empty()) + buffer_.pop(); + data_length_ = {0}; + data_offset_ = {0}; + } - private: - Buffer buffer_; - size_t data_length_; - uint32_t data_offset_; - typename Buffer::size_type limit_; + private: + Buffer buffer_; + size_t data_length_; + uint32_t data_offset_; + typename Buffer::size_type limit_; - }; // << TCP::PacketBuffer + }; // << TCP::PacketBuffer - /* - A connection between two Sockets (local and remote). - Receives and handle TCP::Packet. - Transist between many states. - */ - class Connection : public std::enable_shared_from_this { - public: - /* - Connection identifier - */ - using Tuple = std::pair; - - /// CALLBACKS /// - /* - On connection attempt - When a remote sends SYN to connection in LISTENING state. - First thing that will happen. - */ - using AcceptCallback = delegate)>; + /* + A connection between two Sockets (local and remote). + Receives and handle TCP::Packet. + Transist between many states. + */ + class Connection : public std::enable_shared_from_this { + public: + /* + Connection identifier + */ + using Tuple = std::pair; + + /// CALLBACKS /// + /* + On connection attempt - When a remote sends SYN to connection in LISTENING state. + First thing that will happen. + */ + using AcceptCallback = delegate)>; - /* - On connected - When both hosts exchanged sequence numbers (handshake is done). - Now in ESTABLISHED state - it's allowed to write and read to/from the remote. - */ - using ConnectCallback = delegate)>; + /* + On connected - When both hosts exchanged sequence numbers (handshake is done). + Now in ESTABLISHED state - it's allowed to write and read to/from the remote. + */ + using ConnectCallback = delegate)>; - /* - On receiving data - When there is data to read in the receive buffer. - Either when remote PUSH, or buffer is full. - */ - using ReceiveCallback = delegate, bool)>; - - /* - On disconnect - When a remote told it wanna close the connection. - Connection has received a FIN, currently last thing that will happen before a connection is remoed. - */ - struct Disconnect; - - using DisconnectCallback = delegate, Disconnect)>; - - /* - On error - When any of the users request fails. - */ - using ErrorCallback = delegate, TCPException)>; - - /* - When a packet is received - Everytime a connection receives an incoming packet. - Would probably be used for debugging. - (Currently not in use) - */ - using PacketReceivedCallback = delegate, TCP::Packet_ptr)>; - - /* - When a packet is dropped - Everytime an incoming packet is unallowed, it will be dropped. - Can be used for debugging. - */ - using PacketDroppedCallback = delegate; - - /* - Buffer - */ - using Buffer = PacketBuffer<>; - - /* - Reason for disconnect event. - */ - struct Disconnect { - public: - enum Reason { - CLOSING, - REFUSED, - RESET - }; - - Reason reason; - - explicit Disconnect(Reason reason) : reason(reason) {} - - inline operator Reason() const noexcept { return reason; } - - inline operator std::string() const noexcept { return to_string(); } - - inline bool operator ==(const Disconnect& dc) const { return reason == dc.reason; } - - std::string to_string() const { - switch(reason) { - case CLOSING: - return "Connection closing"; - case REFUSED: - return "Conneciton refused"; - case RESET: - return "Connection reset"; - default: - return "Unknown reason"; - } - } - }; // < struct TCP::Connection::Disconnect - - /* - Interface for one of the many states a Connection can have. - */ - class State { - public: - enum Result { - CLOSED = -1, - OK = 0, - CLOSE = 1 - }; - /* - Open a Connection. - OPEN - */ - virtual void open(Connection&, bool active = false); - - /* - Write to a Connection. - SEND - */ - virtual size_t send(Connection&, const char* buffer, size_t n, bool push = false); - - /* - Read from a Connection. - RECEIVE - */ - virtual size_t receive(Connection&, char* buffer, size_t n); + /* + On receiving data - When there is data to read in the receive buffer. + Either when remote PUSH, or buffer is full. + */ + using ReceiveCallback = delegate, bool)>; + + /* + On disconnect - When a remote told it wanna close the connection. + Connection has received a FIN, currently last thing that will happen before a connection is remoed. + */ + struct Disconnect; + + using DisconnectCallback = delegate, Disconnect)>; + + /* + On error - When any of the users request fails. + */ + using ErrorCallback = delegate, TCPException)>; + + /* + When a packet is received - Everytime a connection receives an incoming packet. + Would probably be used for debugging. + (Currently not in use) + */ + using PacketReceivedCallback = delegate, TCP::Packet_ptr)>; + + /* + When a packet is dropped - Everytime an incoming packet is unallowed, it will be dropped. + Can be used for debugging. + */ + using PacketDroppedCallback = delegate; + + /* + Buffer + */ + using Buffer = PacketBuffer<>; + + /* + Reason for disconnect event. + */ + struct Disconnect { + public: + enum Reason { + CLOSING, + REFUSED, + RESET + }; + + Reason reason; + + explicit Disconnect(Reason reason) : reason(reason) {} + + inline operator Reason() const noexcept { return reason; } + + inline operator std::string() const noexcept { return to_string(); } + + inline bool operator ==(const Disconnect& dc) const { return reason == dc.reason; } + + std::string to_string() const { + switch(reason) { + case CLOSING: + return "Connection closing"; + case REFUSED: + return "Conneciton refused"; + case RESET: + return "Connection reset"; + default: + return "Unknown reason"; + } + } + }; // < struct TCP::Connection::Disconnect + + /* + Interface for one of the many states a Connection can have. + */ + class State { + public: + enum Result { + CLOSED = -1, + OK = 0, + CLOSE = 1 + }; + /* + Open a Connection. + OPEN + */ + virtual void open(Connection&, bool active = false); + + /* + Write to a Connection. + SEND + */ + virtual size_t send(Connection&, const char* buffer, size_t n, bool push = false); + + /* + Read from a Connection. + RECEIVE + */ + virtual size_t receive(Connection&, char* buffer, size_t n); - /* - Close a Connection. - CLOSE - */ - virtual void close(Connection&); + /* + Close a Connection. + CLOSE + */ + virtual void close(Connection&); - /* - Terminate a Connection. - ABORT - */ - virtual void abort(Connection&); + /* + Terminate a Connection. + ABORT + */ + virtual void abort(Connection&); - /* - Handle a Packet - SEGMENT ARRIVES - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) = 0; - - /* - The current state represented as a string. - STATUS - */ - virtual std::string to_string() const = 0; - - protected: - /* - Helper functions - TODO: Clean up names. - */ - virtual bool check_seq(Connection&, TCP::Packet_ptr); - - virtual void unallowed_syn_reset_connection(Connection&, TCP::Packet_ptr); - - virtual bool check_ack(Connection&, TCP::Packet_ptr); - - virtual void process_segment(Connection&, TCP::Packet_ptr); - - virtual void process_fin(Connection&, TCP::Packet_ptr); - - virtual void send_reset(Connection&); - - }; // < class TCP::Connection::State - - /* - Forward declaration of concrete states. - Definition in "tcp_connection_states.hpp" - */ - class Closed; - class Listen; - class SynSent; - class SynReceived; - class Established; - class FinWait1; - class FinWait2; - class CloseWait; - class LastAck; - class Closing; - class TimeWait; - - /* - Transmission Control Block. - Keep tracks of all the data for a connection. + /* + Handle a Packet + SEGMENT ARRIVES + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) = 0; + + /* + The current state represented as a string. + STATUS + */ + virtual std::string to_string() const = 0; + + protected: + /* + Helper functions + TODO: Clean up names. + */ + virtual bool check_seq(Connection&, TCP::Packet_ptr); + + virtual void unallowed_syn_reset_connection(Connection&, TCP::Packet_ptr); + + virtual bool check_ack(Connection&, TCP::Packet_ptr); + + virtual void process_segment(Connection&, TCP::Packet_ptr); + + virtual void process_fin(Connection&, TCP::Packet_ptr); + + virtual void send_reset(Connection&); + + }; // < class TCP::Connection::State + + /* + Forward declaration of concrete states. + Definition in "tcp_connection_states.hpp" + */ + class Closed; + class Listen; + class SynSent; + class SynReceived; + class Established; + class FinWait1; + class FinWait2; + class CloseWait; + class LastAck; + class Closing; + class TimeWait; + + /* + Transmission Control Block. + Keep tracks of all the data for a connection. - RFC 793: Page 19 - Among the variables stored in the - TCB are the local and remote socket numbers, the security and - precedence of the connection, pointers to the user's send and receive - buffers, pointers to the retransmit queue and to the current segment. - In addition several variables relating to the send and receive - sequence numbers are stored in the TCB. - */ - struct TCB { - /* Send Sequence Variables */ - struct { - TCP::Seq UNA; // send unacknowledged - TCP::Seq NXT; // send next - uint16_t WND; // send window - uint16_t UP; // send urgent pointer - TCP::Seq WL1; // segment sequence number used for last window update - TCP::Seq WL2; // segment acknowledgment number used for last window update - - uint16_t MSS; // Maximum segment size for outgoing segments. - } SND; // << - TCP::Seq ISS; // initial send sequence number - - /* Receive Sequence Variables */ - struct { - TCP::Seq NXT; // receive next - uint16_t WND; // receive window - uint16_t UP; // receive urgent pointer - } RCV; // << - TCP::Seq IRS; // initial receive sequence number - - TCB() { - SND = { 0, 0, TCP::default_window_size, 0, 0, 0, TCP::default_mss }; - ISS = 0; - RCV = { 0, TCP::default_window_size, 0 }; - IRS = 0; - }; - - std::string to_string() const; - }__attribute__((packed)); // < struct TCP::Connection::TCB - - /* - Creates a connection without a remote. - */ - Connection(TCP& host, Port local_port); - - /* - Creates a connection with a remote. - */ - Connection(TCP& host, Port local_port, Socket remote); - - /* - The hosting TCP instance. - */ - inline const TCP& host() const { return host_; } - - /* - The local Socket bound to this connection. - */ - inline TCP::Socket local() const { return {host_.inet_.ip_addr(), local_port_}; } - - /* - The remote Socket bound to this connection. - */ - inline TCP::Socket remote() const { return remote_; } - - /* - Set remote Socket bound to this connection. - @WARNING: Should this be public? Used by TCP. - */ - inline void set_remote(Socket remote) { remote_ = remote; } - - - /* - Read content from remote. - */ - size_t read(char* buffer, size_t n); - - /* - Read n bytes into a string. - Default 1024 bytes. - */ - std::string read(size_t n = 0); - - /* - Write content to remote. - */ - size_t write(const char* buffer, size_t n, bool PUSH = true); - - /* - Write a string to the remote. - */ - inline void write(const std::string& content) { - write(content.data(), content.size(), true); - } - - /* - Open connection. - */ - void open(bool active = false); - - /* - Close connection. - */ - void close(); - - /* - Abort connection. (Same as Terminate) - */ - inline void abort() { - state_->abort(*this); - signal_close(); - } - - /* - Set callback for ACCEPT event. - */ - inline Connection& onAccept(AcceptCallback callback) { - on_accept_ = callback; - return *this; - } - - /* - Set callback for CONNECT event. - */ - inline Connection& onConnect(ConnectCallback callback) { - on_connect_ = callback; - return *this; - } - - /* - Set callback for ON RECEIVE event. - */ - inline Connection& onReceive(ReceiveCallback callback) { - on_receive_ = callback; - return *this; - } - - /* - Set callback for DISCONNECT event. - */ - inline Connection& onDisconnect(DisconnectCallback callback) { - on_disconnect_ = callback; - return *this; - } - - /* - Set callback for ERROR event. - */ - inline Connection& onError(ErrorCallback callback) { - on_error_ = callback; - return *this; - } - - /* - Set callback for every packet received. - */ - inline Connection& onPacketReceived(PacketReceivedCallback callback) { - on_packet_received_ = callback; - return *this; - } - - /* - Set callback for when a packet is dropped. - */ - inline Connection& onPacketDropped(PacketDroppedCallback callback) { - on_packet_dropped_ = callback; - return *this; - } - - /* - Represent the Connection as a string (STATUS). - */ - std::string to_string() const; - - /* - Returns the current state of the connection. - */ - inline Connection::State& state() const { return *state_; } - - /* - Returns the previous state of the connection. - */ - inline Connection::State& prev_state() const { return *prev_state_; } - - /* - Calculates and return bytes transmitted. - TODO: Not sure if this will suffice. - */ - inline uint32_t bytes_transmitted() const { - return control_block.SND.NXT - control_block.ISS; - } - - /* - Calculates and return bytes received. - TODO: Not sure if this will suffice. - */ - inline uint32_t bytes_received() const { - return control_block.RCV.NXT - control_block.IRS; - } - - /* - Return the id (TUPLE) of the connection. - */ - inline Connection::Tuple tuple() const { - return {local_port_, remote_}; - } - - /* - Receive buffer - */ - inline const Buffer& receive_buffer() { - return receive_buffer_; - } - - /* - Send buffer - */ - inline const Buffer& send_buffer() { - return send_buffer_; - } - - /* - Receive a TCP Packet. - - @WARNING: Public, for use in TCP::bottom (friend it?) - */ - void receive(TCP::Packet_ptr); - - - /* - State checks. - */ - bool is_listening() const; - - bool is_connected() const; - - bool is_closing() const; - - bool is_writable() const; - - /* - Helper function for state checks. - */ - inline bool is_state(const State& state) const { - return state_ == &state; - } - - inline bool is_state(const std::string& state_str) const { - return state_->to_string() == state_str; - } - - /* - Destroy the Connection. - - Clean up. - */ - ~Connection(); - - private: - /* - "Parent" for Connection. - */ - TCP& host_; // 4 B - - /* - End points. - */ - TCP::Port local_port_; // 2 B - TCP::Socket remote_; // 8~ B - - /* - The current state the Connection is in. - Handles most of the logic. - */ - State* state_; // 4 B - // Previous state. Used to keep track of state transitions. - State* prev_state_; // 4 B + RFC 793: Page 19 + Among the variables stored in the + TCB are the local and remote socket numbers, the security and + precedence of the connection, pointers to the user's send and receive + buffers, pointers to the retransmit queue and to the current segment. + In addition several variables relating to the send and receive + sequence numbers are stored in the TCB. + */ + struct TCB { + /* Send Sequence Variables */ + struct { + TCP::Seq UNA; // send unacknowledged + TCP::Seq NXT; // send next + uint16_t WND; // send window + uint16_t UP; // send urgent pointer + TCP::Seq WL1; // segment sequence number used for last window update + TCP::Seq WL2; // segment acknowledgment number used for last window update + + uint16_t MSS; // Maximum segment size for outgoing segments. + } SND; // << + TCP::Seq ISS; // initial send sequence number + + /* Receive Sequence Variables */ + struct { + TCP::Seq NXT; // receive next + uint16_t WND; // receive window + uint16_t UP; // receive urgent pointer + } RCV; // << + TCP::Seq IRS; // initial receive sequence number + + TCB() { + SND = { 0, 0, TCP::default_window_size, 0, 0, 0, TCP::default_mss }; + ISS = 0; + RCV = { 0, TCP::default_window_size, 0 }; + IRS = 0; + }; + + std::string to_string() const; + }__attribute__((packed)); // < struct TCP::Connection::TCB + + /* + Creates a connection without a remote. + */ + Connection(TCP& host, Port local_port); + + /* + Creates a connection with a remote. + */ + Connection(TCP& host, Port local_port, Socket remote); + + /* + The hosting TCP instance. + */ + inline const TCP& host() const { return host_; } + + /* + The local Socket bound to this connection. + */ + inline TCP::Socket local() const { return {host_.inet_.ip_addr(), local_port_}; } + + /* + The remote Socket bound to this connection. + */ + inline TCP::Socket remote() const { return remote_; } + + /* + Set remote Socket bound to this connection. + @WARNING: Should this be public? Used by TCP. + */ + inline void set_remote(Socket remote) { remote_ = remote; } + + + /* + Read content from remote. + */ + size_t read(char* buffer, size_t n); + + /* + Read n bytes into a string. + Default 1024 bytes. + */ + std::string read(size_t n = 0); + + /* + Write content to remote. + */ + size_t write(const char* buffer, size_t n, bool PUSH = true); + + /* + Write a string to the remote. + */ + inline void write(const std::string& content) { + write(content.data(), content.size(), true); + } + + /* + Open connection. + */ + void open(bool active = false); + + /* + Close connection. + */ + void close(); + + /* + Abort connection. (Same as Terminate) + */ + inline void abort() { + state_->abort(*this); + signal_close(); + } + + /* + Set callback for ACCEPT event. + */ + inline Connection& onAccept(AcceptCallback callback) { + on_accept_ = callback; + return *this; + } + + /* + Set callback for CONNECT event. + */ + inline Connection& onConnect(ConnectCallback callback) { + on_connect_ = callback; + return *this; + } + + /* + Set callback for ON RECEIVE event. + */ + inline Connection& onReceive(ReceiveCallback callback) { + on_receive_ = callback; + return *this; + } + + /* + Set callback for DISCONNECT event. + */ + inline Connection& onDisconnect(DisconnectCallback callback) { + on_disconnect_ = callback; + return *this; + } + + /* + Set callback for ERROR event. + */ + inline Connection& onError(ErrorCallback callback) { + on_error_ = callback; + return *this; + } + + /* + Set callback for every packet received. + */ + inline Connection& onPacketReceived(PacketReceivedCallback callback) { + on_packet_received_ = callback; + return *this; + } + + /* + Set callback for when a packet is dropped. + */ + inline Connection& onPacketDropped(PacketDroppedCallback callback) { + on_packet_dropped_ = callback; + return *this; + } + + /* + Represent the Connection as a string (STATUS). + */ + std::string to_string() const; + + /* + Returns the current state of the connection. + */ + inline Connection::State& state() const { return *state_; } + + /* + Returns the previous state of the connection. + */ + inline Connection::State& prev_state() const { return *prev_state_; } + + /* + Calculates and return bytes transmitted. + TODO: Not sure if this will suffice. + */ + inline uint32_t bytes_transmitted() const { + return control_block.SND.NXT - control_block.ISS; + } + + /* + Calculates and return bytes received. + TODO: Not sure if this will suffice. + */ + inline uint32_t bytes_received() const { + return control_block.RCV.NXT - control_block.IRS; + } + + /* + Return the id (TUPLE) of the connection. + */ + inline Connection::Tuple tuple() const { + return {local_port_, remote_}; + } + + /* + Receive buffer + */ + inline const Buffer& receive_buffer() { + return receive_buffer_; + } + + /* + Send buffer + */ + inline const Buffer& send_buffer() { + return send_buffer_; + } + + /* + Receive a TCP Packet. + + @WARNING: Public, for use in TCP::bottom (friend it?) + */ + void receive(TCP::Packet_ptr); + + + /* + State checks. + */ + bool is_listening() const; + + bool is_connected() const; + + bool is_closing() const; + + bool is_writable() const; + + /* + Helper function for state checks. + */ + inline bool is_state(const State& state) const { + return state_ == &state; + } + + inline bool is_state(const std::string& state_str) const { + return state_->to_string() == state_str; + } + + /* + Destroy the Connection. + + Clean up. + */ + ~Connection(); + + private: + /* + "Parent" for Connection. + */ + TCP& host_; // 4 B + + /* + End points. + */ + TCP::Port local_port_; // 2 B + TCP::Socket remote_; // 8~ B + + /* + The current state the Connection is in. + Handles most of the logic. + */ + State* state_; // 4 B + // Previous state. Used to keep track of state transitions. + State* prev_state_; // 4 B - /* - Keep tracks of all sequence variables. - */ - TCB control_block; // 36 B - - /* - Buffers - */ - Buffer receive_buffer_; - Buffer send_buffer_; - - /* - When time-wait timer was started. - */ - uint64_t time_wait_started; + /* + Keep tracks of all sequence variables. + */ + TCB control_block; // 36 B + + /* + Buffers + */ + Buffer receive_buffer_; + Buffer send_buffer_; + + /* + When time-wait timer was started. + */ + uint64_t time_wait_started; - /// CALLBACK HANDLING /// + /// CALLBACK HANDLING /// - /* When a Connection is initiated. */ - AcceptCallback on_accept_ = AcceptCallback::from(this); - inline bool default_on_accept(std::shared_ptr) { - //debug2(" Connection attempt from: %s \n", conn->remote().to_string().c_str()); - return true; // Always accept - } - - /* When Connection is ESTABLISHED. */ - ConnectCallback on_connect_ = [](std::shared_ptr) { - debug2(" Connected.\n"); - }; + /* When a Connection is initiated. */ + AcceptCallback on_accept_ = AcceptCallback::from(this); + inline bool default_on_accept(std::shared_ptr) { + //debug2(" Connection attempt from: %s \n", conn->remote().to_string().c_str()); + return true; // Always accept + } + + /* When Connection is ESTABLISHED. */ + ConnectCallback on_connect_ = [](std::shared_ptr) { + debug2(" Connected.\n"); + }; - /* When data is received */ - ReceiveCallback on_receive_ = [](std::shared_ptr, bool) { - debug2(" Connection received data. \n"); - }; + /* When data is received */ + ReceiveCallback on_receive_ = [](std::shared_ptr, bool) { + debug2(" Connection received data. \n"); + }; - /* When Connection is CLOSING. */ - DisconnectCallback on_disconnect_ = [](std::shared_ptr, Disconnect) { - //debug2(" Connection disconnect. Reason: %s \n", msg.c_str()); - }; + /* When Connection is CLOSING. */ + DisconnectCallback on_disconnect_ = [](std::shared_ptr, Disconnect) { + //debug2(" Connection disconnect. Reason: %s \n", msg.c_str()); + }; - /* When error occcured. */ - ErrorCallback on_error_ = ErrorCallback::from(this); - inline void default_on_error(std::shared_ptr, TCPException) { - //debug2(" TCPException: %s \n", error.what()); - } + /* When error occcured. */ + ErrorCallback on_error_ = ErrorCallback::from(this); + inline void default_on_error(std::shared_ptr, TCPException) { + //debug2(" TCPException: %s \n", error.what()); + } - /* When packet is received */ - PacketReceivedCallback on_packet_received_ = [](std::shared_ptr, TCP::Packet_ptr) { - //debug2(" Packet received: %s \n", packet->to_string().c_str()); - }; + /* When packet is received */ + PacketReceivedCallback on_packet_received_ = [](std::shared_ptr, TCP::Packet_ptr) { + //debug2(" Packet received: %s \n", packet->to_string().c_str()); + }; - /* When a packet is dropped. */ - PacketDroppedCallback on_packet_dropped_ = [](TCP::Packet_ptr, std::string) { - //debug(" Packet dropped. %s | Reason: %s \n", - // packet->to_string().c_str(), reason.c_str()); - }; + /* When a packet is dropped. */ + PacketDroppedCallback on_packet_dropped_ = [](TCP::Packet_ptr, std::string) { + //debug(" Packet dropped. %s | Reason: %s \n", + // packet->to_string().c_str(), reason.c_str()); + }; - /* - Invoke/signal the diffrent TCP events. - */ - inline bool signal_accept() { return on_accept_(shared_from_this()); } + /* + Invoke/signal the diffrent TCP events. + */ + inline bool signal_accept() { return on_accept_(shared_from_this()); } - inline void signal_connect() { on_connect_(shared_from_this()); } + inline void signal_connect() { on_connect_(shared_from_this()); } - inline void signal_receive(bool PUSH) { on_receive_(shared_from_this(), PUSH); } + inline void signal_receive(bool PUSH) { on_receive_(shared_from_this(), PUSH); } - inline void signal_disconnect(Disconnect::Reason&& reason) { on_disconnect_(shared_from_this(), Disconnect{reason}); } + inline void signal_disconnect(Disconnect::Reason&& reason) { on_disconnect_(shared_from_this(), Disconnect{reason}); } - inline void signal_error(TCPException error) { on_error_(shared_from_this(), error); } + inline void signal_error(TCPException error) { on_error_(shared_from_this(), error); } - inline void signal_packet_received(TCP::Packet_ptr packet) { on_packet_received_(shared_from_this(), packet); } + inline void signal_packet_received(TCP::Packet_ptr packet) { on_packet_received_(shared_from_this(), packet); } - inline void signal_packet_dropped(TCP::Packet_ptr packet, std::string reason) { on_packet_dropped_(packet, reason); } + inline void signal_packet_dropped(TCP::Packet_ptr packet, std::string reason) { on_packet_dropped_(packet, reason); } - /* - Drop a packet. Used for debug/callback. - */ - inline void drop(TCP::Packet_ptr packet, std::string reason) { signal_packet_dropped(packet, reason); } - inline void drop(TCP::Packet_ptr packet) { drop(packet, "None given."); } + /* + Drop a packet. Used for debug/callback. + */ + inline void drop(TCP::Packet_ptr packet, std::string reason) { signal_packet_dropped(packet, reason); } + inline void drop(TCP::Packet_ptr packet) { drop(packet, "None given."); } - /// TCB HANDLING /// + /// TCB HANDLING /// - /* - Returns the TCB. - */ - inline Connection::TCB& tcb() { return control_block; } + /* + Returns the TCB. + */ + inline Connection::TCB& tcb() { return control_block; } - /* - Generate a new ISS. - */ - TCP::Seq generate_iss(); + /* + Generate a new ISS. + */ + TCP::Seq generate_iss(); - /// STATE HANDLING /// - /* - Set state. (used by substates) - */ - void set_state(State& state); + /// STATE HANDLING /// + /* + Set state. (used by substates) + */ + void set_state(State& state); - /// BUFFER HANDLING /// + /// BUFFER HANDLING /// - /* - Read from receive buffer. - */ - size_t read_from_receive_buffer(char* buffer, size_t n); + /* + Read from receive buffer. + */ + size_t read_from_receive_buffer(char* buffer, size_t n); - /* - Add(queue) a packet to the receive buffer. - */ - bool add_to_receive_buffer(TCP::Packet_ptr packet); + /* + Add(queue) a packet to the receive buffer. + */ + bool add_to_receive_buffer(TCP::Packet_ptr packet); - /* - Write to the send buffer. Segmentize into packets. - */ - size_t write_to_send_buffer(const char* buffer, size_t n, bool PUSH = true); - - /* - Transmit the send buffer. - */ - void transmit(); - - /* - Transmit the packet. - */ - void transmit(TCP::Packet_ptr); - - /* - Creates a new outgoing packet and put it in the back of the send buffer. - */ - TCP::Packet_ptr create_outgoing_packet(); - - /* - Returns the packet in the back of the send buffer. - If the send buffer is empty, it creates a new packet and adds it. - */ - TCP::Packet_ptr outgoing_packet(); + /* + Write to the send buffer. Segmentize into packets. + */ + size_t write_to_send_buffer(const char* buffer, size_t n, bool PUSH = true); + + /* + Transmit the send buffer. + */ + void transmit(); + + /* + Transmit the packet. + */ + void transmit(TCP::Packet_ptr); + + /* + Creates a new outgoing packet and put it in the back of the send buffer. + */ + TCP::Packet_ptr create_outgoing_packet(); + + /* + Returns the packet in the back of the send buffer. + If the send buffer is empty, it creates a new packet and adds it. + */ + TCP::Packet_ptr outgoing_packet(); - /// RETRANSMISSION /// + /// RETRANSMISSION /// - /* - Starts a retransmission timer that retransmits the packet when RTO has passed. + /* + Starts a retransmission timer that retransmits the packet when RTO has passed. - // TODO: Calculate RTO, currently hardcoded to 1 second (1000ms). - */ - void add_retransmission(TCP::Packet_ptr); - - /* - Measure the elapsed time between sending a data octet with a - particular sequence number and receiving an acknowledgment that - covers that sequence number (segments sent do not have to match - segments received). This measured elapsed time is the Round Trip - Time (RTT). - */ - //std::chrono::milliseconds RTT() const; - std::chrono::milliseconds RTO() const; + // TODO: Calculate RTO, currently hardcoded to 1 second (1000ms). + */ + void add_retransmission(TCP::Packet_ptr); + + /* + Measure the elapsed time between sending a data octet with a + particular sequence number and receiving an acknowledgment that + covers that sequence number (segments sent do not have to match + segments received). This measured elapsed time is the Round Trip + Time (RTT). + */ + //std::chrono::milliseconds RTT() const; + std::chrono::milliseconds RTO() const; - /* - Start the time wait timeout for 2*MSL - */ - void start_time_wait_timeout(); + /* + Start the time wait timeout for 2*MSL + */ + void start_time_wait_timeout(); - /* - Tell the host (TCP) to delete this connection. - */ - void signal_close(); + /* + Tell the host (TCP) to delete this connection. + */ + void signal_close(); - /// OPTIONS /// - /* - Maximum Segment Data Size - (Limit the size for outgoing packets) - */ - inline uint16_t MSDS() const { - return std::min(host_.MSS(), control_block.SND.MSS); - } + /// OPTIONS /// + /* + Maximum Segment Data Size + (Limit the size for outgoing packets) + */ + inline uint16_t MSDS() const { + return std::min(host_.MSS(), control_block.SND.MSS); + } - /* - Parse and apply options. - */ - void parse_options(TCP::Packet_ptr); + /* + Parse and apply options. + */ + void parse_options(TCP::Packet_ptr); - /* - Add an option. - */ - void add_option(TCP::Option::Kind, TCP::Packet_ptr); + /* + Add an option. + */ + void add_option(TCP::Option::Kind, TCP::Packet_ptr); - }; // < class TCP::Connection + }; // < class TCP::Connection - /// USER INTERFACE - TCP /// + /// USER INTERFACE - TCP /// - /* - Constructor - */ - TCP(IPStack&); + /* + Constructor + */ + TCP(IPStack&); - /* - Bind a new listener to a given Port. - */ - TCP::Connection& bind(Port port); + /* + Bind a new listener to a given Port. + */ + TCP::Connection& bind(Port port); - /* - Active open a new connection to the given remote. - */ - Connection_ptr connect(Socket remote); + /* + Active open a new connection to the given remote. + */ + Connection_ptr connect(Socket remote); - /* - Active open a new connection to the given remote. - */ - inline auto connect(TCP::Address address, Port port = 80) { - return connect({address, port}); - } + /* + Active open a new connection to the given remote. + */ + inline auto connect(TCP::Address address, Port port = 80) { + return connect({address, port}); + } - /* - Active open a new connection to the given remote. - */ - void connect(Socket remote, Connection::ConnectCallback); + /* + Active open a new connection to the given remote. + */ + void connect(Socket remote, Connection::ConnectCallback); - /* - Receive packet from network layer (IP). - */ - void bottom(net::Packet_ptr); + /* + Receive packet from network layer (IP). + */ + void bottom(net::Packet_ptr); - /* - Delegate output to network layer - */ - inline void set_network_out(downstream del) { _network_layer_out = del; } + /* + Delegate output to network layer + */ + inline void set_network_out(downstream del) { _network_layer_out = del; } - /* - Compute the TCP checksum - */ + /* + Compute the TCP checksum + */ static uint16_t checksum(const TCP::Packet_ptr); inline const auto& listeners() { return listeners_; } @@ -1236,113 +1236,113 @@ class TCP { inline const auto& connections() { return connections_; } /* - Number of open ports. + Number of open ports. */ - inline size_t openPorts() { return listeners_.size(); } + inline size_t openPorts() { return listeners_.size(); } - /* - Number of active connections. - */ - inline size_t activeConnections() { return connections_.size(); } + /* + Number of active connections. + */ + inline size_t activeConnections() { return connections_.size(); } - /* - Maximum Segment Lifetime - */ - inline auto MSL() const { return MAX_SEG_LIFETIME; } + /* + Maximum Segment Lifetime + */ + inline auto MSL() const { return MAX_SEG_LIFETIME; } - /* - Set Maximum Segment Lifetime - */ - inline void set_MSL(const std::chrono::milliseconds msl) { - MAX_SEG_LIFETIME = msl; - } + /* + Set Maximum Segment Lifetime + */ + inline void set_MSL(const std::chrono::milliseconds msl) { + MAX_SEG_LIFETIME = msl; + } - /* - Maximum Buffer Size - */ - inline auto buffer_limit() const { return MAX_BUFFER_SIZE; } + /* + Maximum Buffer Size + */ + inline auto buffer_limit() const { return MAX_BUFFER_SIZE; } - /* - Set Buffer limit - */ - inline void set_buffer_limit(size_t buffer_limit) { - MAX_BUFFER_SIZE = buffer_limit; - } + /* + Set Buffer limit + */ + inline void set_buffer_limit(size_t buffer_limit) { + MAX_BUFFER_SIZE = buffer_limit; + } - /* - Maximum Segment Size - [RFC 793] [RFC 879] [RFC 6691] + /* + Maximum Segment Size + [RFC 793] [RFC 879] [RFC 6691] - @NOTE: Currently not supporting MTU bigger than 1482 bytes. - */ - inline uint16_t MSS() const { - /* - VirtulaBox "issue": - MTU > 1498 will break TCP. - MTU > 1482 seems to cause fragmentation: https://www.virtualbox.org/ticket/13967 - */ - const uint16_t VBOX_LIMIT = 1482; - return std::min(inet_.MTU(), VBOX_LIMIT) - sizeof(Full_header::ip4) - sizeof(TCP::Header); - } + @NOTE: Currently not supporting MTU bigger than 1482 bytes. + */ + inline uint16_t MSS() const { + /* + VirtulaBox "issue": + MTU > 1498 will break TCP. + MTU > 1482 seems to cause fragmentation: https://www.virtualbox.org/ticket/13967 + */ + const uint16_t VBOX_LIMIT = 1482; + return std::min(inet_.MTU(), VBOX_LIMIT) - sizeof(Full_header::ip4) - sizeof(TCP::Header); + } - /* - Show all connections for TCP as a string. - */ - std::string status() const; + /* + Show all connections for TCP as a string. + */ + std::string status() const; -private: - IPStack& inet_; - std::map listeners_; - std::map connections_; + private: + IPStack& inet_; + std::map listeners_; + std::map connections_; - downstream _network_layer_out; + downstream _network_layer_out; - /* - Settings - */ - TCP::Port current_ephemeral_ = 1024; + /* + Settings + */ + TCP::Port current_ephemeral_ = 1024; - std::chrono::milliseconds MAX_SEG_LIFETIME; + std::chrono::milliseconds MAX_SEG_LIFETIME; - /* - Current: limit by packet COUNT. - Connection buffer size in bytes = buffers * BUFFER_LIMIT * MTU. - */ - size_t MAX_BUFFER_SIZE = 10; + /* + Current: limit by packet COUNT. + Connection buffer size in bytes = buffers * BUFFER_LIMIT * MTU. + */ + size_t MAX_BUFFER_SIZE = 10; - /* - Transmit packet to network layer (IP). - */ - void transmit(TCP::Packet_ptr); + /* + Transmit packet to network layer (IP). + */ + void transmit(TCP::Packet_ptr); - /* - Generate a unique initial sequence number (ISS). - */ - TCP::Seq generate_iss(); + /* + Generate a unique initial sequence number (ISS). + */ + TCP::Seq generate_iss(); - /* - Returns a free port for outgoing connections. - */ - TCP::Port free_port(); + /* + Returns a free port for outgoing connections. + */ + TCP::Port free_port(); - /* - Packet is dropped. - */ - void drop(TCP::Packet_ptr); + /* + Packet is dropped. + */ + void drop(TCP::Packet_ptr); - /* - Add a Connection. - */ - Connection_ptr add_connection(TCP::Port local_port, TCP::Socket remote); + /* + Add a Connection. + */ + Connection_ptr add_connection(TCP::Port local_port, TCP::Socket remote); - /* - Close and delete the connection. - */ - void close_connection(TCP::Connection&); + /* + Close and delete the connection. + */ + void close_connection(TCP::Connection&); -}; // < class TCP + }; // < class TCP }; // < namespace net diff --git a/api/net/tcp_connection_states.hpp b/api/net/tcp_connection_states.hpp index 67e314d43d..118193835a 100644 --- a/api/net/tcp_connection_states.hpp +++ b/api/net/tcp_connection_states.hpp @@ -25,320 +25,320 @@ using Connection = TCP::Connection; using State = TCP::Connection::State; /* - CLOSED + CLOSED */ class Connection::Closed : public State { public: - inline static State& instance() { - static Closed instance; - return instance; - } + inline static State& instance() { + static Closed instance; + return instance; + } - virtual void open(Connection&, bool active = false) override; + virtual void open(Connection&, bool active = false) override; - virtual size_t send(Connection&, const char* buffer, size_t n, bool push) override; + virtual size_t send(Connection&, const char* buffer, size_t n, bool push) override; - /* - PASSIVE: - <- Do nothing (Start listening). + /* + PASSIVE: + <- Do nothing (Start listening). - => Listen. + => Listen. - ACTIVE: - <- Send SYN. + ACTIVE: + <- Send SYN. - => SynSent - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + => SynSent + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "CLOSED"; - }; + inline virtual std::string to_string() const override { + return "CLOSED"; + }; private: - inline Closed() {}; + inline Closed() {}; }; /* - LISTEN + LISTEN */ class Connection::Listen : public State { public: - inline static State& instance() { - static Listen instance; - return instance; - } - virtual void open(Connection&, bool active = false) override; + inline static State& instance() { + static Listen instance; + return instance; + } + virtual void open(Connection&, bool active = false) override; - virtual size_t send(Connection&, const char* buffer, size_t n, bool push) override; + virtual size_t send(Connection&, const char* buffer, size_t n, bool push) override; - virtual void close(Connection&) override; - /* - -> Receive SYN. + virtual void close(Connection&) override; + /* + -> Receive SYN. - <- Send SYN+ACK. + <- Send SYN+ACK. - => SynReceived. - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + => SynReceived. + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "LISTENING"; - }; + inline virtual std::string to_string() const override { + return "LISTENING"; + }; private: - inline Listen() {}; + inline Listen() {}; }; /* - SYN-SENT + SYN-SENT */ class Connection::SynSent : public State { public: - inline static State& instance() { - static SynSent instance; - return instance; - } + inline static State& instance() { + static SynSent instance; + return instance; + } - virtual size_t send(Connection&, const char* buffer, size_t n, bool push) override; + virtual size_t send(Connection&, const char* buffer, size_t n, bool push) override; - virtual void close(Connection&) override; - /* - -> Receive SYN+ACK + virtual void close(Connection&) override; + /* + -> Receive SYN+ACK - <- Send ACK. + <- Send ACK. - => Established. - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + => Established. + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "SYN-SENT"; - }; + inline virtual std::string to_string() const override { + return "SYN-SENT"; + }; private: - inline SynSent() {}; + inline SynSent() {}; }; /* - SYN-RCV + SYN-RCV */ class Connection::SynReceived : public State { public: - inline static State& instance() { - static SynReceived instance; - return instance; - } + inline static State& instance() { + static SynReceived instance; + return instance; + } - virtual size_t send(Connection&, const char* buffer, size_t n, bool push) override; + virtual size_t send(Connection&, const char* buffer, size_t n, bool push) override; - virtual void close(Connection&) override; + virtual void close(Connection&) override; - virtual void abort(Connection&) override; - /* - -> Receive ACK. + virtual void abort(Connection&) override; + /* + -> Receive ACK. - <- Do nothing (Connection is Established) + <- Do nothing (Connection is Established) - => Established. - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + => Established. + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "SYN-RCV"; - }; + inline virtual std::string to_string() const override { + return "SYN-RCV"; + }; private: - inline SynReceived() {}; + inline SynReceived() {}; }; /* - ESTABLISHED + ESTABLISHED */ class Connection::Established : public State { public: - inline static State& instance() { - static Established instance; - return instance; - } + inline static State& instance() { + static Established instance; + return instance; + } - virtual size_t send(Connection&, const char* buffer, size_t n, bool push) override; + virtual size_t send(Connection&, const char* buffer, size_t n, bool push) override; - virtual size_t receive(Connection&, char* buffer, size_t n) override; + virtual size_t receive(Connection&, char* buffer, size_t n) override; - virtual void close(Connection&) override; + virtual void close(Connection&) override; - virtual void abort(Connection&) override; + virtual void abort(Connection&) override; - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "ESTABLISHED"; - }; + inline virtual std::string to_string() const override { + return "ESTABLISHED"; + }; private: - inline Established() {}; + inline Established() {}; }; /* - FIN-WAIT-1 + FIN-WAIT-1 */ class Connection::FinWait1 : public State { public: - inline static State& instance() { - static FinWait1 instance; - return instance; - } + inline static State& instance() { + static FinWait1 instance; + return instance; + } - virtual size_t receive(Connection&, char* buffer, size_t n) override; + virtual size_t receive(Connection&, char* buffer, size_t n) override; - virtual void close(Connection&) override; + virtual void close(Connection&) override; - virtual void abort(Connection&) override; + virtual void abort(Connection&) override; - /* - -> Receive ACK. + /* + -> Receive ACK. - => FinWait2. - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + => FinWait2. + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "FIN-WAIT-1"; - }; + inline virtual std::string to_string() const override { + return "FIN-WAIT-1"; + }; private: - inline FinWait1() {}; + inline FinWait1() {}; }; /* - FIN-WAIT-2 + FIN-WAIT-2 */ class Connection::FinWait2 : public State { public: - inline static State& instance() { - static FinWait2 instance; - return instance; - } + inline static State& instance() { + static FinWait2 instance; + return instance; + } - virtual size_t receive(Connection&, char* buffer, size_t n) override; + virtual size_t receive(Connection&, char* buffer, size_t n) override; - virtual void close(Connection&) override; + virtual void close(Connection&) override; - virtual void abort(Connection&) override; - /* + virtual void abort(Connection&) override; + /* - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "FIN-WAIT-2"; - }; + inline virtual std::string to_string() const override { + return "FIN-WAIT-2"; + }; private: - inline FinWait2() {}; + inline FinWait2() {}; }; /* - CLOSE-WAIT + CLOSE-WAIT */ class Connection::CloseWait : public State { public: - inline static State& instance() { - static CloseWait instance; - return instance; - } + inline static State& instance() { + static CloseWait instance; + return instance; + } - virtual size_t send(Connection&, const char* buffer, size_t n, bool push) override; + virtual size_t send(Connection&, const char* buffer, size_t n, bool push) override; - virtual size_t receive(Connection&, char* buffer, size_t n) override; + virtual size_t receive(Connection&, char* buffer, size_t n) override; - virtual void close(Connection&) override; + virtual void close(Connection&) override; - virtual void abort(Connection&) override; - /* - -> Nothing I think... + virtual void abort(Connection&) override; + /* + -> Nothing I think... - <- Send FIN. + <- Send FIN. - => LastAck - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + => LastAck + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "CLOSE-WAIT"; - }; + inline virtual std::string to_string() const override { + return "CLOSE-WAIT"; + }; private: - inline CloseWait() {}; + inline CloseWait() {}; }; /* - LAST-ACK + LAST-ACK */ class Connection::LastAck : public State { public: - inline static State& instance() { - static LastAck instance; - return instance; - } - /* - -> Receive ACK. + inline static State& instance() { + static LastAck instance; + return instance; + } + /* + -> Receive ACK. - <- conn.onClose(); + <- conn.onClose(); - => Closed (Tell TCP to remove this connection) - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + => Closed (Tell TCP to remove this connection) + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "LAST-ACK"; - }; + inline virtual std::string to_string() const override { + return "LAST-ACK"; + }; private: - inline LastAck() {}; + inline LastAck() {}; }; /* - CLOSING + CLOSING */ class Connection::Closing : public State { public: - inline static State& instance() { - static Closing instance; - return instance; - } - /* - -> Receive ACK. + inline static State& instance() { + static Closing instance; + return instance; + } + /* + -> Receive ACK. - => TimeWait (Guess this isnt needed, just start a Close-timer) - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + => TimeWait (Guess this isnt needed, just start a Close-timer) + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "CLOSING"; - }; + inline virtual std::string to_string() const override { + return "CLOSING"; + }; private: - inline Closing() {}; + inline Closing() {}; }; /* - TIME-WAIT + TIME-WAIT */ class Connection::TimeWait : public State { public: - inline static State& instance() { - static TimeWait instance; - return instance; - } - /* + inline static State& instance() { + static TimeWait instance; + return instance; + } + /* - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "TIME-WAIT"; - }; + inline virtual std::string to_string() const override { + return "TIME-WAIT"; + }; private: - inline TimeWait() {}; + inline TimeWait() {}; }; -#endif \ No newline at end of file +#endif diff --git a/api/net/util.hpp b/api/net/util.hpp index f5d3f7161a..621273bf2f 100644 --- a/api/net/util.hpp +++ b/api/net/util.hpp @@ -22,37 +22,37 @@ namespace net { -/* - * See P.49 of C programming - * Get "n" bits from integer "x", starting from position "p" - * e.g., getbits(x, 31, 8) -- highest byte - * getbits(x, 7, 8) -- lowest byte - */ + /* + * See P.49 of C programming + * Get "n" bits from integer "x", starting from position "p" + * e.g., getbits(x, 31, 8) -- highest byte + * getbits(x, 7, 8) -- lowest byte + */ #define getbits(x, p, n) (((x) >> ((p) + 1 - (n))) & ~(~0 << (n))) -inline uint16_t ntohs(uint16_t n) noexcept { - return __builtin_bswap16(n); -} + inline uint16_t ntohs(uint16_t n) noexcept { + return __builtin_bswap16(n); + } -inline uint16_t htons(uint16_t n) noexcept { - return __builtin_bswap16(n); -} + inline uint16_t htons(uint16_t n) noexcept { + return __builtin_bswap16(n); + } -inline uint32_t ntohl(uint32_t n) noexcept { - return __builtin_bswap32(n); -} + inline uint32_t ntohl(uint32_t n) noexcept { + return __builtin_bswap32(n); + } -inline uint32_t htonl(uint32_t n) noexcept { - return __builtin_bswap32(n); -} + inline uint32_t htonl(uint32_t n) noexcept { + return __builtin_bswap32(n); + } -inline uint64_t ntohll(uint64_t n) noexcept { - return __builtin_bswap64(n); -} + inline uint64_t ntohll(uint64_t n) noexcept { + return __builtin_bswap64(n); + } -inline uint64_t htonll(uint64_t n) noexcept { - return __builtin_bswap64(n); -} + inline uint64_t htonll(uint64_t n) noexcept { + return __builtin_bswap64(n); + } } //< namespace net diff --git a/api/utility/async_loop.hpp b/api/utility/async_loop.hpp index c4c456a360..d30230784e 100644 --- a/api/utility/async_loop.hpp +++ b/api/utility/async_loop.hpp @@ -6,27 +6,27 @@ typedef std::shared_ptr next_ptr_t; inline void async_loop( - std::function func, - std::function on_done) + std::function func, + std::function on_done) { // store next function on heap auto next = std::make_shared (); // loop: *next = - [next] (bool done) - { - // check we are done, and if so, - // execute the callback function and return - if (done) + [next] (bool done) { - on_done(); - return; + // check we are done, and if so, + // execute the callback function and return + if (done) + { + on_done(); + return; + } + // otherwise, + // execute one iteration of the loop + func(next); } - // otherwise, - // execute one iteration of the loop - func(next); - } // start the process next(false); } diff --git a/api/utility/delegate.hpp b/api/utility/delegate.hpp index 27c04c64cd..a942bf7da5 100644 --- a/api/utility/delegate.hpp +++ b/api/utility/delegate.hpp @@ -7,7 +7,7 @@ Licence: Assumed to be public domain. ...It's just awesome how people make great stuff and just post it - */ +*/ #ifndef OSABI_DELEGATE_HPP #define OSABI_DELEGATE_HPP @@ -25,7 +25,7 @@ class delegate using stub_ptr_type = R (*)(void*, A&&...); delegate(void* const o, stub_ptr_type const m) noexcept : - object_ptr_(o), + object_ptr_(o), stub_ptr_(m) { } @@ -42,16 +42,16 @@ class delegate delegate(::std::nullptr_t const) noexcept : delegate() { } template {}>::type> - explicit delegate(C const* const o) noexcept : - object_ptr_(const_cast(o)) + typename ::std::enable_if< ::std::is_class{}>::type> + explicit delegate(C const* const o) noexcept : + object_ptr_(const_cast(o)) { } template {}>::type> - explicit delegate(C const& o) noexcept : - object_ptr_(const_cast(&o)) + typename ::std::enable_if< ::std::is_class{}>::type> + explicit delegate(C const& o) noexcept : + object_ptr_(const_cast(&o)) { } @@ -84,11 +84,11 @@ class delegate typename = typename ::std::enable_if< !::std::is_same::type>{} >::type - > - delegate(T&& f) : + > + delegate(T&& f) : store_(operator new(sizeof(typename ::std::decay::type)), - functor_deleter::type>), - store_size_(sizeof(typename ::std::decay::type)) + functor_deleter::type>), + store_size_(sizeof(typename ::std::decay::type)) { using functor_type = typename ::std::decay::type; @@ -122,22 +122,22 @@ class delegate typename = typename ::std::enable_if< !::std::is_same::type>{} >::type - > - delegate& operator=(T&& f) + > + delegate& operator=(T&& f) { using functor_type = typename ::std::decay::type; if ((sizeof(functor_type) > store_size_) || !store_.unique()) - { - store_.reset(operator new(sizeof(functor_type)), - functor_deleter); + { + store_.reset(operator new(sizeof(functor_type)), + functor_deleter); - store_size_ = sizeof(functor_type); - } + store_size_ = sizeof(functor_type); + } else - { - deleter_(store_.get()); - } + { + deleter_(store_.get()); + } new (store_.get()) functor_type(::std::forward(f)); @@ -201,14 +201,14 @@ class delegate template static delegate from(C* const object_ptr, - R (C::* const method_ptr)(A...)) + R (C::* const method_ptr)(A...)) { return member_pair(object_ptr, method_ptr); } template static delegate from(C const* const object_ptr, - R (C::* const method_ptr)(A...) const) + R (C::* const method_ptr)(A...) const) { return const_member_pair(object_ptr, method_ptr); } @@ -221,7 +221,7 @@ class delegate template static delegate from(C const& object, - R (C::* const method_ptr)(A...) const) + R (C::* const method_ptr)(A...) const) { return const_member_pair(&object, method_ptr); } @@ -262,7 +262,7 @@ class delegate R operator()(A... args) const { -// assert(stub_ptr); + // assert(stub_ptr); return stub_ptr_(object_ptr_, ::std::forward(args)...); } @@ -303,14 +303,14 @@ class delegate static R method_stub(void* const object_ptr, A&&... args) { return (static_cast(object_ptr)->*method_ptr)( - ::std::forward(args)...); + ::std::forward(args)...); } template static R const_method_stub(void* const object_ptr, A&&... args) { return (static_cast(object_ptr)->*method_ptr)( - ::std::forward(args)...); + ::std::forward(args)...); } template @@ -318,7 +318,7 @@ class delegate template struct is_member_pair< ::std::pair > : std::true_type + R (C::* const)(A...)> > : std::true_type { }; @@ -327,16 +327,16 @@ class delegate template struct is_const_member_pair< ::std::pair > : std::true_type + R (C::* const)(A...) const> > : std::true_type { }; template static typename ::std::enable_if< !(is_member_pair{} || - is_const_member_pair{}), + is_const_member_pair{}), R - >::type + >::type functor_stub(void* const object_ptr, A&&... args) { return (*static_cast(object_ptr))(::std::forward(args)...); @@ -345,13 +345,13 @@ class delegate template static typename ::std::enable_if< is_member_pair{} || - is_const_member_pair{}, + is_const_member_pair{}, R - >::type - functor_stub(void* const object_ptr, A&&... args) + >::type + functor_stub(void* const object_ptr, A&&... args) { return (static_cast(object_ptr)->first->* - static_cast(object_ptr)->second)(::std::forward(args)...); + static_cast(object_ptr)->second)(::std::forward(args)...); } }; @@ -365,7 +365,7 @@ namespace std auto const seed(hash()(d.object_ptr_)); return hash::stub_ptr_type>()( - d.stub_ptr_) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + d.stub_ptr_) + 0x9e3779b9 + (seed << 6) + (seed >> 2); } }; } diff --git a/api/utility/membitmap.hpp b/api/utility/membitmap.hpp index bf8606ced3..fe22eb1e67 100644 --- a/api/utility/membitmap.hpp +++ b/api/utility/membitmap.hpp @@ -23,7 +23,7 @@ * In-memory bitmap implementation * * -**/ + **/ namespace fs { @@ -56,15 +56,15 @@ namespace fs { // each word for (index_t i = 0; i < _size; i++) - if (_data[i] != WORD_MAX) - { - // each bit - for (index_t b = 0; b < CHUNK_SIZE; b++) - if (!(_data[i] & (1 << b))) - { - return i * CHUNK_SIZE + b; - } - } // chunk + if (_data[i] != WORD_MAX) + { + // each bit + for (index_t b = 0; b < CHUNK_SIZE; b++) + if (!(_data[i] & (1 << b))) + { + return i * CHUNK_SIZE + b; + } + } // chunk return -1; } // first_free() diff --git a/api/utility/ringbuffer.hpp b/api/utility/ringbuffer.hpp index 88bd7f9f38..1999811a90 100644 --- a/api/utility/ringbuffer.hpp +++ b/api/utility/ringbuffer.hpp @@ -24,110 +24,110 @@ namespace includeOS { - class RingBuffer - { - enum error_t - { - E_OK = 0, - E_NO_SPACE = -1; - E_WRITE_FAILED = -2; - }; + class RingBuffer + { + enum error_t + { + E_OK = 0, + E_NO_SPACE = -1; + E_WRITE_FAILED = -2; + }; - RingBuffer(int size) - { - this->size = size + 1; - this->start = 0; - this->end = 0; - this->buffer = new char[this->size]; - } - ~RingBuffer() - { - if (this->buffer) - delete[] this->buffer; - } + RingBuffer(int size) + { + this->size = size + 1; + this->start = 0; + this->end = 0; + this->buffer = new char[this->size]; + } + ~RingBuffer() + { + if (this->buffer) + delete[] this->buffer; + } - int write(char* data, int length) - { - if (available_data() == 0) - { - this->start = this->end = 0; - } + int write(char* data, int length) + { + if (available_data() == 0) + { + this->start = this->end = 0; + } - if (length > available_space()) - { - return E_NO_SPACE; - } + if (length > available_space()) + { + return E_NO_SPACE; + } - void* result = memcpy(ends_at(), data, length); - if (result == nullptr) - { - return E_WRITE_FAILED; - } + void* result = memcpy(ends_at(), data, length); + if (result == nullptr) + { + return E_WRITE_FAILED; + } - // commit write - this->end = (this->end + length) % this->size; - // return length written - return length; - } + // commit write + this->end = (this->end + length) % this->size; + // return length written + return length; + } - int read(char* dest, int length) - { - check_debug(amount <= RingBuffer_available_data(buffer), - "Not enough in the buffer: has %d, needs %d", - RingBuffer_available_data(buffer), amount); + int read(char* dest, int length) + { + check_debug(amount <= RingBuffer_available_data(buffer), + "Not enough in the buffer: has %d, needs %d", + RingBuffer_available_data(buffer), amount); - void *result = memcpy(target, RingBuffer_starts_at(buffer), amount); - check(result != NULL, "Failed to write buffer into data."); + void *result = memcpy(target, RingBuffer_starts_at(buffer), amount); + check(result != NULL, "Failed to write buffer into data."); - // commit read - this->start = (this->start + length) % this->size; + // commit read + this->start = (this->start + length) % this->size; - if (this->end == this->start) - { - this->start = this->end = 0; - } + if (this->end == this->start) + { + this->start = this->end = 0; + } - return length; - } + return length; + } - #define RingBuffer_available_data(B) (((B)->end + 1) % (B)->length - (B)->start - 1) - #define RingBuffer_available_space(B) ((B)->length - (B)->end - 1) +#define RingBuffer_available_data(B) (((B)->end + 1) % (B)->length - (B)->start - 1) +#define RingBuffer_available_space(B) ((B)->length - (B)->end - 1) - int available_data() const - { - return (this->end + 1) % this->size - this->start - 1; - } - int available_space() const - { - return this-> - } + int available_data() const + { + return (this->end + 1) % this->size - this->start - 1; + } + int available_space() const + { + return this-> + } - const char* starts_at() const - { - return this->buffer + this->end; - } - const char* ends_at() const - { - return this->buffer + this->end; - } + const char* starts_at() const + { + return this->buffer + this->end; + } + const char* ends_at() const + { + return this->buffer + this->end; + } - bool full() const - { - return available_data() - this->size == 0; - } - bool empty() const - { - return available_data() == 0; - } + bool full() const + { + return available_data() - this->size == 0; + } + bool empty() const + { + return available_data() == 0; + } - private: - int size; - int start; - int end; - char* buffer; - }; + private: + int size; + int start; + int end; + char* buffer; + }; } #endif diff --git a/api/utility/signal.hpp b/api/utility/signal.hpp index c15d4cc269..35c672f8f0 100644 --- a/api/utility/signal.hpp +++ b/api/utility/signal.hpp @@ -24,42 +24,42 @@ template class signal { public: - //! \brief Callable type of the signal handlers - using handler = std::function; + //! \brief Callable type of the signal handlers + using handler = std::function; - //! \brief Default constructor - explicit signal() = default; + //! \brief Default constructor + explicit signal() = default; - //! \brief Default destructor - ~signal() noexcept = default; + //! \brief Default destructor + ~signal() noexcept = default; - //! \brief Default move constructor - explicit signal(signal&&) noexcept = default; + //! \brief Default move constructor + explicit signal(signal&&) noexcept = default; - //! \brief Default assignment operator - signal& operator=(signal&&) = default; + //! \brief Default assignment operator + signal& operator=(signal&&) = default; - //! \brief Connect a callable object to this signal - void connect(handler&& fn) { - funcs.emplace_back(std::forward(fn)); - } + //! \brief Connect a callable object to this signal + void connect(handler&& fn) { + funcs.emplace_back(std::forward(fn)); + } - //! \brief Emit this signal by executing all connected callable objects - template - void emit(Args&&... args) { - for(auto& fn : funcs) - fn(std::forward(args)...); - } + //! \brief Emit this signal by executing all connected callable objects + template + void emit(Args&&... args) { + for(auto& fn : funcs) + fn(std::forward(args)...); + } private: - // Set of callable objects registered to be called on demand - std::vector funcs; + // Set of callable objects registered to be called on demand + std::vector funcs; - // Avoid copying - signal(signal const&) = delete; + // Avoid copying + signal(signal const&) = delete; - // Avoid assignment - signal& operator=(signal const&) = delete; + // Avoid assignment + signal& operator=(signal const&) = delete; }; //< class signal #endif //< UTILITY_SIGNAL_HPP diff --git a/api/virtio/console.hpp b/api/virtio/console.hpp index 89b622792d..951789bd9b 100644 --- a/api/virtio/console.hpp +++ b/api/virtio/console.hpp @@ -41,7 +41,7 @@ * placed in the receive queue for incoming data and outgoing * characters are placed in the transmit queue. * -**/ + **/ class VirtioCon : public Virtio { @@ -98,7 +98,7 @@ class VirtioCon : public Virtio /** * Handle device IRQ. * Will look for config. changes and service RX/TX queues as necessary. - **/ + **/ void irq_handler(); Virtio::Queue rx; // 0 diff --git a/api/virtio/virtio.hpp b/api/virtio/virtio.hpp index 4ec99d0cd1..c5affa27b4 100644 --- a/api/virtio/virtio.hpp +++ b/api/virtio/virtio.hpp @@ -16,17 +16,17 @@ // limitations under the License. /** - @note This virtio implementation was very much inspired by - SanOS, (C) Michael Ringgaard. All due respect. + @note This virtio implementation was very much inspired by + SanOS, (C) Michael Ringgaard. All due respect. - STANDARD: + STANDARD: - We're aiming to become standards compilant according to this one: + We're aiming to become standards compilant according to this one: - Virtio 1.0, OASIS Committee Specification Draft 03 - (http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.html) + Virtio 1.0, OASIS Committee Specification Draft 03 + (http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.html) - In the following abbreviated to Virtio 1.03 or Virtio std. + In the following abbreviated to Virtio 1.03 or Virtio std. */ #pragma once #ifndef VIRTIO_VIRTIO_HPP @@ -63,7 +63,7 @@ /** A simple scatter-gather list used for Queue::enqueue. ( From sanos, virtio.h - probably Linux originally) - */ +*/ struct scatterlist { void* data; int size; @@ -76,21 +76,21 @@ class Virtio // http://docs.oasis-open.org/virtio/virtio/v1.0/csprd01/virtio-v1.0-csprd01.html#x1-860005 // Virtio device types enum virtiotype_t - { - RESERVED = 0, - NIC, - BLOCK, - CONSOLE, - ENTROPY, - BALLOON, - IO_MEM, - RP_MSG, - SCSI_HOST, - T9P, - WLAN, - RP_SERIAL, - CAIF - }; + { + RESERVED = 0, + NIC, + BLOCK, + CONSOLE, + ENTROPY, + BALLOON, + IO_MEM, + RP_MSG, + SCSI_HOST, + T9P, + WLAN, + RP_SERIAL, + CAIF + }; /** Virtio Queue class. */ class Queue @@ -111,11 +111,11 @@ class Virtio le32 len; /* This marks a buffer as continuing via the next field. */ - #define VIRTQ_DESC_F_NEXT 1 +#define VIRTQ_DESC_F_NEXT 1 /* This marks a buffer as device write-only (otherwise device read-only). */ - #define VIRTQ_DESC_F_WRITE 2 +#define VIRTQ_DESC_F_WRITE 2 /* This means the buffer contains a list of buffer descriptors. */ - #define VIRTQ_DESC_F_INDIRECT 4 +#define VIRTQ_DESC_F_INDIRECT 4 /* The flags as indicated above. */ le16 flags; /* Next field if flags & NEXT */ @@ -148,7 +148,7 @@ class Virtio le16 flags; le16 idx; struct virtq_used_elem ring[ /* Queue Size */]; - /*le16 avail_event; Only if VIRTIO_F_EVENT_IDX */ + /*le16 avail_event; Only if VIRTIO_F_EVENT_IDX */ }; @@ -299,7 +299,7 @@ class Virtio /** Indicate which Virtio version (PCI revision ID) is supported. Currently only Legacy is supported (partially the 1.0 standard) - */ + */ static inline bool version_supported(uint16_t i) { return i <= 0; } diff --git a/etc/batch_apply_editorconfig.sh b/etc/batch_apply_editorconfig.sh new file mode 100644 index 0000000000..e0fa4ebdef --- /dev/null +++ b/etc/batch_apply_editorconfig.sh @@ -0,0 +1,9 @@ +#! /bin/bash + +SRC=$1 + +for file in `find $SRC \( -not -path "*/cxxabi/*" -not -path "*/STREAM/*" -not -path "*/lest/*" -not -path "*/mod/*" \) -type f \( -name *.cpp -or -name *.hpp -or -name *.inc \)` +do + echo -e "\n >> Formatting $file" + emacs $file -batch --eval '(indent-region (point-min) (point-max) nil)' -f save-buffer +done diff --git a/examples/demo_service/service.cpp b/examples/demo_service/service.cpp index 7acabb6e33..4b69193b60 100644 --- a/examples/demo_service/service.cpp +++ b/examples/demo_service/service.cpp @@ -49,58 +49,58 @@ void Service::start() { auto& server = inet->tcp().bind(80); hw::PIT::instance().onRepeatedTimeout(30s, []{ - printf(" TCP STATUS:\n%s \n", inet->tcp().status().c_str()); - }); + printf(" TCP STATUS:\n%s \n", inet->tcp().status().c_str()); + }); // Add a TCP connection handler - here a hardcoded HTTP-service server.onAccept([](auto conn) -> bool { printf(" @onAccept - Connection attempt from: %s \n", - conn->to_string().c_str()); + conn->to_string().c_str()); return true; // allow all connections - }).onConnect([](auto) { - printf(" @onConnect - Connection successfully established.\n"); + }).onConnect([](auto) { + printf(" @onConnect - Connection successfully established.\n"); - }).onReceive([](auto conn, bool push) { - std::string data = conn->read(1024); - printf(" @onData - PUSH: %d, Data read: \n%s\n", push, data.c_str()); - int color = rand(); - std::stringstream stream; + }).onReceive([](auto conn, bool push) { + std::string data = conn->read(1024); + printf(" @onData - PUSH: %d, Data read: \n%s\n", push, data.c_str()); + int color = rand(); + std::stringstream stream; - /* HTML Fonts */ - std::string ubuntu_medium = "font-family: \'Ubuntu\', sans-serif; font-weight: 500; "; - std::string ubuntu_normal = "font-family: \'Ubuntu\', sans-serif; font-weight: 400; "; - std::string ubuntu_light = "font-family: \'Ubuntu\', sans-serif; font-weight: 300; "; + /* HTML Fonts */ + std::string ubuntu_medium = "font-family: \'Ubuntu\', sans-serif; font-weight: 500; "; + std::string ubuntu_normal = "font-family: \'Ubuntu\', sans-serif; font-weight: 400; "; + std::string ubuntu_light = "font-family: \'Ubuntu\', sans-serif; font-weight: 300; "; - /* HTML */ - stream << "" - << "" - << "" - << "

> 8) << "\">" - << "IncludeOS

" - << "

Now speaks TCP!

" - // .... generate more dynamic content - << "

...and can improvise http. With limitations of course, but it's been easier than expected so far

" - << "

© 2015, Oslo and Akershus University College of Applied Sciences
" - << "\n"; + /* HTML */ + stream << "" + << "" + << "" + << "

> 8) << "\">" + << "IncludeOS

" + << "

Now speaks TCP!

" + // .... generate more dynamic content + << "

...and can improvise http. With limitations of course, but it's been easier than expected so far

" + << "

© 2015, Oslo and Akershus University College of Applied Sciences
" + << "\n"; - /* HTTP-header */ - std::string html = stream.str(); - std::string header="HTTP/1.1 200 OK \n " \ - "Date: Mon, 01 Jan 1970 00:00:01 GMT \n" \ - "Server: IncludeOS prototype 4.0 \n" \ - "Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT \n" \ - "Content-Type: text/html; charset=UTF-8 \n" \ - "Content-Length: "+std::to_string(html.size())+"\n" \ - "Accept-Ranges: bytes\n" \ - "Connection: close\n\n"; + /* HTTP-header */ + std::string html = stream.str(); + std::string header="HTTP/1.1 200 OK \n " \ + "Date: Mon, 01 Jan 1970 00:00:01 GMT \n" \ + "Server: IncludeOS prototype 4.0 \n" \ + "Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT \n" \ + "Content-Type: text/html; charset=UTF-8 \n" \ + "Content-Length: "+std::to_string(html.size())+"\n" \ + "Accept-Ranges: bytes\n" \ + "Connection: close\n\n"; - std::string output{header + html}; - conn->write(output.data(), output.size()); + std::string output{header + html}; + conn->write(output.data(), output.size()); - }).onDisconnect([](auto, auto reason) { - printf(" @onDisconnect - Reason: %s \n", reason.to_string().c_str()); - }); + }).onDisconnect([](auto, auto reason) { + printf(" @onDisconnect - Reason: %s \n", reason.to_string().c_str()); + }); printf("*** TEST SERVICE STARTED *** \n"); } diff --git a/examples/tcp/service.cpp b/examples/tcp/service.cpp index f944aa6fb2..610a7edebf 100644 --- a/examples/tcp/service.cpp +++ b/examples/tcp/service.cpp @@ -16,16 +16,16 @@ // limitations under the License. /* - An example to show incoming and outgoing TCP Connections. - In this example, IncludeOS is listening on port 80. + An example to show incoming and outgoing TCP Connections. + In this example, IncludeOS is listening on port 80. - Data received on port 80 will be redirected to a - outgoing connection to a (in this case) python server (server.py) + Data received on port 80 will be redirected to a + outgoing connection to a (in this case) python server (server.py) - Data received from the python server connection - will be redirected back to the client. + Data received from the python server connection + will be redirected back to the client. - To try it out, use netcat to connect to this IncludeOS instance. + To try it out, use netcat to connect to this IncludeOS instance. */ #include @@ -43,19 +43,19 @@ net::TCP::Socket python_server{ {{10,0,2,2}} , 1337}; // Called when data is received on client (incoming connection) void handle_client_on_receive(Connection_ptr client, Connection_ptr python) { - // Read the request from our client - std::string request = client->read(1024); - printf("Received [Client]: %s\n", request.c_str()); - // Write the request to our python server - python->write(request); + // Read the request from our client + std::string request = client->read(1024); + printf("Received [Client]: %s\n", request.c_str()); + // Write the request to our python server + python->write(request); } // Called when data is received on python (outgoing connection) void handle_python_on_receive(Connection_ptr python, Connection_ptr client) { - // Read the response from our python server - std::string response = python->read(1024); - // Write response to our client - client->write(response); + // Read the response from our python server + std::string response = python->read(1024); + // Write response to our client + client->write(response); } void Service::start() { @@ -74,41 +74,41 @@ void Service::start() { // Set up a TCP server on port 80 auto& server = inet->tcp().bind(80); inet->dhclient()->on_config([&server](auto&) { - printf("Server IP updated: %s\n", server.local().to_string().c_str()); - }); + printf("Server IP updated: %s\n", server.local().to_string().c_str()); + }); printf("Server listening: %s \n", server.local().to_string().c_str()); // When someone connects to our server server.onConnect([](Connection_ptr client) { - printf("Connected [Client]: %s\n", client->to_string().c_str()); - // Make an outgoing connection to our python server - auto outgoing = inet->tcp().connect(python_server); - // When outgoing connection to python sever is established - outgoing->onConnect([client](Connection_ptr python) { - printf("Connected [Python]: %s\n", python->to_string().c_str()); + printf("Connected [Client]: %s\n", client->to_string().c_str()); + // Make an outgoing connection to our python server + auto outgoing = inet->tcp().connect(python_server); + // When outgoing connection to python sever is established + outgoing->onConnect([client](Connection_ptr python) { + printf("Connected [Python]: %s\n", python->to_string().c_str()); - // Setup handlers for when data is received on client and python connection - // When client has data to be read - client->onReceive([python](Connection_ptr client, bool) { - handle_client_on_receive(client, python); - }); + // Setup handlers for when data is received on client and python connection + // When client has data to be read + client->onReceive([python](Connection_ptr client, bool) { + handle_client_on_receive(client, python); + }); - // When python server has data to be read - python->onReceive([client](Connection_ptr python, bool) { - handle_python_on_receive(python, client); - }); + // When python server has data to be read + python->onReceive([client](Connection_ptr python, bool) { + handle_python_on_receive(python, client); + }); - // When client is disconnecting - client->onDisconnect([python](Connection_ptr, Disconnect reason) { - printf("Disconnected [Client]: %s\n", reason.to_string().c_str()); - python->close(); - }); + // When client is disconnecting + client->onDisconnect([python](Connection_ptr, Disconnect reason) { + printf("Disconnected [Client]: %s\n", reason.to_string().c_str()); + python->close(); + }); - // When python is disconnecting - python->onDisconnect([client](Connection_ptr, Disconnect reason) { - printf("Disconnected [Python]: %s\n", reason.to_string().c_str()); - client->close(); - }); - }); // << onConnect (outgoing (python)) - }); // << onConnect (client) + // When python is disconnecting + python->onDisconnect([client](Connection_ptr, Disconnect reason) { + printf("Disconnected [Python]: %s\n", reason.to_string().c_str()); + client->close(); + }); + }); // << onConnect (outgoing (python)) + }); // << onConnect (client) } diff --git a/src/crt/cxx_abi.cpp b/src/crt/cxx_abi.cpp index 911ead7b00..40617afe7f 100644 --- a/src/crt/cxx_abi.cpp +++ b/src/crt/cxx_abi.cpp @@ -22,7 +22,7 @@ * This header is for instantiating and implementing * missing functionality gluing libc++ to the kernel * -**/ + **/ #include extern "C" diff --git a/src/crt/mman.cpp b/src/crt/mman.cpp index d82a15511d..23f99aef44 100644 --- a/src/crt/mman.cpp +++ b/src/crt/mman.cpp @@ -20,15 +20,15 @@ struct mmap_entry_t std::map _mmap_entries; void* mmap(void* addr, size_t length, - int prot, int flags, - int fd, off_t offset) + int prot, int flags, + int fd, off_t offset) { // invalid or misaligned length if (length == 0 || (length & 4095) != 0) - { - errno = EINVAL; - return MAP_FAILED; - } + { + errno = EINVAL; + return MAP_FAILED; + } // associate some VA space with open file @fd // for now just allocate page-aligned on heap @@ -53,15 +53,15 @@ int munmap(void* addr, size_t length) { auto it = _mmap_entries.find(addr); if (it != _mmap_entries.end()) - { - // - assert(it->second.length == length); + { + // + assert(it->second.length == length); - // free and remove the entry - free(it->second.addr); - _mmap_entries.erase(it); - return 0; - } + // free and remove the entry + free(it->second.addr); + _mmap_entries.erase(it); + return 0; + } errno = EINVAL; return -1; } diff --git a/src/debug/ircd.cpp b/src/debug/ircd.cpp index f4ca803615..84068f8a8c 100644 --- a/src/debug/ircd.cpp +++ b/src/debug/ircd.cpp @@ -12,9 +12,9 @@ void Client::split_message(const std::string& msg) printf("[Client]: "); for (auto& str : vec) - { - printf("[%s]", str.c_str()); - } + { + printf("[%s]", str.c_str()); + } printf("\n"); // ignore empty messages if (vec.size() == 0) return; @@ -25,47 +25,47 @@ void Client::split_message(const std::string& msg) void Client::read(const char* buf, size_t len) { while (len > 0) - { - int search = -1; - - for (size_t i = 0; i < len; i++) - if (buf[i] == 13 || buf[i] == 10) - { - search = i; break; - } - // not found: - if (search == -1) - { - // append entire buffer - buffer.append(buf, len); - break; - } - else { - // found CR LF: - if (search != 0) - { - // append to clients buffer - buffer.append(buf, search); - - // move forward in socket buffer - buf += search; - // decrease len - len -= search; - } + int search = -1; + + for (size_t i = 0; i < len; i++) + if (buf[i] == 13 || buf[i] == 10) + { + search = i; break; + } + // not found: + if (search == -1) + { + // append entire buffer + buffer.append(buf, len); + break; + } else - { - buf++; len--; - } + { + // found CR LF: + if (search != 0) + { + // append to clients buffer + buffer.append(buf, search); + + // move forward in socket buffer + buf += search; + // decrease len + len -= search; + } + else + { + buf++; len--; + } - // parse message - if (buffer.size()) - { - split_message(buffer); - buffer.clear(); - } + // parse message + if (buffer.size()) + { + split_message(buffer); + buffer.clear(); + } + } } - } } void Client::send(uint16_t numeric, std::string text) @@ -94,59 +94,59 @@ void Client::send(std::string text) void Client::handle(const std::string&, const std::vector& msg) { - #define TK_CAP "CAP" - #define TK_PASS "PASS" - #define TK_NICK "NICK" - #define TK_USER "USER" +#define TK_CAP "CAP" +#define TK_PASS "PASS" +#define TK_NICK "NICK" +#define TK_USER "USER" const std::string& cmd = msg[0]; if (this->is_reg() == false) - { - if (cmd == TK_CAP) - { - // ignored completely - } - else if (cmd == TK_PASS) { - if (msg.size() > 1) - { - this->passw = msg[1]; - } + if (cmd == TK_CAP) + { + // ignored completely + } + else if (cmd == TK_PASS) + { + if (msg.size() > 1) + { + this->passw = msg[1]; + } + else + { + send(ERR_NEEDMOREPARAMS, cmd + " :Not enough parameters"); + } + } + else if (cmd == TK_NICK) + { + if (msg.size() > 1) + { + this->nick = msg[1]; + welcome(regis | 1); + } + else + { + send(ERR_NEEDMOREPARAMS, cmd + " :Not enough parameters"); + } + } + else if (cmd == TK_USER) + { + if (msg.size() > 1) + { + this->user = msg[1]; + welcome(regis | 2); + } + else + { + send(ERR_NEEDMOREPARAMS, cmd + " :Not enough parameters"); + } + } else - { - send(ERR_NEEDMOREPARAMS, cmd + " :Not enough parameters"); - } + { + send(ERR_NOSUCHCMD, cmd + " :Unknown command"); + } } - else if (cmd == TK_NICK) - { - if (msg.size() > 1) - { - this->nick = msg[1]; - welcome(regis | 1); - } - else - { - send(ERR_NEEDMOREPARAMS, cmd + " :Not enough parameters"); - } - } - else if (cmd == TK_USER) - { - if (msg.size() > 1) - { - this->user = msg[1]; - welcome(regis | 2); - } - else - { - send(ERR_NEEDMOREPARAMS, cmd + " :Not enough parameters"); - } - } - else - { - send(ERR_NOSUCHCMD, cmd + " :Unknown command"); - } - } } #define RPL_WELCOME 1 @@ -162,15 +162,15 @@ void Client::welcome(uint8_t newreg) regis = newreg; // not registered before, but registered now if (!regged && is_reg()) - { - printf("* Registered: %s\n", nickuserhost().c_str()); - send(RPL_WELCOME, ":Welcome to the Internet Relay Network, " + nickuserhost()); - send(RPL_YOURHOST, ":Your host is " + SERVER_NAME + ", running v1.0"); - } + { + printf("* Registered: %s\n", nickuserhost().c_str()); + send(RPL_WELCOME, ":Welcome to the Internet Relay Network, " + nickuserhost()); + send(RPL_YOURHOST, ":Your host is " + SERVER_NAME + ", running v1.0"); + } else if (oldreg == 0) - { - auth_notice(); - } + { + auth_notice(); + } } void Client::auth_notice() { diff --git a/src/debug/ircsplit.hpp b/src/debug/ircsplit.hpp index f9a572a962..e195f79e09 100644 --- a/src/debug/ircsplit.hpp +++ b/src/debug/ircsplit.hpp @@ -10,40 +10,40 @@ split(const std::string& text, std::string& source) if (text.empty()) return retv; // check for source if (text[0] == ':') - { - x = text.find(" ", 1); - source = text.substr(x); - // early return for source-only msg - if (x == std::string::npos) return retv; - p = x+1; - } - // parse remainder - do - { - x = text.find(" ", p+1); - size_t y = text.find(":", x+1); // find last param - - if (y == x+1) - { - // single argument - retv.push_back(text.substr(p, x-p)); - // ending text argument - retv.push_back(text.substr(y+1)); - break; - } - else if (x != std::string::npos) { - // single argument - retv.push_back(text.substr(p, x-p)); + x = text.find(" ", 1); + source = text.substr(x); + // early return for source-only msg + if (x == std::string::npos) return retv; + p = x+1; } - else + // parse remainder + do { - // last argument - retv.push_back(text.substr(p)); - } - p = x+1; + x = text.find(" ", p+1); + size_t y = text.find(":", x+1); // find last param + + if (y == x+1) + { + // single argument + retv.push_back(text.substr(p, x-p)); + // ending text argument + retv.push_back(text.substr(y+1)); + break; + } + else if (x != std::string::npos) + { + // single argument + retv.push_back(text.substr(p, x-p)); + } + else + { + // last argument + retv.push_back(text.substr(p)); + } + p = x+1; - } while (x != std::string::npos); + } while (x != std::string::npos); return retv; } diff --git a/src/debug/test_disk.cpp b/src/debug/test_disk.cpp index 9ef2416bb7..124d4b4fd9 100644 --- a/src/debug/test_disk.cpp +++ b/src/debug/test_disk.cpp @@ -23,106 +23,106 @@ void Service::start() // mount first valid partition (auto-detect and mount) disk->mount( // or specify partition explicitly in parameter - [] (fs::error_t err) - { - if (err) - { - printf("Could not mount filesystem\n"); - return; - } - // get a reference to the mounted filesystem - auto& fs = disk->fs(); + [] (fs::error_t err) + { + if (err) + { + printf("Could not mount filesystem\n"); + return; + } + // get a reference to the mounted filesystem + auto& fs = disk->fs(); - // check contents of disk - auto dirents = fs::new_shared_vector(); - err = fs.ls("/", dirents); - if (err) - printf("Could not list '/' directory\n"); - else - for (auto& e : *dirents) - { - printf("%s: %s\t of size %llu bytes (CL: %llu)\n", - e.type_string().c_str(), e.name().c_str(), e.size, e.block); - } + // check contents of disk + auto dirents = fs::new_shared_vector(); + err = fs.ls("/", dirents); + if (err) + printf("Could not list '/' directory\n"); + else + for (auto& e : *dirents) + { + printf("%s: %s\t of size %llu bytes (CL: %llu)\n", + e.type_string().c_str(), e.name().c_str(), e.size, e.block); + } - auto ent = fs.stat("/test.txt"); - // validate the stat call - if (ent.is_valid()) - { - // read specific area of file - auto buf = fs.read(ent, 1032, 65); - std::string contents((const char*) buf.buffer.get(), buf.len); - printf("[%s contents (%llu bytes)]:\n%s\n[end]\n\n", - ent.name().c_str(), buf.len, contents.c_str()); + auto ent = fs.stat("/test.txt"); + // validate the stat call + if (ent.is_valid()) + { + // read specific area of file + auto buf = fs.read(ent, 1032, 65); + std::string contents((const char*) buf.buffer.get(), buf.len); + printf("[%s contents (%llu bytes)]:\n%s\n[end]\n\n", + ent.name().c_str(), buf.len, contents.c_str()); - } - else - { - printf("Invalid entity for /test.txt\n"); - } - return; + } + else + { + printf("Invalid entity for /test.txt\n"); + } + return; - disk->fs().ls("/", - [] (fs::error_t err, auto ents) - { - if (err) - { - printf("Could not list '/' directory\n"); - return; - } + disk->fs().ls("/", + [] (fs::error_t err, auto ents) + { + if (err) + { + printf("Could not list '/' directory\n"); + return; + } - for (auto& e : *ents) - { - printf("%s: %s\t of size %llu bytes (CL: %llu)\n", - e.type_string().c_str(), e.name().c_str(), e.size, e.block); + for (auto& e : *ents) + { + printf("%s: %s\t of size %llu bytes (CL: %llu)\n", + e.type_string().c_str(), e.name().c_str(), e.size, e.block); - if (e.is_file()) - { - printf("*** Attempting to read: %s\n", e.name().c_str()); - disk->fs().readFile(e, - [e] (fs::error_t err, fs::buffer_t buffer, size_t len) - { - if (err) - { - printf("Failed to read file %s!\n", - e.name().c_str()); - return; - } + if (e.is_file()) + { + printf("*** Attempting to read: %s\n", e.name().c_str()); + disk->fs().readFile(e, + [e] (fs::error_t err, fs::buffer_t buffer, size_t len) + { + if (err) + { + printf("Failed to read file %s!\n", + e.name().c_str()); + return; + } - std::string contents((const char*) buffer.get(), len); - printf("[%s contents]:\n%s\nEOF\n\n", - e.name().c_str(), contents.c_str()); - }); - } - } - }); + std::string contents((const char*) buffer.get(), len); + printf("[%s contents]:\n%s\nEOF\n\n", + e.name().c_str(), contents.c_str()); + }); + } + } + }); - disk->fs().stat("/test.txt", - [] (fs::error_t err, const auto& e) - { - if (err) - { - printf("Could not stat %s\n", e.name().c_str()); - return; - } + disk->fs().stat("/test.txt", + [] (fs::error_t err, const auto& e) + { + if (err) + { + printf("Could not stat %s\n", e.name().c_str()); + return; + } - printf("stat: /test.txt is a %s on cluster %llu\n", - e.type_string().c_str(), e.block); - }); - disk->fs().stat("/Sample Pictures/Koala.jpg", - [] (fs::error_t err, const auto& e) - { - if (err) - { - printf("Could not stat %s\n", e.name().c_str()); - return; - } + printf("stat: /test.txt is a %s on cluster %llu\n", + e.type_string().c_str(), e.block); + }); + disk->fs().stat("/Sample Pictures/Koala.jpg", + [] (fs::error_t err, const auto& e) + { + if (err) + { + printf("Could not stat %s\n", e.name().c_str()); + return; + } - printf("stat: %s is a %s on cluster %llu\n", - e.name().c_str(), e.type_string().c_str(), e.block); - }); + printf("stat: %s is a %s on cluster %llu\n", + e.name().c_str(), e.type_string().c_str(), e.block); + }); - }); // disk->auto_detect() + }); // disk->auto_detect() printf("*** TEST SERVICE STARTED *** \n"); } @@ -130,16 +130,16 @@ void Service::start() void list_partitions(decltype(disk) disk) { disk->partitions( - [] (fs::error_t err, auto& parts) - { - if (err) - { - printf("Failed to retrieve volumes on disk\n"); - return; - } + [] (fs::error_t err, auto& parts) + { + if (err) + { + printf("Failed to retrieve volumes on disk\n"); + return; + } - for (auto& part : parts) - printf("[Partition] '%s' at LBA %u\n", - part.name().c_str(), part.lba()); - }); + for (auto& part : parts) + printf("[Partition] '%s' at LBA %u\n", + part.name().c_str(), part.lba()); + }); } diff --git a/src/debug/test_ipv6.cpp b/src/debug/test_ipv6.cpp index 7fe76ff46d..9bb1b0d917 100644 --- a/src/debug/test_ipv6.cpp +++ b/src/debug/test_ipv6.cpp @@ -40,9 +40,9 @@ void Service::start() // basic UDP service net::Inet::ifconfig( - net::ETH0, - ip4, {{255, 255, 255, 0}}, - ip6); + net::ETH0, + ip4, {{255, 255, 255, 0}}, + ip6); net::Inet* inet = net::Inet::up(); @@ -64,37 +64,37 @@ void Service::start() // basic UDP service static const int UDP_PORT = 64; inet->udp6_listen(UDP_PORT, - [=] (std::shared_ptr& pckt) -> int - { - printf("Received UDP6 packet from %s to my listener on port %d\n", - pckt->src().str().c_str(), pckt->dst_port()); + [=] (std::shared_ptr& pckt) -> int + { + printf("Received UDP6 packet from %s to my listener on port %d\n", + pckt->src().str().c_str(), pckt->dst_port()); - std::string data((const char*) pckt->data(), pckt->data_length()); + std::string data((const char*) pckt->data(), pckt->data_length()); - printf("Contents (len=%d):\n%s\n", pckt->data_length(), data.c_str()); + printf("Contents (len=%d):\n%s\n", pckt->data_length(), data.c_str()); - // unfortunately, - // copy the ether src field of the incoming packet - net::Ethernet::addr ether_src = - ((net::Ethernet::header*) pckt->buffer())->src; + // unfortunately, + // copy the ether src field of the incoming packet + net::Ethernet::addr ether_src = + ((net::Ethernet::header*) pckt->buffer())->src; - // create a response packet with destination [ether_src] dst() - std::shared_ptr newpacket = - inet->udp6_create(ether_src, pckt->dst(), UDP_PORT); + // create a response packet with destination [ether_src] dst() + std::shared_ptr newpacket = + inet->udp6_create(ether_src, pckt->dst(), UDP_PORT); - const char* text = "This is the response packet!"; - // copy text into UDP data section - memcpy( newpacket->data(), text, strlen(text) ); - // set new length - newpacket->set_length(strlen(text)); + const char* text = "This is the response packet!"; + // copy text into UDP data section + memcpy( newpacket->data(), text, strlen(text) ); + // set new length + newpacket->set_length(strlen(text)); - // generate checksum for packet before sending - newpacket->gen_checksum(); + // generate checksum for packet before sending + newpacket->gen_checksum(); - // ship it to the ether - inet->udp6_send(newpacket); - return -1; - } - ); + // ship it to the ether + inet->udp6_send(newpacket); + return -1; + } + ); } diff --git a/src/debug/test_service.cpp b/src/debug/test_service.cpp index c8c14099b7..2553927806 100644 --- a/src/debug/test_service.cpp +++ b/src/debug/test_service.cpp @@ -35,19 +35,19 @@ void Service::start() hw::Nic& eth0 = hw::Dev::eth<0,VirtioNet>(); inet = std::make_unique >(eth0); inet->network_config( - {{ 10,0,0,42 }}, // IP - {{ 255,255,255,0 }}, // Netmask - {{ 10,0,0,1 }}, // Gateway - {{ 8,8,8,8 }} ); // DNS + {{ 10,0,0,42 }}, // IP + {{ 255,255,255,0 }}, // Netmask + {{ 10,0,0,1 }}, // Gateway + {{ 8,8,8,8 }} ); // DNS /* - auto& tcp = inet->tcp(); - auto& server = tcp.bind(6667); // IRCd default port - server.onConnect( - [] (auto csock) - { + auto& tcp = inet->tcp(); + auto& server = tcp.bind(6667); // IRCd default port + server.onConnect( + [] (auto csock) + { printf("*** Received connection from %s\n", - csock->remote().to_string().c_str()); + csock->remote().to_string().c_str()); /// create client /// size_t index = clients.size(); @@ -59,22 +59,22 @@ void Service::start() csock->onReceive( [&client] (auto conn, bool) { - char buffer[1024]; - size_t bytes = conn->read(buffer, sizeof(buffer)); + char buffer[1024]; + size_t bytes = conn->read(buffer, sizeof(buffer)); - client.read(buffer, bytes); + client.read(buffer, bytes); }); .onDisconnect( [&client] (auto conn, std::string) { - // remove client from various lists - client.remove(); - /// inform others about disconnect - //client.bcast(TK_QUIT, "Disconnected"); + // remove client from various lists + client.remove(); + /// inform others about disconnect + //client.bcast(TK_QUIT, "Disconnected"); }); - });*/ + });*/ /// terminal /// auto& serial = hw::Serial::port<1> (); @@ -82,12 +82,12 @@ void Service::start() term = std::make_unique (serial); // add 'ifconfig' command term->add( - "ifconfig", "Show information about interfaces", - [] (const std::vector&) -> int - { - term->write("%s\r\n", inet->tcp().status().c_str()); - return 0; - }); + "ifconfig", "Show information about interfaces", + [] (const std::vector&) -> int + { + term->write("%s\r\n", inet->tcp().status().c_str()); + return 0; + }); /// terminal /// printf("*** TEST SERVICE STARTED *** \n"); diff --git a/src/debug/test_tcp.cpp b/src/debug/test_tcp.cpp index 4318d649f4..f42594c305 100644 --- a/src/debug/test_tcp.cpp +++ b/src/debug/test_tcp.cpp @@ -41,18 +41,18 @@ void Service::start() { auto& server = inet->tcp().bind(80); hw::PIT::instance().onTimeout(5s, [server]{ - printf("Server is running: %s \n", server.to_string().c_str()); - }); + printf("Server is running: %s \n", server.to_string().c_str()); + }); server.onPacketReceived([](auto conn, auto packet) { - printf(" Received: %s\n", packet->to_string().c_str()); + printf(" Received: %s\n", packet->to_string().c_str()); - }).onPacketDropped([](auto packet, std::string reason) { - printf(" Dropped: %s - Reason: %s \n", packet->to_string().c_str(), reason.c_str()); + }).onPacketDropped([](auto packet, std::string reason) { + printf(" Dropped: %s - Reason: %s \n", packet->to_string().c_str(), reason.c_str()); - }).onReceive([](auto conn, bool) { - conn->write("Hey"); - }).onConnect([](auto conn) { - printf(" Connected.\n"); - }); + }).onReceive([](auto conn, bool) { + conn->write("Hey"); + }).onConnect([](auto conn) { + printf(" Connected.\n"); + }); } diff --git a/src/fs/disk.cpp b/src/fs/disk.cpp index c7828319c5..f6e8afa24a 100644 --- a/src/fs/disk.cpp +++ b/src/fs/disk.cpp @@ -21,131 +21,131 @@ namespace fs { -Disk::Disk(hw::IDiskDevice& dev) - : device {dev} + Disk::Disk(hw::IDiskDevice& dev) + : device {dev} { // for now we can only assume FAT, anyways filesys.reset(new FAT(device)); } -void Disk::partitions(on_parts_func func) { + void Disk::partitions(on_parts_func func) { - /** Read Master Boot Record (sector 0) */ - device.read(0, - [this, func] (hw::IDiskDevice::buffer_t data) - { - std::vector parts; + /** Read Master Boot Record (sector 0) */ + device.read(0, + [this, func] (hw::IDiskDevice::buffer_t data) + { + std::vector parts; - if (!data) { - func(true, parts); - return; - } + if (!data) { + func(true, parts); + return; + } - // First sector is the Master Boot Record - auto* mbr =(MBR::mbr*) data.get(); + // First sector is the Master Boot Record + auto* mbr =(MBR::mbr*) data.get(); - for (int i {0}; i < 4; ++i) { - // all the partitions are offsets to potential Volume Boot Records - parts.emplace_back( - mbr->part[i].flags, //< flags - mbr->part[i].type, //< id - mbr->part[i].lba_begin, //< LBA - mbr->part[i].sectors); - } + for (int i {0}; i < 4; ++i) { + // all the partitions are offsets to potential Volume Boot Records + parts.emplace_back( + mbr->part[i].flags, //< flags + mbr->part[i].type, //< id + mbr->part[i].lba_begin, //< LBA + mbr->part[i].sectors); + } - func(no_error, parts); - }); -} + func(no_error, parts); + }); + } -void Disk::mount(on_mount_func func) -{ - device.read(0, - [this, func] (hw::IDiskDevice::buffer_t data) + void Disk::mount(on_mount_func func) { - if (!data) { - // TODO: error-case for unable to read MBR - mount(INVALID, func); - return; - } + device.read(0, + [this, func] (hw::IDiskDevice::buffer_t data) + { + if (!data) { + // TODO: error-case for unable to read MBR + mount(INVALID, func); + return; + } - // auto-detect FAT on MBR: - auto* mbr = (MBR::mbr*) data.get(); - MBR::BPB* bpb = mbr->bpb(); + // auto-detect FAT on MBR: + auto* mbr = (MBR::mbr*) data.get(); + MBR::BPB* bpb = mbr->bpb(); - if (bpb->bytes_per_sector >= 512 - && bpb->fa_tables != 0 - && bpb->signature != 0) // check MBR signature too - { - // we have FAT on MBR (and we are assuming mount FAT) - mount(MBR, func); - return; - } + if (bpb->bytes_per_sector >= 512 + && bpb->fa_tables != 0 + && bpb->signature != 0) // check MBR signature too + { + // we have FAT on MBR (and we are assuming mount FAT) + mount(MBR, func); + return; + } - // go through partition list - for (int i = 0; i < 4; i++) - { - if (mbr->part[i].type != 0 // 0 is unused partition - && mbr->part[i].lba_begin != 0 // 0 is MBR anyways - && mbr->part[i].sectors != 0) // 0 means no size, so... - { - mount((partition_t) (VBR1 + i), func); - return; - } - } + // go through partition list + for (int i = 0; i < 4; i++) + { + if (mbr->part[i].type != 0 // 0 is unused partition + && mbr->part[i].lba_begin != 0 // 0 is MBR anyways + && mbr->part[i].sectors != 0) // 0 means no size, so... + { + mount((partition_t) (VBR1 + i), func); + return; + } + } - // no partition was found (TODO: extended partitions) - mount(INVALID, func); - return; - }); -} + // no partition was found (TODO: extended partitions) + mount(INVALID, func); + return; + }); + } -void Disk::mount(partition_t part, on_mount_func func) { + void Disk::mount(partition_t part, on_mount_func func) { - if (part == INVALID) - { - // Something bad happened maybe in auto-detect - // Either way, no partition was found - func(true); - return; - } - else if (part == MBR) - { - // For the MBR case, all we need to do is mount on sector 0 - fs().mount(0, device.size(), func); - } - else - { - /** - * Otherwise, we will have to read the LBA offset - * of the partition to be mounted - */ - device.read(0, - [this, part, func] (hw::IDiskDevice::buffer_t data) - { - if (!data) { - // TODO: error-case for unable to read MBR - func(true); - return; + if (part == INVALID) + { + // Something bad happened maybe in auto-detect + // Either way, no partition was found + func(true); + return; + } + else if (part == MBR) + { + // For the MBR case, all we need to do is mount on sector 0 + fs().mount(0, device.size(), func); } + else + { + /** + * Otherwise, we will have to read the LBA offset + * of the partition to be mounted + */ + device.read(0, + [this, part, func] (hw::IDiskDevice::buffer_t data) + { + if (!data) { + // TODO: error-case for unable to read MBR + func(true); + return; + } - auto* mbr = (MBR::mbr*) data.get(); //< Treat data as MBR - auto pint = static_cast(part - 1); //< Treat VBR1 as index 0 etc. + auto* mbr = (MBR::mbr*) data.get(); //< Treat data as MBR + auto pint = static_cast(part - 1); //< Treat VBR1 as index 0 etc. - /** Get LBA from selected partition */ - auto lba_base = mbr->part[pint].lba_begin; - auto lba_size = mbr->part[pint].sectors; + /** Get LBA from selected partition */ + auto lba_base = mbr->part[pint].lba_begin; + auto lba_size = mbr->part[pint].sectors; - /** - * Call the filesystems mount function - * with lba_begin as base address - */ - fs().mount(lba_base, lba_size, func); - }); + /** + * Call the filesystems mount function + * with lba_begin as base address + */ + fs().mount(lba_base, lba_size, func); + }); + } } -} -std::string Disk::Partition::name() const { - return MBR::id_to_name(id); -} + std::string Disk::Partition::name() const { + return MBR::id_to_name(id); + } } //< namespace fs diff --git a/src/fs/ext4.cpp b/src/fs/ext4.cpp index 7a6e26cd9b..a361e72173 100644 --- a/src/fs/ext4.cpp +++ b/src/fs/ext4.cpp @@ -19,26 +19,26 @@ namespace fs void EXT4::mount(uint64_t start, uint64_t size, on_mount_func on_mount) { printf("Superblock: %u bytes, Block group desc: %u bytes\n", - sizeof(superblock), sizeof(group_desc)); + sizeof(superblock), sizeof(group_desc)); assert(sizeof(superblock) == 1024); assert(sizeof(group_desc) == 64); printf("Inode table: %u\n", - sizeof(inode_table)); + sizeof(inode_table)); // read Master Boot Record (sector 0) device.read(start, - [this, start, size, on_mount] (buffer_t data) - { - auto* mbr = (MBR::mbr*) data.get(); - assert(mbr != nullptr); + [this, start, size, on_mount] (buffer_t data) + { + auto* mbr = (MBR::mbr*) data.get(); + assert(mbr != nullptr); - /// now what? - printf("Mounting EXT4 from LBA %llu to %llu\n", - start, size); + /// now what? + printf("Mounting EXT4 from LBA %llu to %llu\n", + start, size); - init(data.get()); - }); + init(data.get()); + }); } diff --git a/src/fs/fat.cpp b/src/fs/fat.cpp index 361c5dfc81..72a126a5de 100644 --- a/src/fs/fat.cpp +++ b/src/fs/fat.cpp @@ -15,8 +15,8 @@ #define unlikely(x) __builtin_expect(!!(x), 0) inline std::string trim_right_copy( - const std::string& s, - const std::string& delimiters = " \f\n\r\t\v" ) + const std::string& s, + const std::string& delimiters = " \f\n\r\t\v" ) { return s.substr( 0, s.find_last_not_of( delimiters ) + 1 ); } @@ -37,11 +37,11 @@ namespace fs MBR::BPB* bpb = mbr->bpb(); this->sector_size = bpb->bytes_per_sector; if (unlikely(this->sector_size < 512)) - { - printf("Invalid sector size (%u) for FAT32 partition\n", sector_size); - printf("Are you mounting the correct partition?\n"); - panic("FAT32: Invalid sector size"); - } + { + printf("Invalid sector size (%u) for FAT32 partition\n", sector_size); + printf("Are you mounting the correct partition?\n"); + panic("FAT32: Invalid sector size"); + } // Let's begin our incantation // To drive out the demons of old DOS we have to read some PBP values @@ -70,7 +70,7 @@ namespace fs // sectors per FAT (not sure about the rule here) this->sectors_per_fat = bpb->sectors_per_fat; if (this->sectors_per_fat == 0) - this->sectors_per_fat = *(uint32_t*) &mbr->boot[25]; + this->sectors_per_fat = *(uint32_t*) &mbr->boot[25]; // root dir sectors from root entries this->root_dir_sectors = ((bpb->root_entries * 32) + (sector_size - 1)) / sector_size; // calculate index of first data sector @@ -92,28 +92,28 @@ namespace fs // now that we're here, we can determine the actual FAT type // using the official method: if (this->clusters < 4085) - { - this->fat_type = FAT::T_FAT12; - this->root_cluster = 2; - debug("The image is type FAT12, with %u clusters\n", this->clusters); - } + { + this->fat_type = FAT::T_FAT12; + this->root_cluster = 2; + debug("The image is type FAT12, with %u clusters\n", this->clusters); + } else if (this->clusters < 65525) - { - this->fat_type = FAT::T_FAT16; - this->root_cluster = 2; - debug("The image is type FAT16, with %u clusters\n", this->clusters); - } + { + this->fat_type = FAT::T_FAT16; + this->root_cluster = 2; + debug("The image is type FAT16, with %u clusters\n", this->clusters); + } else - { - this->fat_type = FAT::T_FAT32; - this->root_cluster = *(uint32_t*) &mbr->boot[33]; - this->root_cluster = 2; - debug("The image is type FAT32, with %u clusters\n", this->clusters); - //printf("Root dir entries: %u clusters\n", bpb->root_entries); - //assert(bpb->root_entries == 0); - //this->root_dir_sectors = 0; - //this->data_index = bpb->reserved_sectors + bpb->fa_tables * this->sectors_per_fat; - } + { + this->fat_type = FAT::T_FAT32; + this->root_cluster = *(uint32_t*) &mbr->boot[33]; + this->root_cluster = 2; + debug("The image is type FAT32, with %u clusters\n", this->clusters); + //printf("Root dir entries: %u clusters\n", bpb->root_entries); + //assert(bpb->root_entries == 0); + //this->root_dir_sectors = 0; + //this->data_index = bpb->reserved_sectors + bpb->fa_tables * this->sectors_per_fat; + } debug("Root cluster index: %u (sector %u)\n", this->root_cluster, cl_to_sector(root_cluster)); debug("System ID: %.8s\n", bpb->system_id); } @@ -125,149 +125,149 @@ namespace fs // read Partition block device.read(this->lba_base, - [this, on_mount] (buffer_t data) - { - auto* mbr = (MBR::mbr*) data.get(); - assert(mbr != nullptr); + [this, on_mount] (buffer_t data) + { + auto* mbr = (MBR::mbr*) data.get(); + assert(mbr != nullptr); - // verify image signature - debug("OEM name: \t%s\n", mbr->oem_name); - debug("MBR signature: \t0x%x\n", mbr->magic); - assert(mbr->magic == 0xAA55); + // verify image signature + debug("OEM name: \t%s\n", mbr->oem_name); + debug("MBR signature: \t0x%x\n", mbr->magic); + assert(mbr->magic == 0xAA55); - // initialize FAT16 or FAT32 filesystem - init(mbr); + // initialize FAT16 or FAT32 filesystem + init(mbr); - // determine which FAT version is mounted - std::string inf = "ofs: " + std::to_string(lba_base) + - "size: " + std::to_string(lba_size) + - " (" + std::to_string(this->lba_size * sector_size) + " bytes)\n"; + // determine which FAT version is mounted + std::string inf = "ofs: " + std::to_string(lba_base) + + "size: " + std::to_string(lba_size) + + " (" + std::to_string(this->lba_size * sector_size) + " bytes)\n"; - switch (this->fat_type) - { - case FAT::T_FAT12: - INFO("FS", "Mounting FAT12 filesystem"); - break; - case FAT::T_FAT16: - INFO("FS", "Mounting FAT16 filesystem"); - break; - case FAT::T_FAT32: - INFO("FS", "Mounting FAT32 filesystem"); - break; - } - INFO2("[ofs=%u size=%u (%u bytes)]\n", - this->lba_base, this->lba_size, this->lba_size * 512); + switch (this->fat_type) + { + case FAT::T_FAT12: + INFO("FS", "Mounting FAT12 filesystem"); + break; + case FAT::T_FAT16: + INFO("FS", "Mounting FAT16 filesystem"); + break; + case FAT::T_FAT32: + INFO("FS", "Mounting FAT32 filesystem"); + break; + } + INFO2("[ofs=%u size=%u (%u bytes)]\n", + this->lba_base, this->lba_size, this->lba_size * 512); - // on_mount callback - on_mount(no_error); - }); + // on_mount callback + on_mount(no_error); + }); } bool FAT::int_dirent( - uint32_t sector, - const void* data, - dirvec_t dirents) + uint32_t sector, + const void* data, + dirvec_t dirents) { - auto* root = (cl_dir*) data; - bool found_last = false; + auto* root = (cl_dir*) data; + bool found_last = false; - for (int i = 0; i < 16; i++) + for (int i = 0; i < 16; i++) { if (unlikely(root[i].shortname[0] == 0x0)) - { - //printf("end of dir\n"); - found_last = true; - // end of directory - break; - } + { + //printf("end of dir\n"); + found_last = true; + // end of directory + break; + } else if (unlikely(root[i].shortname[0] == 0xE5)) - { - // unused index - } + { + // unused index + } else - { + { // traverse long names, then final cluster // to read all the relevant info if (likely(root[i].is_longname())) - { - auto* L = (cl_long*) &root[i]; - // the last long index is part of a chain of entries - if (L->is_last()) - { - // buffer for long filename - char final_name[256]; - int final_count = 0; + { + auto* L = (cl_long*) &root[i]; + // the last long index is part of a chain of entries + if (L->is_last()) + { + // buffer for long filename + char final_name[256]; + int final_count = 0; - int total = L->long_index(); - // go to the last entry and work backwards - i += total-1; - L += total-1; + int total = L->long_index(); + // go to the last entry and work backwards + i += total-1; + L += total-1; - for (int idx = total; idx > 0; idx--) - { - uint16_t longname[13]; - memcpy(longname+ 0, L->first, 10); - memcpy(longname+ 5, L->second, 12); - memcpy(longname+11, L->third, 4); + for (int idx = total; idx > 0; idx--) + { + uint16_t longname[13]; + memcpy(longname+ 0, L->first, 10); + memcpy(longname+ 5, L->second, 12); + memcpy(longname+11, L->third, 4); - for (int j = 0; j < 13; j++) - { - // 0xFFFF indicates end of name - if (unlikely(longname[j] == 0xFFFF)) break; - // sometimes, invalid stuff are snuck into filenames - if (unlikely(longname[j] == 0x0)) break; + for (int j = 0; j < 13; j++) + { + // 0xFFFF indicates end of name + if (unlikely(longname[j] == 0xFFFF)) break; + // sometimes, invalid stuff are snuck into filenames + if (unlikely(longname[j] == 0x0)) break; - final_name[final_count] = longname[j] & 0xFF; - final_count++; - } - L--; + final_name[final_count] = longname[j] & 0xFF; + final_count++; + } + L--; - if (unlikely(final_count > 240)) - { - debug("Suspicious long name length, breaking...\n"); - break; - } - } + if (unlikely(final_count > 240)) + { + debug("Suspicious long name length, breaking...\n"); + break; + } + } - final_name[final_count] = 0; - debug("Long name: %s\n", final_name); + final_name[final_count] = 0; + debug("Long name: %s\n", final_name); - i++; // skip over the long version - // to the short version for the stats and cluster - auto* D = &root[i]; - std::string dirname(final_name, final_count); - dirname = trim_right_copy(dirname); + i++; // skip over the long version + // to the short version for the stats and cluster + auto* D = &root[i]; + std::string dirname(final_name, final_count); + dirname = trim_right_copy(dirname); - dirents->emplace_back( - D->type(), - dirname, - D->dir_cluster(root_cluster), - sector, // parent block - D->size(), - D->attrib); - } - } + dirents->emplace_back( + D->type(), + dirname, + D->dir_cluster(root_cluster), + sector, // parent block + D->size(), + D->attrib); + } + } else - { - auto* D = &root[i]; - debug("Short name: %.11s\n", D->shortname); + { + auto* D = &root[i]; + debug("Short name: %.11s\n", D->shortname); - std::string dirname((char*) D->shortname, 11); - dirname = trim_right_copy(dirname); + std::string dirname((char*) D->shortname, 11); + dirname = trim_right_copy(dirname); - dirents->emplace_back( - D->type(), - dirname, - D->dir_cluster(root_cluster), - sector, // parent block - D->size(), - D->attrib); - } - } + dirents->emplace_back( + D->type(), + dirname, + D->dir_cluster(root_cluster), + sector, // parent block + D->size(), + D->attrib); + } + } } // directory list - return found_last; + return found_last; } } diff --git a/src/fs/fat_async.cpp b/src/fs/fat_async.cpp index 965a35de98..ca1cb4b1db 100644 --- a/src/fs/fat_async.cpp +++ b/src/fs/fat_async.cpp @@ -15,43 +15,43 @@ namespace fs { void FAT::int_ls( - uint32_t sector, - dirvec_t dirents, - on_internal_ls_func callback) + uint32_t sector, + dirvec_t dirents, + on_internal_ls_func callback) { // list contents of meme sector by sector typedef std::function next_func_t; auto next = std::make_shared (); *next = - [this, sector, callback, dirents, next] (uint32_t sector) - { - debug("int_ls: sec=%u\n", sector); - device.read(sector, - [this, sector, callback, dirents, next] (buffer_t data) + [this, sector, callback, dirents, next] (uint32_t sector) + { + debug("int_ls: sec=%u\n", sector); + device.read(sector, + [this, sector, callback, dirents, next] (buffer_t data) { if (!data) - { - // could not read sector - callback(true, dirents); - return; - } + { + // could not read sector + callback(true, dirents); + return; + } // parse entries in sector bool done = int_dirent(sector, data.get(), dirents); if (done) - { - // execute callback - callback(no_error, dirents); - } + { + // execute callback + callback(no_error, dirents); + } else - { - // go to next sector - (*next)(sector+1); - } + { + // go to next sector + (*next)(sector+1); + } }); // read root dir - }; + }; // start reading sectors asynchronously (*next)(sector); @@ -65,68 +65,68 @@ namespace fs // asynch stack traversal auto next = std::make_shared (); *next = - [this, path, next, callback] (uint32_t cluster) - { - if (path->empty()) + [this, path, next, callback] (uint32_t cluster) { - // attempt to read directory - uint32_t S = this->cl_to_sector(cluster); + if (path->empty()) + { + // attempt to read directory + uint32_t S = this->cl_to_sector(cluster); - // result allocated on heap - auto dirents = std::make_shared> (); + // result allocated on heap + auto dirents = std::make_shared> (); - int_ls(S, dirents, - [callback] (error_t error, dirvec_t ents) - { - callback(error, ents); - }); - return; - } + int_ls(S, dirents, + [callback] (error_t error, dirvec_t ents) + { + callback(error, ents); + }); + return; + } - // retrieve next name - std::string name = path->front(); - path->pop_front(); + // retrieve next name + std::string name = path->front(); + path->pop_front(); - uint32_t S = this->cl_to_sector(cluster); - debug("Current target: %s on cluster %u (sector %u)\n", name.c_str(), cluster, S); + uint32_t S = this->cl_to_sector(cluster); + debug("Current target: %s on cluster %u (sector %u)\n", name.c_str(), cluster, S); - // result allocated on heap - auto dirents = std::make_shared> (); + // result allocated on heap + auto dirents = std::make_shared> (); - // list directory contents - int_ls(S, dirents, - [name, dirents, next, callback] (error_t error, dirvec_t ents) + // list directory contents + int_ls(S, dirents, + [name, dirents, next, callback] (error_t error, dirvec_t ents) { if (unlikely(error)) - { - debug("Could not find: %s\n", name.c_str()); - callback(true, dirents); - return; - } + { + debug("Could not find: %s\n", name.c_str()); + callback(true, dirents); + return; + } // look for name in directory for (auto& e : *ents) - { - if (unlikely(e.name() == name)) - { - // go to this directory, unless its the last name - debug("Found match for %s", name.c_str()); - // enter the matching directory - debug("\t\t cluster: %llu\n", e.block); - // only follow directories - if (e.type() == DIR) - (*next)(e.block); - else - callback(true, dirents); - return; - } - } // for (ents) + { + if (unlikely(e.name() == name)) + { + // go to this directory, unless its the last name + debug("Found match for %s", name.c_str()); + // enter the matching directory + debug("\t\t cluster: %llu\n", e.block); + // only follow directories + if (e.type() == DIR) + (*next)(e.block); + else + callback(true, dirents); + return; + } + } // for (ents) debug("NO MATCH for %s\n", name.c_str()); callback(true, dirents); }); - }; + }; // start by reading root directory (*next)(0); } @@ -137,10 +137,10 @@ namespace fs auto pstk = std::make_shared (path); traverse(pstk, - [on_ls] (error_t error, dirvec_t dirents) - { - on_ls(error, dirents); - }); + [on_ls] (error_t error, dirvec_t dirents) + { + on_ls(error, dirents); + }); } void FAT::read(const Dirent& ent, uint64_t pos, uint64_t n, on_read_func callback) @@ -156,51 +156,51 @@ namespace fs auto next = std::make_shared (); *next = - [this, sector, buffer, callback, next] (size_t start, size_t n, size_t end) - { - if (unlikely(n == end)) + [this, sector, buffer, callback, next] (size_t start, size_t n, size_t end) { - // report back to HQ - debug("DONE start=%lu, current=%lu, total=%lu\n", start, n, end - start); - // create shared buffer - auto buffer_ptr = buffer_t(buffer, std::default_delete()); - // notify caller - callback(no_error, buffer_ptr, end - start); - return; - } + if (unlikely(n == end)) + { + // report back to HQ + debug("DONE start=%lu, current=%lu, total=%lu\n", start, n, end - start); + // create shared buffer + auto buffer_ptr = buffer_t(buffer, std::default_delete()); + // notify caller + callback(no_error, buffer_ptr, end - start); + return; + } - // read the current sector based on position @n - uint32_t current_sector = sector + n / this->sector_size; + // read the current sector based on position @n + uint32_t current_sector = sector + n / this->sector_size; - device.read(current_sector, - [this, start, n, end, buffer, &callback, sector, next] (buffer_t data) + device.read(current_sector, + [this, start, n, end, buffer, &callback, sector, next] (buffer_t data) { if (!data) - { - // general I/O error occurred - debug("Failed to read sector %u for read()", sector); - // cleanup - delete[] buffer; - callback(true, buffer_t(), 0); - return; - } + { + // general I/O error occurred + debug("Failed to read sector %u for read()", sector); + // cleanup + delete[] buffer; + callback(true, buffer_t(), 0); + return; + } uint32_t length = n & (sector_size-1); if (n == start && n > 0) - { - length = sector_size - length; - } + { + length = sector_size - length; + } else - { - length = (n + sector_size) < end ? sector_size : (end - n); - } + { + length = (n + sector_size) < end ? sector_size : (end - n); + } // copy over data memcpy(buffer + n, data.get(), length); // continue reading next sector (*next)(start, n + length, end); }); - }; + }; // start! (*next)(pos, pos, pos + n); @@ -210,52 +210,52 @@ namespace fs { auto path = std::make_shared (strpath); if (unlikely(path->empty())) - { - // there is no possible file to read where path is empty - callback(true, nullptr, 0); - return; - } + { + // there is no possible file to read where path is empty + callback(true, nullptr, 0); + return; + } debug("readFile: %s\n", path->back().c_str()); std::string filename = path->back(); path->pop_back(); traverse(path, - [this, filename, &callback] (error_t error, dirvec_t dirents) - { - if (unlikely(error)) - { - // no path, no file! - callback(error, buffer_t(), 0); - return; - } + [this, filename, &callback] (error_t error, dirvec_t dirents) + { + if (unlikely(error)) + { + // no path, no file! + callback(error, buffer_t(), 0); + return; + } - // find the matching filename in directory - for (auto& ent : *dirents) - { - if (unlikely(ent.name() == filename)) - { - // read this file - read(ent, 0, ent.size, callback); - return; - } - } + // find the matching filename in directory + for (auto& ent : *dirents) + { + if (unlikely(ent.name() == filename)) + { + // read this file + read(ent, 0, ent.size, callback); + return; + } + } - // file not found - callback(true, buffer_t(), 0); - }); + // file not found + callback(true, buffer_t(), 0); + }); } // readFile() void FAT::stat(const std::string& strpath, on_stat_func func) { auto path = std::make_shared (strpath); if (unlikely(path->empty())) - { - // root doesn't have any stat anyways - // Note: could use ATTR_VOLUME_ID in FAT - func(true, Dirent(INVALID_ENTITY, strpath)); - return; - } + { + // root doesn't have any stat anyways + // Note: could use ATTR_VOLUME_ID in FAT + func(true, Dirent(INVALID_ENTITY, strpath)); + return; + } debug("stat: %s\n", path->back().c_str()); // extract file we are looking for @@ -265,28 +265,28 @@ namespace fs auto callback = std::make_shared (func); traverse(path, - [this, filename, callback] (error_t error, dirvec_t dirents) - { - if (unlikely(error)) - { - // no path, no file! - (*callback)(error, Dirent(INVALID_ENTITY, filename)); - return; - } + [this, filename, callback] (error_t error, dirvec_t dirents) + { + if (unlikely(error)) + { + // no path, no file! + (*callback)(error, Dirent(INVALID_ENTITY, filename)); + return; + } - // find the matching filename in directory - for (auto& e : *dirents) - { - if (unlikely(e.name() == filename)) - { - // read this file - (*callback)(no_error, e); - return; - } - } + // find the matching filename in directory + for (auto& e : *dirents) + { + if (unlikely(e.name() == filename)) + { + // read this file + (*callback)(no_error, e); + return; + } + } - // not found - (*callback)(true, Dirent(INVALID_ENTITY, filename)); - }); + // not found + (*callback)(true, Dirent(INVALID_ENTITY, filename)); + }); } } diff --git a/src/fs/fat_sync.cpp b/src/fs/fat_sync.cpp index 6a446d3712..ffe3dd2730 100644 --- a/src/fs/fat_sync.cpp +++ b/src/fs/fat_sync.cpp @@ -35,11 +35,11 @@ namespace fs // if what we want to read is larger than the rest, exit early if (rest > n) - { - memcpy(result, data.get() + internal_ofs, n); + { + memcpy(result, data.get() + internal_ofs, n); - return Buffer(no_error, buffer_t(result), n); - } + return Buffer(no_error, buffer_t(result), n); + } // otherwise, read to the sector border uint8_t* ptr = result; memcpy(ptr, data.get() + internal_ofs, rest); @@ -49,21 +49,21 @@ namespace fs // copy entire sectors while (n > device.block_size()) - { - data = device.read_sync(sector); + { + data = device.read_sync(sector); - memcpy(ptr, data.get(), device.block_size()); - ptr += device.block_size(); - n -= device.block_size(); - sector += 1; - } + memcpy(ptr, data.get(), device.block_size()); + ptr += device.block_size(); + n -= device.block_size(); + sector += 1; + } // copy remainder if (likely(n > 0)) - { - data = device.read_sync(sector); - memcpy(ptr, data.get(), n); - } + { + data = device.read_sync(sector); + memcpy(ptr, data.get(), n); + } return Buffer(no_error, buffer_t(result), total); } @@ -72,10 +72,10 @@ namespace fs { Path path(strpath); if (unlikely(path.empty())) - { - // there is no possible file to read where path is empty - return Buffer(true, nullptr, 0); - } + { + // there is no possible file to read where path is empty + return Buffer(true, nullptr, 0); + } debug("readFile: %s\n", path.back().c_str()); std::string filename = path.back(); @@ -89,13 +89,13 @@ namespace fs // find the matching filename in directory for (auto& e : *dirents) - { - if (unlikely(e.name() == filename)) { - // read this file - return read(e, 0, e.size); + if (unlikely(e.name() == filename)) + { + // read this file + return read(e, 0, e.size); + } } - } // entry not found return Buffer(true, buffer_t(), 0); } // readFile() @@ -104,15 +104,15 @@ namespace fs { bool done = false; while (!done) - { - // read sector sync - buffer_t data = device.read_sync(sector); - if (!data) return true; - // parse directory into @ents - done = int_dirent(sector, data.get(), ents); - // go to next sector until done - sector++; - } + { + // read sector sync + buffer_t data = device.read_sync(sector); + if (!data) return true; + // parse directory into @ents + done = int_dirent(sector, data.get(), ents); + // go to next sector until done + sector++; + } return no_error; } @@ -125,46 +125,46 @@ namespace fs Dirent found(INVALID_ENTITY); while (!path.empty()) - { - uint32_t S = this->cl_to_sector(cluster); - dirents->clear(); // mui importante - // sync read entire directory - auto err = int_ls(S, dirents); - if (err) return err; - // the name we are looking for - std::string name = path.front(); - path.pop_front(); - - // check for matches in dirents - for (auto& e : *dirents) - if (unlikely(e.name() == name)) { - // go to this directory, unless its the last name - debug("traverse_sync: Found match for %s", name.c_str()); - // enter the matching directory - debug("\t\t cluster: %lu\n", e.block); - // only follow if the name is a directory - if (e.type() == DIR) - { - found = e; - break; - } - else - { - // not dir = error, for now - return true; - } - } // for (ents) + uint32_t S = this->cl_to_sector(cluster); + dirents->clear(); // mui importante + // sync read entire directory + auto err = int_ls(S, dirents); + if (err) return err; + // the name we are looking for + std::string name = path.front(); + path.pop_front(); - // validate result - if (found.type() == INVALID_ENTITY) - { - debug("traverse_sync: NO MATCH for %s\n", name.c_str()); - return true; + // check for matches in dirents + for (auto& e : *dirents) + if (unlikely(e.name() == name)) + { + // go to this directory, unless its the last name + debug("traverse_sync: Found match for %s", name.c_str()); + // enter the matching directory + debug("\t\t cluster: %lu\n", e.block); + // only follow if the name is a directory + if (e.type() == DIR) + { + found = e; + break; + } + else + { + // not dir = error, for now + return true; + } + } // for (ents) + + // validate result + if (found.type() == INVALID_ENTITY) + { + debug("traverse_sync: NO MATCH for %s\n", name.c_str()); + return true; + } + // set next cluster + cluster = found.block; } - // set next cluster - cluster = found.block; - } uint32_t S = this->cl_to_sector(cluster); // read result directory entries into ents @@ -180,10 +180,10 @@ namespace fs { Path path(strpath); if (unlikely(path.empty())) - { - // root doesn't have any stat anyways (except ATTR_VOLUME_ID in FAT) - return Dirent(INVALID_ENTITY); - } + { + // root doesn't have any stat anyways (except ATTR_VOLUME_ID in FAT) + return Dirent(INVALID_ENTITY); + } debug("stat_sync: %s\n", path.back().c_str()); // extract file we are looking for @@ -198,13 +198,13 @@ namespace fs // find the matching filename in directory for (auto& e : *dirents) - { - if (unlikely(e.name() == filename)) { - // return this directory entry - return e; + if (unlikely(e.name() == filename)) + { + // return this directory entry + return e; + } } - } // entry not found return Dirent(INVALID_ENTITY); } diff --git a/src/fs/mbr.cpp b/src/fs/mbr.cpp index 38af37731d..0e1dabc188 100644 --- a/src/fs/mbr.cpp +++ b/src/fs/mbr.cpp @@ -5,74 +5,74 @@ namespace fs std::string MBR::id_to_name(uint8_t id) { switch (id) - { - case 0x00: - return "Empty"; - case 0x01: - return "DOS 12-bit FAT"; - case 0x02: - return "XENIX root"; - case 0x03: - return "XENIX /usr"; - case 0x04: - return "DOS 3.0+ 16-bit FAT"; - case 0x05: - return "DOS 3.3+ Extended Partition"; - case 0x06: - return "DOS 3.31+ 16-bit FAT (32M+)"; - case 0x07: - return "NTFS or exFAT"; - case 0x08: - return "Commodore DOS logical FAT"; - case 0x0b: - return "WIN95 OSR2 FAT32"; - case 0x0c: - return "WIN95 OSR2 FAT32, LBA-mapped"; - case 0x0d: - return "SILICON SAFE"; - case 0x0e: - return "WIN95: DOS 16-bit FAT, LBA-mapped"; - case 0x0f: - return "WIN95: Extended partition, LBA-mapped"; - case 0x11: - return "Hidden DOS 12-bit FAT"; - case 0x12: - return "Configuration utility partition (Compaq)"; - case 0x14: - return "Hidden DOS 16-bit FAT <32M"; - case 0x16: - return "Hidden DOS 16-bit FAT >= 32M"; - case 0x27: - return "Windows RE hidden partition"; - case 0x3c: - return "PartitionMagic recovery partition"; - case 0x82: - return "Linux swap"; - case 0x83: - return "Linux native partition"; - case 0x84: - return "Hibernation partition"; - case 0x85: - return "Linux extended partition"; - case 0x86: - return "FAT16 fault tolerant volume set"; - case 0x87: - return "NTFS fault tolerant volume set"; - case 0x8e: - return "Linux Logical Volume Manager partition"; - case 0x9f: - return "BSDI (BSD/OS)"; - case 0xa6: - return "OpenBSD"; - case 0xa8: - return "Apple MacOS X (BSD-like filesystem)"; - case 0xa9: - return "NetBSD"; - case 0xaf: - return "MacOS X HFS"; - default: - return "Invalid identifier: " + std::to_string(id); - } + { + case 0x00: + return "Empty"; + case 0x01: + return "DOS 12-bit FAT"; + case 0x02: + return "XENIX root"; + case 0x03: + return "XENIX /usr"; + case 0x04: + return "DOS 3.0+ 16-bit FAT"; + case 0x05: + return "DOS 3.3+ Extended Partition"; + case 0x06: + return "DOS 3.31+ 16-bit FAT (32M+)"; + case 0x07: + return "NTFS or exFAT"; + case 0x08: + return "Commodore DOS logical FAT"; + case 0x0b: + return "WIN95 OSR2 FAT32"; + case 0x0c: + return "WIN95 OSR2 FAT32, LBA-mapped"; + case 0x0d: + return "SILICON SAFE"; + case 0x0e: + return "WIN95: DOS 16-bit FAT, LBA-mapped"; + case 0x0f: + return "WIN95: Extended partition, LBA-mapped"; + case 0x11: + return "Hidden DOS 12-bit FAT"; + case 0x12: + return "Configuration utility partition (Compaq)"; + case 0x14: + return "Hidden DOS 16-bit FAT <32M"; + case 0x16: + return "Hidden DOS 16-bit FAT >= 32M"; + case 0x27: + return "Windows RE hidden partition"; + case 0x3c: + return "PartitionMagic recovery partition"; + case 0x82: + return "Linux swap"; + case 0x83: + return "Linux native partition"; + case 0x84: + return "Hibernation partition"; + case 0x85: + return "Linux extended partition"; + case 0x86: + return "FAT16 fault tolerant volume set"; + case 0x87: + return "NTFS fault tolerant volume set"; + case 0x8e: + return "Linux Logical Volume Manager partition"; + case 0x9f: + return "BSDI (BSD/OS)"; + case 0xa6: + return "OpenBSD"; + case 0xa8: + return "Apple MacOS X (BSD-like filesystem)"; + case 0xa9: + return "NetBSD"; + case 0xaf: + return "MacOS X HFS"; + default: + return "Invalid identifier: " + std::to_string(id); + } } diff --git a/src/fs/memdisk.cpp b/src/fs/memdisk.cpp index 6ae3c5e588..83fed8ddab 100644 --- a/src/fs/memdisk.cpp +++ b/src/fs/memdisk.cpp @@ -31,55 +31,55 @@ extern "C" { namespace fs { -MemDisk::MemDisk() noexcept + MemDisk::MemDisk() noexcept : image_start { &_DISK_START_ }, image_end { &_DISK_END_ } {} -void MemDisk::read(block_t blk, on_read_func callback) { - auto* sector_loc = ((char*) image_start) + blk * block_size(); - // Disallow reading memory past disk image - if (unlikely(sector_loc >= image_end)) - { - callback(buffer_t()); return; - } + void MemDisk::read(block_t blk, on_read_func callback) { + auto* sector_loc = ((char*) image_start) + blk * block_size(); + // Disallow reading memory past disk image + if (unlikely(sector_loc >= image_end)) + { + callback(buffer_t()); return; + } - auto* buffer = new uint8_t[block_size()]; - assert( memcpy(buffer, sector_loc, block_size()) == buffer ); + auto* buffer = new uint8_t[block_size()]; + assert( memcpy(buffer, sector_loc, block_size()) == buffer ); - callback( buffer_t(buffer, std::default_delete()) ); -} - -void MemDisk::read(block_t start, block_t count, on_read_func callback) { - auto* start_loc = ((char*) image_start) + start * block_size(); - auto* end_loc = start_loc + count * block_size(); - // Disallow reading memory past disk image - if (unlikely(end_loc >= image_end)) - { - callback(buffer_t()); return; + callback( buffer_t(buffer, std::default_delete()) ); } + + void MemDisk::read(block_t start, block_t count, on_read_func callback) { + auto* start_loc = ((char*) image_start) + start * block_size(); + auto* end_loc = start_loc + count * block_size(); + // Disallow reading memory past disk image + if (unlikely(end_loc >= image_end)) + { + callback(buffer_t()); return; + } - auto* buffer = new uint8_t[count * block_size()]; - assert( memcpy(buffer, start_loc, count * block_size()) == buffer ); + auto* buffer = new uint8_t[count * block_size()]; + assert( memcpy(buffer, start_loc, count * block_size()) == buffer ); - callback( buffer_t(buffer, std::default_delete()) ); -} + callback( buffer_t(buffer, std::default_delete()) ); + } -MemDisk::buffer_t MemDisk::read_sync(block_t blk) -{ - auto* loc = ((char*) image_start) + blk * block_size(); - // Disallow reading memory past disk image - if (unlikely(loc >= image_end)) - return buffer_t(); + MemDisk::buffer_t MemDisk::read_sync(block_t blk) + { + auto* loc = ((char*) image_start) + blk * block_size(); + // Disallow reading memory past disk image + if (unlikely(loc >= image_end)) + return buffer_t(); - auto* buffer = new uint8_t[block_size()]; - assert( memcpy(buffer, loc, block_size()) == buffer ); + auto* buffer = new uint8_t[block_size()]; + assert( memcpy(buffer, loc, block_size()) == buffer ); - return buffer_t(buffer, std::default_delete()); -} + return buffer_t(buffer, std::default_delete()); + } -MemDisk::block_t MemDisk::size() const noexcept { - return ((char*) image_end - (char*) image_start) / SECTOR_SIZE; -} + MemDisk::block_t MemDisk::size() const noexcept { + return ((char*) image_end - (char*) image_start) / SECTOR_SIZE; + } } //< namespace fs diff --git a/src/fs/path.cpp b/src/fs/path.cpp index e124f137ed..45fe6a7612 100644 --- a/src/fs/path.cpp +++ b/src/fs/path.cpp @@ -22,102 +22,102 @@ namespace fs { - static const char PATH_SEPARATOR = '/'; + static const char PATH_SEPARATOR = '/'; - Path::Path() - : Path("/") - { - // uses current directory - } - Path::Path(const std::string& path) - { - // parse full path - this->state = parse(path); + Path::Path() + : Path("/") + { + // uses current directory + } + Path::Path(const std::string& path) + { + // parse full path + this->state = parse(path); - } // Path::Path(std::string) + } // Path::Path(std::string) - std::string Path::to_string() const - { - // build path - //std::stringstream ss; + std::string Path::to_string() const + { + // build path + //std::stringstream ss; std::string ss; - for (const auto& p : this->stk) - { - ss += PATH_SEPARATOR + p; - } - // append path/ to end - ss += PATH_SEPARATOR; - return ss; - } + for (const auto& p : this->stk) + { + ss += PATH_SEPARATOR + p; + } + // append path/ to end + ss += PATH_SEPARATOR; + return ss; + } - int Path::parse(const std::string& path) - { - if (path.empty()) - { - // do nothing? - return 0; - } + int Path::parse(const std::string& path) + { + if (path.empty()) + { + // do nothing? + return 0; + } - std::string buffer(path.size(), 0); - char lastChar = 0; - int bufi = 0; + std::string buffer(path.size(), 0); + char lastChar = 0; + int bufi = 0; - for (size_t i = 0; i < path.size(); i++) - { - if (path[i] == PATH_SEPARATOR) - { - if (lastChar == PATH_SEPARATOR) - { // invalid path containing // (more than one forw-slash) - return -EINVAL; - } - if (bufi) - { - name_added(std::string(buffer, 0, bufi)); - bufi = 0; - } - else if (i == 0) - { - // if the first character is / separator, - // the path is relative to root, so clear stack - stk.clear(); - } - } - else - { - buffer[bufi] = path[i]; - bufi++; - } - lastChar = path[i]; - } // parse path - if (bufi) - { - name_added(std::string(buffer, 0, bufi)); - } + for (size_t i = 0; i < path.size(); i++) + { + if (path[i] == PATH_SEPARATOR) + { + if (lastChar == PATH_SEPARATOR) + { // invalid path containing // (more than one forw-slash) + return -EINVAL; + } + if (bufi) + { + name_added(std::string(buffer, 0, bufi)); + bufi = 0; + } + else if (i == 0) + { + // if the first character is / separator, + // the path is relative to root, so clear stack + stk.clear(); + } + } + else + { + buffer[bufi] = path[i]; + bufi++; + } + lastChar = path[i]; + } // parse path + if (bufi) + { + name_added(std::string(buffer, 0, bufi)); + } return 0; - } + } - void Path::name_added(const std::string& name) - { - //std::cout << "Path: " << toString() << " --> " << name << std::endl; + void Path::name_added(const std::string& name) + { + //std::cout << "Path: " << toString() << " --> " << name << std::endl; - if (name == ".") - { - // same directory - } - /*else if (name == "..") - { - // if the stack is empty we are at root - if (stk.empty()) - { - // trying to go above root is an error (?) - return; - } + if (name == ".") + { + // same directory + } + /*else if (name == "..") + { + // if the stack is empty we are at root + if (stk.empty()) + { + // trying to go above root is an error (?) + return; + } stk.pop_back(); - }*/ - else - { - // otherwise treat as directory - stk.push_back(name); - } - } + }*/ + else + { + // otherwise treat as directory + stk.push_back(name); + } + } } diff --git a/src/hw/cpu_freq_sampling.cpp b/src/hw/cpu_freq_sampling.cpp index c7953a683b..b6899ccf9b 100644 --- a/src/hw/cpu_freq_sampling.cpp +++ b/src/hw/cpu_freq_sampling.cpp @@ -25,83 +25,83 @@ namespace hw { -/** @note C-style code here, since we're dealing with interrupt handling. - The hardware expects a pure function pointer, and asm can't (easily) - call class member functions. */ + /** @note C-style code here, since we're dealing with interrupt handling. + The hardware expects a pure function pointer, and asm can't (easily) + call class member functions. */ -// This is how you provide storage for a static constexpr variable. -constexpr MHz PIT::frequency_; + // This is how you provide storage for a static constexpr variable. + constexpr MHz PIT::frequency_; -extern "C" double _CPUFreq_ = 0; -extern "C" constexpr uint16_t _cpu_sampling_freq_divider_ = KHz(PIT::frequency()).count() * 10; // Run 1 KHz Lowest: 0xffff + extern "C" double _CPUFreq_ = 0; + extern "C" constexpr uint16_t _cpu_sampling_freq_divider_ = KHz(PIT::frequency()).count() * 10; // Run 1 KHz Lowest: 0xffff -static constexpr int do_samples_ = 20; + static constexpr int do_samples_ = 20; -std::vector _cpu_timestamps; -std::vector _cpu_freq_samples; + std::vector _cpu_timestamps; + std::vector _cpu_freq_samples; -constexpr MHz test_frequency(){ - return MHz(PIT::frequency().count() / _cpu_sampling_freq_divider_); -} + constexpr MHz test_frequency(){ + return MHz(PIT::frequency().count() / _cpu_sampling_freq_divider_); + } -MHz calculate_cpu_frequency(){ + MHz calculate_cpu_frequency(){ - // We expect the cpu_sampling_irq_handler to push in samples; - while (_cpu_timestamps.size() < do_samples_) - OS::halt(); + // We expect the cpu_sampling_irq_handler to push in samples; + while (_cpu_timestamps.size() < do_samples_) + OS::halt(); - debug("_cpu_sampling_freq_divider_ : %i \n",_cpu_sampling_freq_divider_); + debug("_cpu_sampling_freq_divider_ : %i \n",_cpu_sampling_freq_divider_); - #ifdef DEBUG - for (auto t : _cpu_timestamps) debug("%lu \n",(uint32_t)t); - #endif +#ifdef DEBUG + for (auto t : _cpu_timestamps) debug("%lu \n",(uint32_t)t); +#endif - // Subtract the time it takes to measure time :-) - auto t1 = OS::cycles_since_boot(); - OS::cycles_since_boot(); - auto t3 = OS::cycles_since_boot(); - auto overhead = (t3 - t1) * 2; + // Subtract the time it takes to measure time :-) + auto t1 = OS::cycles_since_boot(); + OS::cycles_since_boot(); + auto t3 = OS::cycles_since_boot(); + auto overhead = (t3 - t1) * 2; - debug ("Overhead: %lu \n", (uint32_t)overhead); + debug ("Overhead: %lu \n", (uint32_t)overhead); - for (size_t i = 1; i < _cpu_timestamps.size(); i++){ - // Compute delta in cycles - auto cycles = _cpu_timestamps[i] - _cpu_timestamps[i-1] + overhead; - // Cycles pr. second == Hertz - auto freq = cycles / (1 / test_frequency().count()); - _cpu_freq_samples.push_back(freq); - debug("%lu - %lu = Delta: %lu Current PIT-Freq: %f Hz CPU Freq: %f MHz \n", - (uint32_t)_cpu_timestamps[i], (uint32_t)_cpu_timestamps[i-1], - (uint32_t)cycles, Hz(test_frequency()), freq); - } + for (size_t i = 1; i < _cpu_timestamps.size(); i++){ + // Compute delta in cycles + auto cycles = _cpu_timestamps[i] - _cpu_timestamps[i-1] + overhead; + // Cycles pr. second == Hertz + auto freq = cycles / (1 / test_frequency().count()); + _cpu_freq_samples.push_back(freq); + debug("%lu - %lu = Delta: %lu Current PIT-Freq: %f Hz CPU Freq: %f MHz \n", + (uint32_t)_cpu_timestamps[i], (uint32_t)_cpu_timestamps[i-1], + (uint32_t)cycles, Hz(test_frequency()), freq); + } #ifdef DEBUG - double sum = 0; - for (auto freq : _cpu_freq_samples) - sum += freq; - double mean = sum / _cpu_freq_samples.size(); + double sum = 0; + for (auto freq : _cpu_freq_samples) + sum += freq; + double mean = sum / _cpu_freq_samples.size(); #endif - std::sort(_cpu_freq_samples.begin(), _cpu_freq_samples.end()); - double median = _cpu_freq_samples[_cpu_freq_samples.size() / 2]; + std::sort(_cpu_freq_samples.begin(), _cpu_freq_samples.end()); + double median = _cpu_freq_samples[_cpu_freq_samples.size() / 2]; - debug(" MEAN: %f MEDIAN: %f \n",mean, median); - _CPUFreq_ = median; + debug(" MEAN: %f MEDIAN: %f \n",mean, median); + _CPUFreq_ = median; - return MHz(median); + return MHz(median); -} + } -void cpu_sampling_irq_handler(){ + void cpu_sampling_irq_handler(){ - auto t2 = OS::cycles_since_boot(); + auto t2 = OS::cycles_since_boot(); - if (_cpu_timestamps.size() < do_samples_) - _cpu_timestamps.push_back(t2); + if (_cpu_timestamps.size() < do_samples_) + _cpu_timestamps.push_back(t2); - IRQ_manager::eoi(0); - return; -} + IRQ_manager::eoi(0); + return; + } } //< namespace hw diff --git a/src/hw/ide.cpp b/src/hw/ide.cpp index 8f0245ea63..e73db8c197 100644 --- a/src/hw/ide.cpp +++ b/src/hw/ide.cpp @@ -55,11 +55,11 @@ namespace hw { -IDE::IDE(hw::PCI_Device& pcidev, selector_t sel) : - _pcidev {pcidev}, - _drive {(uint8_t) ((sel == MASTER) ? 0 : 1)}, - _iobase {0U}, - _nb_blk {0U} + IDE::IDE(hw::PCI_Device& pcidev, selector_t sel) : + _pcidev {pcidev}, + _drive {(uint8_t) ((sel == MASTER) ? 0 : 1)}, + _iobase {0U}, + _nb_blk {0U} { INFO("IDE","VENDOR_ID : 0x%x, PRODUCT_ID : 0x%x", _pcidev.vendor_id(), _pcidev.product_id()); INFO("IDE","Attaching to PCI addr 0x%x",_pcidev.pci_addr()); @@ -108,157 +108,157 @@ IDE::IDE(hw::PCI_Device& pcidev, selector_t sel) : INFO("IDE", "Initialization complete"); } -/** - * FIXME: this is a simple trick as we actually can't properly access the private - * members of the class during the IRQ handling... - */ -static IDE::on_read_func _callback = nullptr; // Current callback for asynchronous read -static int _nb_irqs = 0; // Number of IRQs that we expect + /** + * FIXME: this is a simple trick as we actually can't properly access the private + * members of the class during the IRQ handling... + */ + static IDE::on_read_func _callback = nullptr; // Current callback for asynchronous read + static int _nb_irqs = 0; // Number of IRQs that we expect + + void IDE::read(block_t blk, on_read_func callback) { + if (blk >= _nb_blk) { + // avoid reading past the disk boundaries + callback(buffer_t()); + return; + } -void IDE::read(block_t blk, on_read_func callback) { - if (blk >= _nb_blk) { - // avoid reading past the disk boundaries - callback(buffer_t()); + callback(read_sync(blk)); return; + + set_irq_mode(true); + set_drive(0xE0 | (_drive << 4) | ((blk >> 24) & 0x0F)); + set_nbsectors(1); + set_blocknum(blk); + set_command(IDE_CMD_READ); + + _callback = callback; + _nb_irqs = 1; } - callback(read_sync(blk)); - return; + void IDE::read(block_t blk, block_t count, on_read_func callback) + { + if (blk + count >= _nb_blk) { + // avoid reading past the disk boundaries + callback(buffer_t()); + return; + } - set_irq_mode(true); - set_drive(0xE0 | (_drive << 4) | ((blk >> 24) & 0x0F)); - set_nbsectors(1); - set_blocknum(blk); - set_command(IDE_CMD_READ); - - _callback = callback; - _nb_irqs = 1; -} - -void IDE::read(block_t blk, block_t count, on_read_func callback) -{ - if (blk + count >= _nb_blk) { - // avoid reading past the disk boundaries - callback(buffer_t()); - return; + set_irq_mode(true); + set_drive(0xE0 | (_drive << 4) | ((blk >> 24) & 0x0F)); + set_nbsectors(count); + set_blocknum(blk); + set_command(IDE_CMD_READ); + + _callback = callback; + _nb_irqs = count; } - - set_irq_mode(true); - set_drive(0xE0 | (_drive << 4) | ((blk >> 24) & 0x0F)); - set_nbsectors(count); - set_blocknum(blk); - set_command(IDE_CMD_READ); - - _callback = callback; - _nb_irqs = count; -} -IDE::buffer_t IDE::read_sync(block_t blk) -{ - if (blk >= _nb_blk) { - // avoid reading past the disk boundaries - return buffer_t(); - } + IDE::buffer_t IDE::read_sync(block_t blk) + { + if (blk >= _nb_blk) { + // avoid reading past the disk boundaries + return buffer_t(); + } - set_irq_mode(false); - set_drive(0xE0 | (_drive << 4) | ((blk >> 24) & 0x0F)); - set_nbsectors(1); - set_blocknum(blk); - set_command(IDE_CMD_READ); + set_irq_mode(false); + set_drive(0xE0 | (_drive << 4) | ((blk >> 24) & 0x0F)); + set_nbsectors(1); + set_blocknum(blk); + set_command(IDE_CMD_READ); - auto* buffer = new uint8_t[block_size()]; + auto* buffer = new uint8_t[block_size()]; - wait_status_flags(IDE_DRDY, false); + wait_status_flags(IDE_DRDY, false); - uint16_t* wptr = (uint16_t*) buffer; - uint16_t* wend = (uint16_t*)&buffer[block_size()]; - while (wptr < wend) - *(wptr++) = inw(IDE_DATA); + uint16_t* wptr = (uint16_t*) buffer; + uint16_t* wend = (uint16_t*)&buffer[block_size()]; + while (wptr < wend) + *(wptr++) = inw(IDE_DATA); - // return a shared_ptr wrapper for the buffer - return buffer_t(buffer, std::default_delete()); -} + // return a shared_ptr wrapper for the buffer + return buffer_t(buffer, std::default_delete()); + } -void IDE::wait_status_busy() const noexcept { - uint8_t ret; - while (((ret = inb(IDE_STATUS)) & IDE_BUSY) == IDE_BUSY); -} + void IDE::wait_status_busy() const noexcept { + uint8_t ret; + while (((ret = inb(IDE_STATUS)) & IDE_BUSY) == IDE_BUSY); + } -void IDE::wait_status_flags(const int flags, const bool set) const noexcept { - wait_status_busy(); + void IDE::wait_status_flags(const int flags, const bool set) const noexcept { + wait_status_busy(); - auto ret = inb(IDE_STATUS); + auto ret = inb(IDE_STATUS); - for (int i {IDE_TIMEOUT}; i; --i) { - if (set) { - if ((ret & flags) == flags) - break; - } else { - if ((ret & flags) not_eq flags) - break; - } + for (int i {IDE_TIMEOUT}; i; --i) { + if (set) { + if ((ret & flags) == flags) + break; + } else { + if ((ret & flags) not_eq flags) + break; + } - ret = inb(IDE_STATUS); + ret = inb(IDE_STATUS); + } } -} -void IDE::set_drive(const uint8_t drive) const noexcept { - wait_status_flags(IDE_DRQ, true); - outb(IDE_DRV, drive); -} - -void IDE::set_nbsectors(const uint8_t cnt) const noexcept { - wait_status_flags(IDE_DRQ, true); - outb(IDE_SECCNT, cnt); -} + void IDE::set_drive(const uint8_t drive) const noexcept { + wait_status_flags(IDE_DRQ, true); + outb(IDE_DRV, drive); + } -void IDE::set_blocknum(block_t blk) const noexcept { - wait_status_flags(IDE_DRQ, true); - outb(IDE_BLKLO, blk & 0xFF); + void IDE::set_nbsectors(const uint8_t cnt) const noexcept { + wait_status_flags(IDE_DRQ, true); + outb(IDE_SECCNT, cnt); + } - wait_status_flags(IDE_DRQ, true); - outb(IDE_BLKMID, (blk & 0xFF00) >> 8); + void IDE::set_blocknum(block_t blk) const noexcept { + wait_status_flags(IDE_DRQ, true); + outb(IDE_BLKLO, blk & 0xFF); - wait_status_flags(IDE_DRQ, true); - outb(IDE_BLKHI, (blk & 0xFF0000) >> 16); -} + wait_status_flags(IDE_DRQ, true); + outb(IDE_BLKMID, (blk & 0xFF00) >> 8); -void IDE::set_command(const uint16_t command) const noexcept { - wait_status_flags(IDE_DRDY, false); - outb(IDE_CMD, command); -} + wait_status_flags(IDE_DRQ, true); + outb(IDE_BLKHI, (blk & 0xFF0000) >> 16); + } -void IDE::set_irq_mode(const bool on) const noexcept { - wait_status_flags(IDE_DRDY, false); - outb(IDE_CTRL_IRQ, on ? 0 : 1); -} + void IDE::set_command(const uint16_t command) const noexcept { + wait_status_flags(IDE_DRDY, false); + outb(IDE_CMD, command); + } -void IDE::irq_handler() { - if (!_nb_irqs || _callback == nullptr) { - set_irq_mode(false); - IRQ_manager::eoi(IDE_IRQN); - return; + void IDE::set_irq_mode(const bool on) const noexcept { + wait_status_flags(IDE_DRDY, false); + outb(IDE_CTRL_IRQ, on ? 0 : 1); } - auto* buffer = new uint8_t[block_size()]; + void IDE::irq_handler() { + if (!_nb_irqs || _callback == nullptr) { + set_irq_mode(false); + IRQ_manager::eoi(IDE_IRQN); + return; + } - wait_status_flags(IDE_DRDY, false); + auto* buffer = new uint8_t[block_size()]; - uint16_t* wptr = (uint16_t*) buffer; + wait_status_flags(IDE_DRDY, false); - for (block_t i = 0; i < block_size() / sizeof (uint16_t); ++i) - wptr[i] = inw(IDE_DATA); + uint16_t* wptr = (uint16_t*) buffer; - _callback(buffer_t(buffer, std::default_delete())); - _nb_irqs--; + for (block_t i = 0; i < block_size() / sizeof (uint16_t); ++i) + wptr[i] = inw(IDE_DATA); - IRQ_manager::eoi(IDE_IRQN); -} + _callback(buffer_t(buffer, std::default_delete())); + _nb_irqs--; -void IDE::enable_irq_handler() { - auto del(delegate::from(this)); - IRQ_manager::enable_irq(IDE_IRQN); - IRQ_manager::subscribe(IDE_IRQN, del); -} + IRQ_manager::eoi(IDE_IRQN); + } + + void IDE::enable_irq_handler() { + auto del(delegate::from(this)); + IRQ_manager::enable_irq(IDE_IRQN); + IRQ_manager::subscribe(IDE_IRQN, del); + } } //< namespace hw diff --git a/src/hw/nic.cpp b/src/hw/nic.cpp index e6c40ccf1a..74d9df8dbd 100644 --- a/src/hw/nic.cpp +++ b/src/hw/nic.cpp @@ -19,46 +19,46 @@ #include /* -namespace hw { + namespace hw { */ /* -template <> const char* Nic::name(){ + template <> const char* Nic::name(){ //return "Fantastic VirtioNic No.1"; return driver.name(); -} + } */ /* -template <> Nic::Nic(PCI_Device* _dev) + template <> Nic::Nic(PCI_Device* _dev) : pcidev(_dev) //Device(this) -{ + { printf("\n Nic at PCI addr 0x%x scanning for resources\n",_dev->pci_addr()); _dev->probe_resources(); -} + } */ /* -template <> const char* Nic::name(){ + template <> const char* Nic::name(){ return "Specialized E1000 No.1"; -} + } -template <> Nic::Nic(PCI_Device* _dev) + template <> Nic::Nic(PCI_Device* _dev) : pcidev(_dev) //Device(this) -{ + { printf("\n Nic at PCI addr 0x%x scanning for resources\n",_dev->pci_addr()); _dev->probe_resources(); -} + } */ /* -} //< namespace hw + } //< namespace hw */ diff --git a/src/hw/pci_device.cpp b/src/hw/pci_device.cpp index 749363fcff..2a1174856c 100644 --- a/src/hw/pci_device.cpp +++ b/src/hw/pci_device.cpp @@ -24,129 +24,129 @@ namespace hw { -constexpr int NUM_CLASSCODES {19}; - -static const char* classcodes[NUM_CLASSCODES] { - "Too-Old-To-Tell", // 0 - "Mass Storage Controller", // 1 - "Network Controller", // 2 - "Display Controller", // 3 - "Multimedia Controller", // 4 - "Memory Controller", // 5 - "Bridge", // 6 - "Simple communications controllers", - "Base system peripherals", // 8 - "Inupt device", // 9 - "Docking Station", - "Processor", - "Serial Bus Controller", - "Wireless Controller", - "Intelligent I/O Controller", - "Satellite Communication Controller", // 15 - "Encryption/Decryption Controller", // 16 - "Data Acquisition and Signal Processing Controller", // 17 - NULL -}; - -constexpr int SS_BR {3}; - -static const char* bridge_subclasses[SS_BR] { - "Host", - "ISA", - "Other" -}; - -constexpr int SS_NIC {2}; - -static const char* nic_subclasses[SS_NIC] { - "Ethernet", - "Other" -}; - -struct _pci_vendor { - uint16_t id; - const char* name; -} _pci_vendorlist[] { - {0x8086,"Intel Corp."}, - {0x1013,"Cirrus Logic"}, - {0x10EC,"Realtek Semi.Corp."}, - {0x1AF4,"Virtio (Rusty Russell)"}, // Virtio creator - {0x1022,"AMD"}, - {0x0000,NULL} -}; - -static unsigned long pci_size(const unsigned long base, const unsigned long mask) noexcept { - // Find the significant bits - unsigned long size = mask & base; - - // Get the lowest of them to find the decode size - size &= ~(size - 1); - - return size; -} + constexpr int NUM_CLASSCODES {19}; + + static const char* classcodes[NUM_CLASSCODES] { + "Too-Old-To-Tell", // 0 + "Mass Storage Controller", // 1 + "Network Controller", // 2 + "Display Controller", // 3 + "Multimedia Controller", // 4 + "Memory Controller", // 5 + "Bridge", // 6 + "Simple communications controllers", + "Base system peripherals", // 8 + "Inupt device", // 9 + "Docking Station", + "Processor", + "Serial Bus Controller", + "Wireless Controller", + "Intelligent I/O Controller", + "Satellite Communication Controller", // 15 + "Encryption/Decryption Controller", // 16 + "Data Acquisition and Signal Processing Controller", // 17 + NULL + }; + + constexpr int SS_BR {3}; + + static const char* bridge_subclasses[SS_BR] { + "Host", + "ISA", + "Other" + }; + + constexpr int SS_NIC {2}; + + static const char* nic_subclasses[SS_NIC] { + "Ethernet", + "Other" + }; + + struct _pci_vendor { + uint16_t id; + const char* name; + } _pci_vendorlist[] { + {0x8086,"Intel Corp."}, + {0x1013,"Cirrus Logic"}, + {0x10EC,"Realtek Semi.Corp."}, + {0x1AF4,"Virtio (Rusty Russell)"}, // Virtio creator + {0x1022,"AMD"}, + {0x0000,NULL} + }; + + static unsigned long pci_size(const unsigned long base, const unsigned long mask) noexcept { + // Find the significant bits + unsigned long size = mask & base; + + // Get the lowest of them to find the decode size + size &= ~(size - 1); + + return size; + } -uint32_t PCI_Device::iobase() const noexcept { - assert(res_io_ != nullptr); - return res_io_->start_; -}; + uint32_t PCI_Device::iobase() const noexcept { + assert(res_io_ != nullptr); + return res_io_->start_; + }; -void PCI_Device::probe_resources() noexcept { - //Find resources on this PCI device (scan the BAR's) - uint32_t value {PCI::WTF}; + void PCI_Device::probe_resources() noexcept { + //Find resources on this PCI device (scan the BAR's) + uint32_t value {PCI::WTF}; - uint32_t reg {0}; - uint32_t len {0}; + uint32_t reg {0}; + uint32_t len {0}; - for(int bar {0}; bar < 6; ++bar) { - //Read the current BAR register - reg = PCI::CONFIG_BASE_ADDR_0 + (bar << 2); - value = read_dword(reg); + for(int bar {0}; bar < 6; ++bar) { + //Read the current BAR register + reg = PCI::CONFIG_BASE_ADDR_0 + (bar << 2); + value = read_dword(reg); - if (!value) continue; + if (!value) continue; - //Write all 1's to the register, to get the length value (osdev) - write_dword(reg, 0xFFFFFFFF); - len = read_dword(reg); + //Write all 1's to the register, to get the length value (osdev) + write_dword(reg, 0xFFFFFFFF); + len = read_dword(reg); - //Put the value back - write_dword(reg, value); + //Put the value back + write_dword(reg, value); - uint32_t unmasked_val {0}; - uint32_t pci__size {0}; + uint32_t unmasked_val {0}; + uint32_t pci__size {0}; - if (value & 1) { // Resource type IO + if (value & 1) { // Resource type IO - unmasked_val = value & PCI::BASE_ADDRESS_IO_MASK; - pci__size = pci_size(len, PCI::BASE_ADDRESS_IO_MASK & 0xFFFF); + unmasked_val = value & PCI::BASE_ADDRESS_IO_MASK; + pci__size = pci_size(len, PCI::BASE_ADDRESS_IO_MASK & 0xFFFF); - // Add it to resource list - add_resource(new Resource(unmasked_val, pci__size), res_io_); - assert(res_io_ != nullptr); + // Add it to resource list + add_resource(new Resource(unmasked_val, pci__size), res_io_); + assert(res_io_ != nullptr); - } else { //Resource type Mem + } else { //Resource type Mem - unmasked_val = value & PCI::BASE_ADDRESS_MEM_MASK; - pci__size = pci_size(len, PCI::BASE_ADDRESS_MEM_MASK); + unmasked_val = value & PCI::BASE_ADDRESS_MEM_MASK; + pci__size = pci_size(len, PCI::BASE_ADDRESS_MEM_MASK); - //Add it to resource list - add_resource(new Resource(unmasked_val, pci__size), res_mem_); - assert(res_mem_ != nullptr); - } + //Add it to resource list + add_resource(new Resource(unmasked_val, pci__size), res_mem_); + assert(res_mem_ != nullptr); + } + INFO2(""); + INFO2("[ Resource @ BAR %i ]", bar); + INFO2(" Address: 0x%x Size: 0x%x", unmasked_val, pci__size); + INFO2(" Type: %s", value & 1 ? "IO Resource" : "Memory Resource"); + } + INFO2(""); - INFO2("[ Resource @ BAR %i ]", bar); - INFO2(" Address: 0x%x Size: 0x%x", unmasked_val, pci__size); - INFO2(" Type: %s", value & 1 ? "IO Resource" : "Memory Resource"); } - - INFO2(""); -} -PCI_Device::PCI_Device(const uint16_t pci_addr, const uint32_t device_id) noexcept: + PCI_Device::PCI_Device(const uint16_t pci_addr, const uint32_t device_id) noexcept: pci_addr_{pci_addr}, device_id_{device_id} -// Device(Device::PCI) -// Why not inherit Device? Well, I think "PCI devices" are too general to be useful by itself, -// and the "Device" class is Public ABI, so it should only know about stuff that's relevant for the user. + // Device(Device::PCI) + // Why not inherit Device? Well, I think "PCI devices" are too general to be useful by itself, + // and the "Device" class is Public ABI, so it should only know about stuff that's relevant for the user. { //We have device, so probe for details devtype_.reg = read_dword(pci_addr, PCI::CONFIG_CLASS_REV); @@ -159,14 +159,14 @@ PCI_Device::PCI_Device(const uint16_t pci_addr, const uint32_t device_id) noexce switch (devtype_.classcode) { case PCI::BRIDGE: INFO2("+--+ %s %s (0x%x)", - bridge_subclasses[devtype_.subclass < SS_BR ? devtype_.subclass : SS_BR-1], - classcodes[devtype_.classcode],devtype_.subclass); + bridge_subclasses[devtype_.subclass < SS_BR ? devtype_.subclass : SS_BR-1], + classcodes[devtype_.classcode],devtype_.subclass); break; case PCI::NIC: INFO2("+--+ %s %s (0x%x)", - nic_subclasses[devtype_.subclass < SS_NIC ? devtype_.subclass : SS_NIC-1], - classcodes[devtype_.classcode],devtype_.subclass); + nic_subclasses[devtype_.subclass < SS_NIC ? devtype_.subclass : SS_NIC-1], + classcodes[devtype_.classcode],devtype_.subclass); break; default: @@ -179,39 +179,39 @@ PCI_Device::PCI_Device(const uint16_t pci_addr, const uint32_t device_id) noexce } -void PCI_Device::write_dword(const uint8_t reg, const uint32_t value) noexcept { - PCI::msg req; + void PCI_Device::write_dword(const uint8_t reg, const uint32_t value) noexcept { + PCI::msg req; - req.data = 0x80000000; - req.addr = pci_addr_; - req.reg = reg; + req.data = 0x80000000; + req.addr = pci_addr_; + req.reg = reg; - outpd(PCI::CONFIG_ADDR, static_cast(0x80000000) | req.data); - outpd(PCI::CONFIG_DATA, value); -} + outpd(PCI::CONFIG_ADDR, static_cast(0x80000000) | req.data); + outpd(PCI::CONFIG_DATA, value); + } -uint32_t PCI_Device::read_dword(const uint8_t reg) noexcept { - PCI::msg req; + uint32_t PCI_Device::read_dword(const uint8_t reg) noexcept { + PCI::msg req; - req.data = 0x80000000; - req.addr = pci_addr_; - req.reg = reg; + req.data = 0x80000000; + req.addr = pci_addr_; + req.reg = reg; - outpd(PCI::CONFIG_ADDR, static_cast(0x80000000) | req.data); + outpd(PCI::CONFIG_ADDR, static_cast(0x80000000) | req.data); - return inpd(PCI::CONFIG_DATA); -} + return inpd(PCI::CONFIG_DATA); + } -uint32_t PCI_Device::read_dword(const uint16_t pci_addr, const uint8_t reg) noexcept { - PCI::msg req; + uint32_t PCI_Device::read_dword(const uint16_t pci_addr, const uint8_t reg) noexcept { + PCI::msg req; - req.data = 0x80000000; - req.addr = pci_addr; - req.reg = reg; + req.data = 0x80000000; + req.addr = pci_addr; + req.reg = reg; - outpd(PCI::CONFIG_ADDR, static_cast(0x80000000) | req.data); + outpd(PCI::CONFIG_ADDR, static_cast(0x80000000) | req.data); - return inpd(PCI::CONFIG_DATA); -} + return inpd(PCI::CONFIG_DATA); + } } //< namespace hw diff --git a/src/hw/pit.cpp b/src/hw/pit.cpp index cbb26c65f1..503eb42538 100644 --- a/src/hw/pit.cpp +++ b/src/hw/pit.cpp @@ -25,262 +25,262 @@ namespace hw { -// Bit 0-3: Mode 0 - "Interrupt on terminal count" -// Bit 4-5: Both set, access mode "Lobyte / Hibyte" -const uint8_t PIT_mode_register = 0x43; -const uint8_t PIT_chan0 = 0x40; + // Bit 0-3: Mode 0 - "Interrupt on terminal count" + // Bit 4-5: Both set, access mode "Lobyte / Hibyte" + const uint8_t PIT_mode_register = 0x43; + const uint8_t PIT_chan0 = 0x40; -// PIT state -PIT::Mode PIT::current_mode_ = NONE; -PIT::Mode PIT::temp_mode_ = NONE; -uint16_t PIT::current_freq_divider_ = 0; -uint16_t PIT::temp_freq_divider_ = 0; + // PIT state + PIT::Mode PIT::current_mode_ = NONE; + PIT::Mode PIT::temp_mode_ = NONE; + uint16_t PIT::current_freq_divider_ = 0; + uint16_t PIT::temp_freq_divider_ = 0; -uint64_t PIT::IRQ_counter_ = 0; + uint64_t PIT::IRQ_counter_ = 0; -// Used for cpu frequency sampling -extern "C" double _CPUFreq_; -extern "C" uint16_t _cpu_sampling_freq_divider_; -extern "C" void irq_timer_entry(); + // Used for cpu frequency sampling + extern "C" double _CPUFreq_; + extern "C" uint16_t _cpu_sampling_freq_divider_; + extern "C" void irq_timer_entry(); -// Time keeping -uint64_t PIT::millisec_counter = 0; + // Time keeping + uint64_t PIT::millisec_counter = 0; -// The default recurring timer condition -std::function PIT::forever = []{ return true; }; + // The default recurring timer condition + std::function PIT::forever = []{ return true; }; -// Timer ID's -uint32_t PIT::Timer::timers_count_ = 0; + // Timer ID's + uint32_t PIT::Timer::timers_count_ = 0; -using namespace std::chrono; + using namespace std::chrono; -PIT::Timer::Timer(Type t, timeout_handler handler, std::chrono::milliseconds ms, repeat_condition cond) - : type_{t}, id_{++timers_count_}, handler_{handler}, interval_{ms}, cond_{cond} {}; + PIT::Timer::Timer(Type t, timeout_handler handler, std::chrono::milliseconds ms, repeat_condition cond) + : type_{t}, id_{++timers_count_}, handler_{handler}, interval_{ms}, cond_{cond} {}; -void PIT::disable_regular_interrupts() -{ - oneshot(1); -} + void PIT::disable_regular_interrupts() + { + oneshot(1); + } -PIT::~PIT(){} + PIT::~PIT(){} -PIT::PIT(){ - debug(" Instantiating. \n"); + PIT::PIT(){ + debug(" Instantiating. \n"); - auto handler(IRQ_manager::irq_delegate::from(this)); + auto handler(IRQ_manager::irq_delegate::from(this)); - IRQ_manager::subscribe(0, handler); -} + IRQ_manager::subscribe(0, handler); + } -void PIT::estimateCPUFrequency(){ + void PIT::estimateCPUFrequency(){ - debug(" Saving state: curr_freq_div %i \n",current_freq_divider_); - // Save PIT-state - temp_mode_ = current_mode_; - temp_freq_divider_ = current_freq_divider_; + debug(" Saving state: curr_freq_div %i \n",current_freq_divider_); + // Save PIT-state + temp_mode_ = current_mode_; + temp_freq_divider_ = current_freq_divider_; - auto prev_irq_handler = IRQ_manager::get_handler(32); + auto prev_irq_handler = IRQ_manager::get_handler(32); - debug(" Sampling\n"); - IRQ_manager::set_handler(32, cpu_sampling_irq_entry); + debug(" Sampling\n"); + IRQ_manager::set_handler(32, cpu_sampling_irq_entry); - // GO! - set_mode(RATE_GEN); - set_freq_divider(_cpu_sampling_freq_divider_); + // GO! + set_mode(RATE_GEN); + set_freq_divider(_cpu_sampling_freq_divider_); - // BLOCKING call to external measurment. - calculate_cpu_frequency(); + // BLOCKING call to external measurment. + calculate_cpu_frequency(); - debug(" Done. Result: %f \n", _CPUFreq_); + debug(" Done. Result: %f \n", _CPUFreq_); - set_mode(temp_mode_); - set_freq_divider(temp_freq_divider_); + set_mode(temp_mode_); + set_freq_divider(temp_freq_divider_); - IRQ_manager::set_handler(32, prev_irq_handler); -} + IRQ_manager::set_handler(32, prev_irq_handler); + } -MHz PIT::CPUFrequency(){ - if (! _CPUFreq_) - estimateCPUFrequency(); + MHz PIT::CPUFrequency(){ + if (! _CPUFreq_) + estimateCPUFrequency(); - return MHz(_CPUFreq_); -} + return MHz(_CPUFreq_); + } -void PIT::start_timer(Timer t, std::chrono::milliseconds in_msecs){ - if (in_msecs < 1ms) panic("Can't wait less than 1 ms. "); + void PIT::start_timer(Timer t, std::chrono::milliseconds in_msecs){ + if (in_msecs < 1ms) panic("Can't wait less than 1 ms. "); - if (current_mode_ != RATE_GEN) - set_mode(RATE_GEN); + if (current_mode_ != RATE_GEN) + set_mode(RATE_GEN); - if (current_freq_divider_ != millisec_interval) - set_freq_divider(millisec_interval); + if (current_freq_divider_ != millisec_interval) + set_freq_divider(millisec_interval); - auto cycles_pr_millisec = KHz(CPUFrequency()); - debug(" CPU KHz: %f Cycles to wait: %f \n",cycles_pr_millisec.count(), cycles_pr_millisec.count() * in_msecs); + auto cycles_pr_millisec = KHz(CPUFrequency()); + debug(" CPU KHz: %f Cycles to wait: %f \n",cycles_pr_millisec.count(), cycles_pr_millisec.count() * in_msecs); - auto ticks = in_msecs / KHz(current_frequency()).count(); - debug(" PIT KHz: %f * %i = %f ms. \n", - KHz(current_frequency()).count(), (uint32_t)ticks.count(), ((uint32_t)ticks.count() * KHz(current_frequency()).count())); + auto ticks = in_msecs / KHz(current_frequency()).count(); + debug(" PIT KHz: %f * %i = %f ms. \n", + KHz(current_frequency()).count(), (uint32_t)ticks.count(), ((uint32_t)ticks.count() * KHz(current_frequency()).count())); - t.setStart(OS::cycles_since_boot()); - t.setEnd(t.start() + uint64_t(cycles_pr_millisec.count() * in_msecs.count())); + t.setStart(OS::cycles_since_boot()); + t.setEnd(t.start() + uint64_t(cycles_pr_millisec.count() * in_msecs.count())); - auto key = millisec_counter + ticks.count(); + auto key = millisec_counter + ticks.count(); - // We could emplace, but the timer exists allready, and might be a reused one - timers_.insert(std::make_pair(key, t)); + // We could emplace, but the timer exists allready, and might be a reused one + timers_.insert(std::make_pair(key, t)); - debug(" Key: %i id: %i, t.cond()(): %s There are %i timers. \n", - (uint32_t)key, t.id(), t.cond()() ? "true" : "false", timers_.size()); + debug(" Key: %i id: %i, t.cond()(): %s There are %i timers. \n", + (uint32_t)key, t.id(), t.cond()() ? "true" : "false", timers_.size()); -} + } -void PIT::onRepeatedTimeout(std::chrono::milliseconds ms, timeout_handler handler, repeat_condition cond){ - debug(" setting a %i ms. repeating timer \n", (uint32_t)ms.count()); + void PIT::onRepeatedTimeout(std::chrono::milliseconds ms, timeout_handler handler, repeat_condition cond){ + debug(" setting a %i ms. repeating timer \n", (uint32_t)ms.count()); - Timer t(Timer::REPEAT_WHILE, handler, ms, cond); - start_timer(t, ms); -}; + Timer t(Timer::REPEAT_WHILE, handler, ms, cond); + start_timer(t, ms); + }; -void PIT::onTimeout(std::chrono::milliseconds msec, timeout_handler handler){ - Timer t(Timer::ONE_SHOT, handler, msec); + void PIT::onTimeout(std::chrono::milliseconds msec, timeout_handler handler){ + Timer t(Timer::ONE_SHOT, handler, msec); - debug(" setting a %i ms. one-shot timer. Id: %i \n", - (uint32_t)msec.count(), t.id()); + debug(" setting a %i ms. one-shot timer. Id: %i \n", + (uint32_t)msec.count(), t.id()); - start_timer(t, msec); + start_timer(t, msec); -}; + }; -uint8_t PIT::read_back(uint8_t){ - const uint8_t READ_BACK_CMD = 0xc2; + uint8_t PIT::read_back(uint8_t){ + const uint8_t READ_BACK_CMD = 0xc2; - hw::outb(PIT_mode_register, READ_BACK_CMD ); + hw::outb(PIT_mode_register, READ_BACK_CMD ); - auto res = hw::inb(PIT_chan0); + auto res = hw::inb(PIT_chan0); - debug("STATUS: %#x \n", res); + debug("STATUS: %#x \n", res); - return res; + return res; -} + } -void PIT::irq_handler(){ - // All IRQ-handlers has to send EOI - IRQ_manager::eoi(0); + void PIT::irq_handler(){ + // All IRQ-handlers has to send EOI + IRQ_manager::eoi(0); - IRQ_counter_ ++; + IRQ_counter_ ++; - if (current_freq_divider_ == millisec_interval) - millisec_counter++; + if (current_freq_divider_ == millisec_interval) + millisec_counter++; - #ifdef DEBUG - if (millisec_counter % 100 == 0) - OS::rsprint("."); - #endif +#ifdef DEBUG + if (millisec_counter % 100 == 0) + OS::rsprint("."); +#endif - // Iterate over expired timers (we break on the first non-expired) - for (auto it = timers_.begin(); it != timers_.end(); it++) { + // Iterate over expired timers (we break on the first non-expired) + for (auto it = timers_.begin(); it != timers_.end(); it++) { - // Map-keys are sorted. If this timer isn't expired, neither are the rest - if (it->first > millisec_counter) - break; + // Map-keys are sorted. If this timer isn't expired, neither are the rest + if (it->first > millisec_counter) + break; - debug2 ("\n**** Timer type %i, id: %i expired. Running handler **** \n", - it->second.type(), it->second.id()); + debug2 ("\n**** Timer type %i, id: %i expired. Running handler **** \n", + it->second.type(), it->second.id()); - // Execute the handler - it->second.handler()(); + // Execute the handler + it->second.handler()(); - // Re-queue repeating timers - if (it->second.type() == Timer::REPEAT) { - debug2 (" REPEAT: Requeuing the timer \n"); - start_timer(it->second, it->second.interval()); + // Re-queue repeating timers + if (it->second.type() == Timer::REPEAT) { + debug2 (" REPEAT: Requeuing the timer \n"); + start_timer(it->second, it->second.interval()); - }else if (it->second.type() == Timer::REPEAT_WHILE and it->second.cond()()) { - debug2 (" REPEAT_WHILE: Requeuing the timer COND \n"); - start_timer(it->second, it->second.interval()); - } + }else if (it->second.type() == Timer::REPEAT_WHILE and it->second.cond()()) { + debug2 (" REPEAT_WHILE: Requeuing the timer COND \n"); + start_timer(it->second, it->second.interval()); + } - debug2 ("Timer done. Erasing. \n"); + debug2 ("Timer done. Erasing. \n"); - // Escape iterator death - auto remove = it; - it++; + // Escape iterator death + auto remove = it; + it++; - // Erase the timer - timers_.erase(remove); + // Erase the timer + timers_.erase(remove); - // If this was the last timer, we can turn off the clock - if (timers_.empty()){ - // Disable the PIT - oneshot(1); + // If this was the last timer, we can turn off the clock + if (timers_.empty()){ + // Disable the PIT + oneshot(1); - debug2 ("Timers done. PIT disabled for now. \n"); - // Escape iterator death - break; - } + debug2 ("Timers done. PIT disabled for now. \n"); + // Escape iterator death + break; + } - debug2 ("Timers left: %i \n", timers_.size()); + debug2 ("Timers left: %i \n", timers_.size()); - #ifdef DEBUG2 - for (auto t : timers_) - debug2("Key: %i , id: %i, Type: %i", (uint32_t)t.first, t.second.id(), t.second.type()); - #endif +#ifdef DEBUG2 + for (auto t : timers_) + debug2("Key: %i , id: %i, Type: %i", (uint32_t)t.first, t.second.id(), t.second.type()); +#endif - debug2("\n---------------------------\n\n"); - } + debug2("\n---------------------------\n\n"); + } -} + } -void PIT::init(){ - debug(" Initializing @ frequency: %16.16f MHz. Assigning myself to all timer interrupts.\n ", frequency()); - PIT::disable_regular_interrupts(); - IRQ_manager::enable_irq(0); -} + void PIT::init(){ + debug(" Initializing @ frequency: %16.16f MHz. Assigning myself to all timer interrupts.\n ", frequency()); + PIT::disable_regular_interrupts(); + IRQ_manager::enable_irq(0); + } -void PIT::set_mode(Mode mode){ - // Channel is the last two bits in the PIT mode register - // ...we always use channel 0 - auto channel = 0x00; - uint8_t config = mode | LO_HI | channel; - debug(" Setting mode %#x, config: %#x \n", mode, config); + void PIT::set_mode(Mode mode){ + // Channel is the last two bits in the PIT mode register + // ...we always use channel 0 + auto channel = 0x00; + uint8_t config = mode | LO_HI | channel; + debug(" Setting mode %#x, config: %#x \n", mode, config); - hw::outb(PIT_mode_register, config); - current_mode_ = mode; + hw::outb(PIT_mode_register, config); + current_mode_ = mode; -} + } -void PIT::set_freq_divider(uint16_t freq_divider){ - union{ - uint16_t whole; - uint8_t part[2]; - }data{freq_divider}; + void PIT::set_freq_divider(uint16_t freq_divider){ + union{ + uint16_t whole; + uint8_t part[2]; + }data{freq_divider}; - // Send frequency hi/lo to PIT - hw::outb(PIT_chan0, data.part[0]); - hw::outb(PIT_chan0, data.part[1]); + // Send frequency hi/lo to PIT + hw::outb(PIT_chan0, data.part[0]); + hw::outb(PIT_chan0, data.part[1]); - current_freq_divider_ = freq_divider; + current_freq_divider_ = freq_divider; -} + } -void PIT::oneshot(uint16_t t){ + void PIT::oneshot(uint16_t t){ - // Enable 1-shot mode - set_mode(ONE_SHOT); + // Enable 1-shot mode + set_mode(ONE_SHOT); - // Set a frequency for shot - set_freq_divider(t); -} + // Set a frequency for shot + set_freq_divider(t); + } } //< namespace hw diff --git a/src/include/hw/cpu_freq_sampling.hpp b/src/include/hw/cpu_freq_sampling.hpp index 733dde58df..44b902a251 100644 --- a/src/include/hw/cpu_freq_sampling.hpp +++ b/src/include/hw/cpu_freq_sampling.hpp @@ -21,17 +21,17 @@ namespace hw { -/** Proper IRQ-handler for CPU frequency sampling - implemented in interrupts.s - @Note - PIT::estimateCPUFrequency() will register- /de-register this as needed */ -extern "C" void cpu_sampling_irq_handler(); + /** Proper IRQ-handler for CPU frequency sampling - implemented in interrupts.s + @Note + PIT::estimateCPUFrequency() will register- /de-register this as needed */ + extern "C" void cpu_sampling_irq_handler(); -/** CPU frequency sampling. Implemented in hw/cpu_freq_sampling.cpp - @Note this will be automatically called by the oirq-handler */ -extern "C" void cpu_sampling_irq_entry(); + /** CPU frequency sampling. Implemented in hw/cpu_freq_sampling.cpp + @Note this will be automatically called by the oirq-handler */ + extern "C" void cpu_sampling_irq_entry(); -extern "C" void irq_32_entry(); + extern "C" void irq_32_entry(); -extern "C" MHz calculate_cpu_frequency(); + extern "C" MHz calculate_cpu_frequency(); } //< namespace hw diff --git a/src/kernel/cpuid.cpp b/src/kernel/cpuid.cpp index 7982f55c3d..0a38bfb572 100644 --- a/src/kernel/cpuid.cpp +++ b/src/kernel/cpuid.cpp @@ -95,32 +95,32 @@ static cpuid_t cpuid_info(const unsigned int func, const unsigned int subfunc) { cpuid_t info; __asm__ __volatile__ ( - "cpuid" - : "=a"(info.EAX), "=b"(info.EBX), "=c"(info.ECX), "=d"(info.EDX) - : "a"(func), "c"(subfunc) : "%eax", "%ebx", "%ecx", "%edx" - ); + "cpuid" + : "=a"(info.EAX), "=b"(info.EBX), "=c"(info.ECX), "=d"(info.EDX) + : "a"(func), "c"(subfunc) : "%eax", "%ebx", "%ecx", "%edx" + ); return info; } bool CPUID::isAmdCpu() { cpuid_t info = cpuid_info(0, 0); if (memcmp((char *) (&info.EBX), "htuA", 4) == 0 - && memcmp((char *) (&info.EDX), "itne", 4) == 0 - && memcmp((char *) (&info.ECX), "DMAc", 4) == 0) - { + && memcmp((char *) (&info.EDX), "itne", 4) == 0 + && memcmp((char *) (&info.ECX), "DMAc", 4) == 0) + { return true; - } + } return false; } bool CPUID::isIntelCpu() { cpuid_t info = cpuid_info(0, 0); if (memcmp((char *) (&info.EBX), "Genu", 4) == 0 - && memcmp((char *) (&info.EDX), "ineI", 4) == 0 - && memcmp((char *) (&info.ECX), "ntel", 4) == 0) - { + && memcmp((char *) (&info.EDX), "ineI", 4) == 0 + && memcmp((char *) (&info.ECX), "ntel", 4) == 0) + { return true; - } + } return false; } diff --git a/src/kernel/irq_manager.cpp b/src/kernel/irq_manager.cpp index 376b4ef331..8c2ada8c24 100644 --- a/src/kernel/irq_manager.cpp +++ b/src/kernel/irq_manager.cpp @@ -66,39 +66,39 @@ extern "C" } /** Default Exception-handler, which just prints its number */ -#define EXCEPTION_HANDLER(I) \ - void exception_##I##_handler() { \ - printf("\n\n>>>> !!! CPU EXCEPTION %i !!! <<<<<\n", I); \ - printf("Heap end: %#x \n", (uint32_t)&_end); \ - kill(1, 9); \ +#define EXCEPTION_HANDLER(I) \ + void exception_##I##_handler() { \ + printf("\n\n>>>> !!! CPU EXCEPTION %i !!! <<<<<\n", I); \ + printf("Heap end: %#x \n", (uint32_t)&_end); \ + kill(1, 9); \ } void exception_handler() { - #define frp(N, ra) \ - (__builtin_frame_address(N) != nullptr) && \ - (ra = __builtin_return_address(N)) != nullptr +#define frp(N, ra) \ + (__builtin_frame_address(N) != nullptr) && \ + (ra = __builtin_return_address(N)) != nullptr printf("\n"); - #define PRINT_TRACE(N, ra) \ - printf("[%d] Return %p\n", N, ra); +#define PRINT_TRACE(N, ra) \ + printf("[%d] Return %p\n", N, ra); void* ra; if (frp(0, ra)) { - PRINT_TRACE(0, ra); - if (frp(1, ra)) { - PRINT_TRACE(1, ra); - if (frp(2, ra)) { - PRINT_TRACE(2, ra); - if (frp(3, ra)) { - PRINT_TRACE(3, ra); - if (frp(4, ra)) { - PRINT_TRACE(4, ra); - if (frp(5, ra)) { - PRINT_TRACE(5, ra); - if (frp(6, ra)) - PRINT_TRACE(6, ra); - }}}}}} + PRINT_TRACE(0, ra); + if (frp(1, ra)) { + PRINT_TRACE(1, ra); + if (frp(2, ra)) { + PRINT_TRACE(2, ra); + if (frp(3, ra)) { + PRINT_TRACE(3, ra); + if (frp(4, ra)) { + PRINT_TRACE(4, ra); + if (frp(5, ra)) { + PRINT_TRACE(5, ra); + if (frp(6, ra)) + PRINT_TRACE(6, ra); + }}}}}} printf(">>>> !!! CPU EXCEPTION !!! <<<<\n"); extern char _end; @@ -115,19 +115,19 @@ void exception_handler() uint32_t IRQ_manager::irq_counters_[32] {0}; -#define IRQ_HANDLER(I) \ - void irq_##I##_handler() { \ - IRQ_manager::register_interrupt(I); \ +#define IRQ_HANDLER(I) \ + void irq_##I##_handler() { \ + IRQ_manager::register_interrupt(I); \ } /* Macro magic to register default gates */ -#define REG_DEFAULT_EXCPT(I) create_gate(&(idt[I]),exception_entry, \ - default_sel, default_attr ); +#define REG_DEFAULT_EXCPT(I) create_gate(&(idt[I]),exception_entry, \ + default_sel, default_attr ); -#define REG_DEFAULT_IRQ(I) create_gate(&(idt[I + irq_base]),irq_##I##_entry, \ - default_sel, default_attr ); +#define REG_DEFAULT_IRQ(I) create_gate(&(idt[I + irq_base]),irq_##I##_entry, \ + default_sel, default_attr ); - /* EXCEPTIONS */ +/* EXCEPTIONS */ #define EXCEPTION_PAIR(I) void exception_entry(); #define IRQ_PAIR(I) void irq_##I##_entry(); IRQ_HANDLER(I) @@ -191,27 +191,27 @@ void IRQ_manager::init() // Assign the lower 32 IRQ's : Exceptions REG_DEFAULT_EXCPT(0) REG_DEFAULT_EXCPT(1) REG_DEFAULT_EXCPT(2) - REG_DEFAULT_EXCPT(3) REG_DEFAULT_EXCPT(4) REG_DEFAULT_EXCPT(5) - REG_DEFAULT_EXCPT(6) REG_DEFAULT_EXCPT(7) REG_DEFAULT_EXCPT(8) - REG_DEFAULT_EXCPT(9) REG_DEFAULT_EXCPT(10) REG_DEFAULT_EXCPT(11) - REG_DEFAULT_EXCPT(12) REG_DEFAULT_EXCPT(13) REG_DEFAULT_EXCPT(14) - REG_DEFAULT_EXCPT(15) REG_DEFAULT_EXCPT(16) REG_DEFAULT_EXCPT(17) - REG_DEFAULT_EXCPT(18) REG_DEFAULT_EXCPT(19) REG_DEFAULT_EXCPT(20) - // GATES 21-29 are reserved - REG_DEFAULT_EXCPT(30) REG_DEFAULT_EXCPT(31) - INFO2("+ Exception gates set for irq < 32"); + REG_DEFAULT_EXCPT(3) REG_DEFAULT_EXCPT(4) REG_DEFAULT_EXCPT(5) + REG_DEFAULT_EXCPT(6) REG_DEFAULT_EXCPT(7) REG_DEFAULT_EXCPT(8) + REG_DEFAULT_EXCPT(9) REG_DEFAULT_EXCPT(10) REG_DEFAULT_EXCPT(11) + REG_DEFAULT_EXCPT(12) REG_DEFAULT_EXCPT(13) REG_DEFAULT_EXCPT(14) + REG_DEFAULT_EXCPT(15) REG_DEFAULT_EXCPT(16) REG_DEFAULT_EXCPT(17) + REG_DEFAULT_EXCPT(18) REG_DEFAULT_EXCPT(19) REG_DEFAULT_EXCPT(20) + // GATES 21-29 are reserved + REG_DEFAULT_EXCPT(30) REG_DEFAULT_EXCPT(31) + INFO2("+ Exception gates set for irq < 32"); //Redirected IRQ 0 - 15 REG_DEFAULT_IRQ(0) REG_DEFAULT_IRQ(1) REG_DEFAULT_IRQ(3) - REG_DEFAULT_IRQ(4) REG_DEFAULT_IRQ(5) REG_DEFAULT_IRQ(6) - REG_DEFAULT_IRQ(7) REG_DEFAULT_IRQ(8) REG_DEFAULT_IRQ(9) - REG_DEFAULT_IRQ(10) REG_DEFAULT_IRQ(11) REG_DEFAULT_IRQ(12) - REG_DEFAULT_IRQ(13) REG_DEFAULT_IRQ(14) REG_DEFAULT_IRQ(15) - - //Set all irq-gates (> 47) to the default handler - for(int i=48;i 47) to the default handler + for(int i=48;i= 32"); //Load IDT @@ -234,9 +234,9 @@ union addr_union { }; void IRQ_manager::create_gate(IDTDescr* idt_entry, - void (*function_addr)(), - uint16_t segment_sel, - char attributes) { + void (*function_addr)(), + uint16_t segment_sel, + char attributes) { addr_union addr; addr.whole = (uint32_t)function_addr; idt_entry->offset_1 = addr.lo16; @@ -270,7 +270,7 @@ IRQ_manager::irq_delegate IRQ_manager::get_subscriber(uint8_t irq) { } void IRQ_manager::enable_irq(uint8_t irq) { - hw::PIC::enable_irq(irq); + hw::PIC::enable_irq(irq); } int IRQ_manager::timer_interrupts {0}; @@ -327,9 +327,9 @@ void IRQ_manager::notify() { // Spinlock? Well, we can't lock out the IRQ-handler // ... and we don't have a timer interrupt so we can't do blocking locks. if (!irq_counters_[irq]) { - // Remove the IRQ from pending list - irq_pending_ &= ~(1 << irq); - //debug(" IRQ's pending: 0x%lx\n",irq_pending_); + // Remove the IRQ from pending list + irq_pending_ &= ~(1 << irq); + //debug(" IRQ's pending: 0x%lx\n",irq_pending_); } // Critical section end @@ -344,7 +344,7 @@ void IRQ_manager::notify() { } void IRQ_manager::eoi(uint8_t irq) { - hw::PIC::eoi(irq); + hw::PIC::eoi(irq); } void irq_default_handler() { diff --git a/src/kernel/os.cpp b/src/kernel/os.cpp index e4c31c920e..532e9e6eea 100644 --- a/src/kernel/os.cpp +++ b/src/kernel/os.cpp @@ -68,16 +68,16 @@ void OS::start() { /** Estimate CPU frequency - MYINFO("Estimating CPU-frequency"); - INFO2("|"); - INFO2("+--(10 samples, %f sec. interval)", - (hw::PIT::frequency() / _cpu_sampling_freq_divider_).count()); - INFO2("|"); + MYINFO("Estimating CPU-frequency"); + INFO2("|"); + INFO2("+--(10 samples, %f sec. interval)", + (hw::PIT::frequency() / _cpu_sampling_freq_divider_).count()); + INFO2("|"); - // TODO: Debug why actual measurments sometimes causes problems. Issue #246. - cpu_mhz_ = hw::PIT::CPUFrequency(); + // TODO: Debug why actual measurments sometimes causes problems. Issue #246. + cpu_mhz_ = hw::PIT::CPUFrequency(); - INFO2("+--> %f MHz", cpu_mhz_.count()); + INFO2("+--> %f MHz", cpu_mhz_.count()); **/ diff --git a/src/kernel/pci_manager.cpp b/src/kernel/pci_manager.cpp index a0998e590f..e643043ea4 100644 --- a/src/kernel/pci_manager.cpp +++ b/src/kernel/pci_manager.cpp @@ -35,11 +35,11 @@ void PCI_manager::init() { uint32_t id {PCI::WTF}; for (uint16_t pci_addr {0}; pci_addr < 255; ++pci_addr) { - id = hw::PCI_Device::read_dword(pci_addr, PCI::CONFIG_VENDOR); - if (id != PCI::WTF) { - hw::PCI_Device dev {pci_addr, id}; - devices_[dev.classcode()].emplace_back(dev); - } + id = hw::PCI_Device::read_dword(pci_addr, PCI::CONFIG_VENDOR); + if (id != PCI::WTF) { + hw::PCI_Device dev {pci_addr, id}; + devices_[dev.classcode()].emplace_back(dev); + } } // Pretty printing, end of device tree diff --git a/src/kernel/rdrand.cpp b/src/kernel/rdrand.cpp index a24ece1541..aa927244c5 100644 --- a/src/kernel/rdrand.cpp +++ b/src/kernel/rdrand.cpp @@ -25,9 +25,9 @@ bool rdrand16(uint16_t* result) { int res = 0; while (res == 0) - { - res = _rdrand16_step(result); - } + { + res = _rdrand16_step(result); + } return (res == 1); } @@ -35,8 +35,8 @@ bool rdrand32(uint32_t* result) { int res = 0; while (res == 0) - { - res = _rdrand32_step(result); - } + { + res = _rdrand32_step(result); + } return (res == 1); } diff --git a/src/kernel/syscalls.cpp b/src/kernel/syscalls.cpp index 112cd976b1..706fb0288e 100644 --- a/src/kernel/syscalls.cpp +++ b/src/kernel/syscalls.cpp @@ -111,7 +111,7 @@ int read(int UNUSED(file), void* UNUSED(ptr), size_t UNUSED(len)) { int write(int file, const void* ptr, size_t len) { if (file == syscall_fd and not debug_syscalls) { - return len; + return len; } return OS::rsprint((const char*) ptr, len); } diff --git a/src/kernel/terminal.cpp b/src/kernel/terminal.cpp index 180983141c..781c4410b1 100644 --- a/src/kernel/terminal.cpp +++ b/src/kernel/terminal.cpp @@ -32,22 +32,22 @@ Terminal::Terminal(Connection_ptr csock) : Terminal() { csock->onReceive( - [this] (auto conn, bool) - { - char buffer[1024]; - size_t bytes = conn->read(buffer, sizeof(buffer)); + [this] (auto conn, bool) + { + char buffer[1024]; + size_t bytes = conn->read(buffer, sizeof(buffer)); - this->read(buffer, bytes); - }); + this->read(buffer, bytes); + }); on_write = - [csock] (const char* buffer, size_t len) - { - csock->write(buffer, len); - }; + [csock] (const char* buffer, size_t len) + { + csock->write(buffer, len); + }; on_exit = - [csock] { + [csock] { csock->close(); }; // after setting up everything, show introduction @@ -58,29 +58,29 @@ Terminal::Terminal(hw::Serial& serial) : Terminal() { serial.on_data( - [this, &serial] (char c) - { - this->read(&c, 1); - if (c == CR) - { - c = LF; - this->read(&c, 1); - } - else - { - serial.write(c); - } - }); + [this, &serial] (char c) + { + this->read(&c, 1); + if (c == CR) + { + c = LF; + this->read(&c, 1); + } + else + { + serial.write(c); + } + }); on_write = - [&serial] (const char* buffer, size_t len) - { - for (size_t i = 0; i < len; i++) - serial.write(buffer[i]); - }; + [&serial] (const char* buffer, size_t len) + { + for (size_t i = 0; i < len; i++) + serial.write(buffer[i]); + }; on_exit = - [] { + [] { // do nothing }; // after setting up everything, show introduction @@ -90,86 +90,86 @@ Terminal::Terminal(hw::Serial& serial) void Terminal::read(const char* buf, size_t len) { while (len) - { - if (this->subcmd) - { - // execute options - option(this->subcmd, (uint8_t) *buf); - this->subcmd = 0; - } - else if (this->iac) - { - command(*(uint8_t*) buf); - this->iac = false; - } - else if (*buf == 13 && !newline) { - newline = true; + if (this->subcmd) + { + // execute options + option(this->subcmd, (uint8_t) *buf); + this->subcmd = 0; + } + else if (this->iac) + { + command(*(uint8_t*) buf); + this->iac = false; + } + else if (*buf == 13 && !newline) + { + newline = true; + } + else if (*buf == 10 && newline) + { + newline = false; + // parse message + run(buffer); + buffer.clear(); + } + else if (*buf == 0) + { + // NOP + } + else if ((uint8_t) *buf == 0xFF) + { + // Interpret as Command + this->iac = true; + } + else + { + buffer.append(buf, 1); + } + buf++; len--; } - else if (*buf == 10 && newline) - { - newline = false; - // parse message - run(buffer); - buffer.clear(); - } - else if (*buf == 0) - { - // NOP - } - else if ((uint8_t) *buf == 0xFF) - { - // Interpret as Command - this->iac = true; - } - else - { - buffer.append(buf, 1); - } - buf++; len--; - } } void Terminal::command(uint8_t cmd) { switch (cmd) - { - case 247: // erase char - printf("CMD: Erase char\n"); - break; - case 248: // erase line - printf("CMD: Erase line\n"); - break; - case 250: // Begin - printf("CMD: Begin...\n"); - break; - case 251: // Will USE - case 252: // Won't USE - case 253: // Start USE - case 254: // Stop USE - //printf("CMD: Command %d\n", cmd); - this->subcmd = cmd; - break; - case 255: - //printf("CMD: Command %d\n", cmd); - this->subcmd = cmd; - break; - default: - printf("CMD: Unknown command %d\n", cmd); - } + { + case 247: // erase char + printf("CMD: Erase char\n"); + break; + case 248: // erase line + printf("CMD: Erase line\n"); + break; + case 250: // Begin + printf("CMD: Begin...\n"); + break; + case 251: // Will USE + case 252: // Won't USE + case 253: // Start USE + case 254: // Stop USE + //printf("CMD: Command %d\n", cmd); + this->subcmd = cmd; + break; + case 255: + //printf("CMD: Command %d\n", cmd); + this->subcmd = cmd; + break; + default: + printf("CMD: Unknown command %d\n", cmd); + } } void Terminal::option(uint8_t option, uint8_t cmd) { (void) option; switch (cmd) - { - case 24: // terminal type - break; - default: - //printf("CMD: Unknown cmd %d for option %d\n", cmd, option); - break; - } + { + case 24: // terminal type + break; + default: + //printf("CMD: Unknown cmd %d for option %d\n", cmd, option); + break; + } } std::vector @@ -185,41 +185,41 @@ split(const std::string& text, std::string& command) x = text.find(" "); // early return for cmd-only msg if (x == std::string::npos) - { - command = text; - return retv; - } + { + command = text; + return retv; + } // command is substring command = text.substr(0, x); p = x+1; } // parse remainder do - { - x = text.find(" ", p+1); - size_t y = text.find(":", x+1); // find last param - - if (y == x+1) - { - // single argument - retv.push_back(text.substr(p, x-p)); - // ending text argument - retv.push_back(text.substr(y+1)); - break; - } - else if (x != std::string::npos) - { - // single argument - retv.push_back(text.substr(p, x-p)); - } - else { - // last argument - retv.push_back(text.substr(p)); - } - p = x+1; + x = text.find(" ", p+1); + size_t y = text.find(":", x+1); // find last param + + if (y == x+1) + { + // single argument + retv.push_back(text.substr(p, x-p)); + // ending text argument + retv.push_back(text.substr(y+1)); + break; + } + else if (x != std::string::npos) + { + // single argument + retv.push_back(text.substr(p, x-p)); + } + else + { + // last argument + retv.push_back(text.substr(p)); + } + p = x+1; - } while (x != std::string::npos); + } while (x != std::string::npos); return retv; } @@ -229,20 +229,20 @@ void Terminal::run(const std::string& cmd_string) std::string cmd_name; auto cmd_vec = split(cmd_string, cmd_name); if (cmd_name.size()) - { - printf("Terminal::run(): %s\n", cmd_name.c_str()); - - auto it = commands.find(cmd_name); - if (it != commands.end()) { - int retv = it->second.main(cmd_vec); - if (retv) write("%s returned: %d\r\n", cmd_name.c_str(), retv); - } - else - { - write("No such command: '%s'\r\n", cmd_name.c_str()); + printf("Terminal::run(): %s\n", cmd_name.c_str()); + + auto it = commands.find(cmd_name); + if (it != commands.end()) + { + int retv = it->second.main(cmd_vec); + if (retv) write("%s returned: %d\r\n", cmd_name.c_str(), retv); + } + else + { + write("No such command: '%s'\r\n", cmd_name.c_str()); + } } - } prompt(); } @@ -250,29 +250,29 @@ void Terminal::add_basic_commands() { // ?: add( - "?", "List available commands", - [this] (const std::vector&) -> int - { - for (auto cmd : this->commands) + "?", "List available commands", + [this] (const std::vector&) -> int { - write("%s \t-- %s\r\n", cmd.first.c_str(), cmd.second.desc.c_str()); - } - return 0; - }); + for (auto cmd : this->commands) + { + write("%s \t-- %s\r\n", cmd.first.c_str(), cmd.second.desc.c_str()); + } + return 0; + }); // exit: add( - "exit", "Close the terminal", - [this] (const std::vector&) -> int - { - this->on_exit(); - return 0; - }); + "exit", "Close the terminal", + [this] (const std::vector&) -> int + { + this->on_exit(); + return 0; + }); } void Terminal::intro() { std::string banana = - R"baaa( + R"baaa( ____ ___ | _ \ ___ _ _.' _ `. _ | [_) )' _ `._ _ ___ ! \ | | (_) | _ @@ -282,13 +282,13 @@ void Terminal::intro() !::, `-!_| | | |\ | | | | | \ !_!.' ':;! !::; ":;:!.!.\_!_!_!.!-'-':;:'' '''! ';:' `::;::;' '' ., . - `: .,. `' .::... . .::;::;' - `..:;::;:.. ::;::;:;:;, :;::;' + `: .,. `' .::... . .::;::;' + `..:;::;:.. ::;::;:;:;, :;::;' "-:;::;:;: ':;::;:'' ;.-' ""`---...________...---'"" -> Banana Terminal v1 < -)baaa"; + > Banana Terminal v1 < + )baaa"; write("%s", banana.c_str()); prompt(); diff --git a/src/kernel/terminal_disk.cpp b/src/kernel/terminal_disk.cpp index 03966875aa..77b8586a1c 100644 --- a/src/kernel/terminal_disk.cpp +++ b/src/kernel/terminal_disk.cpp @@ -45,116 +45,116 @@ void Terminal::add_disk_commands(Disk_ptr disk) // add 'cd' command add("cd", "Change current directory", - [this, curdir, disk] (const std::vector& args) -> int - { - // current directory, somehow... - std::string target = "/"; - if (!args.empty()) target = args[0]; + [this, curdir, disk] (const std::vector& args) -> int + { + // current directory, somehow... + std::string target = "/"; + if (!args.empty()) target = args[0]; - Path path(*curdir); - path += target; + Path path(*curdir); + path += target; - int rv = target_directory(disk, path); - if (rv) - { - this->write("cd: %s: No such file or directory\r\n", target.c_str()); - return rv; - } - *curdir = path.to_string(); - return 0; - }); + int rv = target_directory(disk, path); + if (rv) + { + this->write("cd: %s: No such file or directory\r\n", target.c_str()); + return rv; + } + *curdir = path.to_string(); + return 0; + }); // add 'ls' command add("ls", "List files in a folder", - [this, curdir, disk] (const std::vector& args) -> int - { - // current directory, somehow... - Path path(*curdir); - if (!args.empty()) path += args[0]; - - int rv = target_directory(disk, path); - if (rv) + [this, curdir, disk] (const std::vector& args) -> int { - this->write("ls: %s: No such file or directory\r\n", path.to_string().c_str()); - return rv; - } + // current directory, somehow... + Path path(*curdir); + if (!args.empty()) path += args[0]; - std::string target = path.to_string(); + int rv = target_directory(disk, path); + if (rv) + { + this->write("ls: %s: No such file or directory\r\n", path.to_string().c_str()); + return rv; + } - auto& fs = disk->fs(); - auto vec = fs::new_shared_vector(); - auto err = fs.ls(target, vec); - if (!err) - { - this->write("%s \t%s \t%s \t%s\r\n", - "Name", "Size", "Type", "Sector"); - for (auto& ent : *vec) - { - this->write("%s \t%llu \t%s \t%llu\r\n", - ent.name().c_str(), ent.size, ent.type_string().c_str(), ent.block); - } - this->write("Total %u\r\n", vec->size()); - return 0; - } - else - { - this->write("Could not list %s\r\n", args[0].c_str()); - return 1; - } - }); + std::string target = path.to_string(); + + auto& fs = disk->fs(); + auto vec = fs::new_shared_vector(); + auto err = fs.ls(target, vec); + if (!err) + { + this->write("%s \t%s \t%s \t%s\r\n", + "Name", "Size", "Type", "Sector"); + for (auto& ent : *vec) + { + this->write("%s \t%llu \t%s \t%llu\r\n", + ent.name().c_str(), ent.size, ent.type_string().c_str(), ent.block); + } + this->write("Total %u\r\n", vec->size()); + return 0; + } + else + { + this->write("Could not list %s\r\n", args[0].c_str()); + return 1; + } + }); // add 'stat' command add("stat", "List file information", - [this, disk] (const std::vector& args) -> int - { - if (!args.empty()) - { - auto& fs = disk->fs(); - auto ent = fs.stat(args[0]); - if (ent.is_valid()) - { - this->write("%s \t%s \t%s \t%s\r\n", - "Name", "Size", "Type", "Sector"); - this->write("%s \t%llu \t%s \t%llu\r\n", - ent.name().c_str(), ent.size, ent.type_string().c_str(), ent.block); - return 0; - } - else - { - this->write("stat: Cannot stat '%s'\r\n", args[0].c_str()); - return 1; - } - } - else + [this, disk] (const std::vector& args) -> int { - this->write("%s\r\n", "stat: Not enough arguments"); - return 1; - } - }); + if (!args.empty()) + { + auto& fs = disk->fs(); + auto ent = fs.stat(args[0]); + if (ent.is_valid()) + { + this->write("%s \t%s \t%s \t%s\r\n", + "Name", "Size", "Type", "Sector"); + this->write("%s \t%llu \t%s \t%llu\r\n", + ent.name().c_str(), ent.size, ent.type_string().c_str(), ent.block); + return 0; + } + else + { + this->write("stat: Cannot stat '%s'\r\n", args[0].c_str()); + return 1; + } + } + else + { + this->write("%s\r\n", "stat: Not enough arguments"); + return 1; + } + }); // add 'cat' command add("cat", "Concatenate files and print", - [this, disk] (const std::vector& args) -> int - { - auto& fs = disk->fs(); - - for (const auto& file : args) + [this, disk] (const std::vector& args) -> int { - // get file information - auto ent = fs.stat(file); - if (!ent.is_valid()) - { - this->write("cat: '%s': No such file or directory\r\n", file.c_str()); - return 1; - } - // read file contents - auto buf = fs.read(ent, 0, ent.size); - if (!buf.buffer) - { - this->write("cat: '%s': I/O error\r\n", file.c_str()); - return 1; - } - // write to terminal client - std::string buffer((char*) buf.buffer.get(), buf.len); - this->write("%s\r\n", buffer.c_str()); - } - return 0; - }); + auto& fs = disk->fs(); + + for (const auto& file : args) + { + // get file information + auto ent = fs.stat(file); + if (!ent.is_valid()) + { + this->write("cat: '%s': No such file or directory\r\n", file.c_str()); + return 1; + } + // read file contents + auto buf = fs.read(ent, 0, ent.size); + if (!buf.buffer) + { + this->write("cat: '%s': I/O error\r\n", file.c_str()); + return 1; + } + // write to terminal client + std::string buffer((char*) buf.buffer.get(), buf.len); + this->write("%s\r\n", buffer.c_str()); + } + return 0; + }); } diff --git a/src/kernel/vga.cpp b/src/kernel/vga.cpp index e820fc1328..d48340b320 100644 --- a/src/kernel/vga.cpp +++ b/src/kernel/vga.cpp @@ -25,10 +25,10 @@ static uint16_t make_vgaentry(const char c, const uint8_t color) noexcept { return c16 | color16 << 8; } const uint16_t ConsoleVGA::DEFAULT_ENTRY = - make_vgaentry(32, make_color(COLOR_LIGHT_GREY, COLOR_BLACK)); + make_vgaentry(32, make_color(COLOR_LIGHT_GREY, COLOR_BLACK)); ConsoleVGA::ConsoleVGA() noexcept: - row{0}, column{0} +row{0}, column{0} { this->color = make_color(COLOR_WHITE, COLOR_BLACK); this->buffer = reinterpret_cast(0xB8000); diff --git a/src/net/arp.cpp b/src/net/arp.cpp index 46666b9eb0..ed43f967e2 100644 --- a/src/net/arp.cpp +++ b/src/net/arp.cpp @@ -27,205 +27,205 @@ namespace net { -static void ignore(Packet_ptr UNUSED(pckt)) { - debug2(" linklayer> Empty handler - DROP!\n"); -} + static void ignore(Packet_ptr UNUSED(pckt)) { + debug2(" linklayer> Empty handler - DROP!\n"); + } // Initialize -Arp::Arp(net::Inet& inet) noexcept: + Arp::Arp(net::Inet& inet) noexcept: inet_ {inet}, - mac_ (inet.link_addr()), - linklayer_out_ {ignore} + mac_ (inet.link_addr()), + linklayer_out_ {ignore} {} -void Arp::bottom(Packet_ptr pckt) { - debug2(" got %i bytes of data\n", pckt->size()); + void Arp::bottom(Packet_ptr pckt) { + debug2(" got %i bytes of data\n", pckt->size()); - header* hdr = reinterpret_cast(pckt->buffer()); + header* hdr = reinterpret_cast(pckt->buffer()); - debug2("Have valid cache? %s\n", is_valid_cached(hdr->sipaddr) ? "YES" : "NO"); - cache(hdr->sipaddr, hdr->shwaddr); + debug2("Have valid cache? %s\n", is_valid_cached(hdr->sipaddr) ? "YES" : "NO"); + cache(hdr->sipaddr, hdr->shwaddr); - switch(hdr->opcode) { + switch(hdr->opcode) { - case H_request: { - debug2("\t ARP REQUEST: "); - debug2("%s is looking for %s\n", - hdr->sipaddr.str().c_str(), - hdr->dipaddr.str().c_str()); + case H_request: { + debug2("\t ARP REQUEST: "); + debug2("%s is looking for %s\n", + hdr->sipaddr.str().c_str(), + hdr->dipaddr.str().c_str()); - if (hdr->dipaddr == inet_.ip_addr()) { - arp_respond(hdr); - } else { - debug2("\t NO MATCH for My IP (%s). DROP!\n", - inet_.ip_addr().str().c_str()); + if (hdr->dipaddr == inet_.ip_addr()) { + arp_respond(hdr); + } else { + debug2("\t NO MATCH for My IP (%s). DROP!\n", + inet_.ip_addr().str().c_str()); + } + break; } - break; - } - case H_reply: { - debug2("\t ARP REPLY: %s belongs to %s\n", - hdr->sipaddr.str().c_str(), hdr->shwaddr.str().c_str()); - - auto waiting = waiting_packets_.find(hdr->sipaddr); - - if (waiting != waiting_packets_.end()) { - debug("Had a packet waiting for this IP. Sending\n"); - transmit(waiting->second); - waiting_packets_.erase(waiting); + case H_reply: { + debug2("\t ARP REPLY: %s belongs to %s\n", + hdr->sipaddr.str().c_str(), hdr->shwaddr.str().c_str()); + + auto waiting = waiting_packets_.find(hdr->sipaddr); + + if (waiting != waiting_packets_.end()) { + debug("Had a packet waiting for this IP. Sending\n"); + transmit(waiting->second); + waiting_packets_.erase(waiting); + } + break; } - break; - } - default: - debug2("\t UNKNOWN OPCODE\n"); - break; - } //< switch(hdr->opcode) -} + default: + debug2("\t UNKNOWN OPCODE\n"); + break; + } //< switch(hdr->opcode) + } -void Arp::cache(IP4::addr ip, Ethernet::addr mac) { - debug2("Caching IP %s for %s\n", ip.str().c_str(), mac.str().c_str()); + void Arp::cache(IP4::addr ip, Ethernet::addr mac) { + debug2("Caching IP %s for %s\n", ip.str().c_str(), mac.str().c_str()); - auto entry = cache_.find(ip); + auto entry = cache_.find(ip); - if (entry != cache_.end()) { - debug2("Cached entry found: %s recorded @ %llu. Updating timestamp\n", - entry->second.mac_.str().c_str(), entry->second.timestamp_); + if (entry != cache_.end()) { + debug2("Cached entry found: %s recorded @ %llu. Updating timestamp\n", + entry->second.mac_.str().c_str(), entry->second.timestamp_); - // Update - entry->second.update(); + // Update + entry->second.update(); - } else { - cache_[ip] = mac; // Insert + } else { + cache_[ip] = mac; // Insert + } } -} -bool Arp::is_valid_cached(IP4::addr ip) { - auto entry = cache_.find(ip); + bool Arp::is_valid_cached(IP4::addr ip) { + auto entry = cache_.find(ip); - if (entry != cache_.end()) { - debug("Cached entry, mac: %s time: %llu Expiry: %llu\n", - entry->second.mac_.str().c_str(), - entry->second.timestamp_, entry->second.timestamp_ + cache_exp_t_); - debug("Time now: %llu\n", static_cast(OS::uptime())); - } + if (entry != cache_.end()) { + debug("Cached entry, mac: %s time: %llu Expiry: %llu\n", + entry->second.mac_.str().c_str(), + entry->second.timestamp_, entry->second.timestamp_ + cache_exp_t_); + debug("Time now: %llu\n", static_cast(OS::uptime())); + } - return entry != cache_.end() - and (entry->second.timestamp_ + cache_exp_t_ > static_cast(OS::uptime())); -} + return entry != cache_.end() + and (entry->second.timestamp_ + cache_exp_t_ > static_cast(OS::uptime())); + } -extern "C" { - unsigned long ether_crc(int length, unsigned char *data); -} + extern "C" { + unsigned long ether_crc(int length, unsigned char *data); + } -void Arp::arp_respond(header* hdr_in) { - debug2("\t IP Match. Constructing ARP Reply\n"); + void Arp::arp_respond(header* hdr_in) { + debug2("\t IP Match. Constructing ARP Reply\n"); - // Populate ARP-header - auto res = std::static_pointer_cast(inet_.createPacket(sizeof(header))); - res->init(mac_, inet_.ip_addr()); + // Populate ARP-header + auto res = std::static_pointer_cast(inet_.createPacket(sizeof(header))); + res->init(mac_, inet_.ip_addr()); - res->set_dest_mac(hdr_in->shwaddr); - res->set_dest_ip(hdr_in->sipaddr); - res->set_opcode(H_reply); + res->set_dest_mac(hdr_in->shwaddr); + res->set_dest_ip(hdr_in->sipaddr); + res->set_opcode(H_reply); - debug2("\t My IP: %s belongs to My Mac: %s\n", - res->source_ip().str().c_str(), res->source_mac().str().c_str()); + debug2("\t My IP: %s belongs to My Mac: %s\n", + res->source_ip().str().c_str(), res->source_mac().str().c_str()); - linklayer_out_(res); -} + linklayer_out_(res); + } -void Arp::transmit(Packet_ptr pckt) { - assert(pckt->size()); + void Arp::transmit(Packet_ptr pckt) { + assert(pckt->size()); - /** Get destination IP from IP header */ - IP4::ip_header* iphdr = reinterpret_cast(pckt->buffer() - + sizeof(Ethernet::header)); - IP4::addr sip = iphdr->saddr; - IP4::addr dip = pckt->next_hop(); + /** Get destination IP from IP header */ + IP4::ip_header* iphdr = reinterpret_cast(pckt->buffer() + + sizeof(Ethernet::header)); + IP4::addr sip = iphdr->saddr; + IP4::addr dip = pckt->next_hop(); - debug2(" physical> Transmitting %i bytes to %s\n", - pckt->size(), dip.str().c_str()); + debug2(" physical> Transmitting %i bytes to %s\n", + pckt->size(), dip.str().c_str()); - Ethernet::addr dest_mac; + Ethernet::addr dest_mac; - if (iphdr->daddr == IP4::INADDR_BCAST) { - // When broadcasting our source IP should be either - // our own IP or 0.0.0.0 + if (iphdr->daddr == IP4::INADDR_BCAST) { + // When broadcasting our source IP should be either + // our own IP or 0.0.0.0 - if (sip != inet_.ip_addr() && sip != IP4::INADDR_ANY) { - debug2(" Dropping outbound broadcast packet due to " - "invalid source IP %s\n", sip.str().c_str()); - return; - } - // mui importante - dest_mac = Ethernet::addr::BROADCAST_FRAME; + if (sip != inet_.ip_addr() && sip != IP4::INADDR_ANY) { + debug2(" Dropping outbound broadcast packet due to " + "invalid source IP %s\n", sip.str().c_str()); + return; + } + // mui importante + dest_mac = Ethernet::addr::BROADCAST_FRAME; - } else { - if (sip != inet_.ip_addr()) { - debug2(" physical> Not bound to source IP %s. My IP is %s. DROP!\n", - sip.str().c_str(), inet_.ip_addr().str().c_str()); - return; - } + } else { + if (sip != inet_.ip_addr()) { + debug2(" physical> Not bound to source IP %s. My IP is %s. DROP!\n", + sip.str().c_str(), inet_.ip_addr().str().c_str()); + return; + } - // If we don't have a cached IP, perform address resolution - if (!is_valid_cached(dip)) { + // If we don't have a cached IP, perform address resolution + if (!is_valid_cached(dip)) { arp_resolver_(pckt); return; - } + } - // Get MAC from cache - dest_mac = cache_[dip].mac_; + // Get MAC from cache + dest_mac = cache_[dip].mac_; + } + + /** Attach next-hop mac and ethertype to ethernet header */ + Ethernet::header* ethhdr = reinterpret_cast(pckt->buffer()); + ethhdr->src = mac_; + ethhdr->dest = dest_mac; + ethhdr->type = Ethernet::ETH_IP4; + + debug2(" physical> Sending packet to %s\n", mac_.str().c_str()); + linklayer_out_(pckt); + } + + void Arp::await_resolution(Packet_ptr pckt, IP4::addr) { + auto queue = waiting_packets_.find(pckt->next_hop()); + + if (queue != waiting_packets_.end()) { + debug(" Packets already queueing for this IP\n"); + queue->second->chain(pckt); + } else { + debug(" This is the first packet going to that IP\n"); + waiting_packets_.emplace(std::make_pair(pckt->next_hop(), pckt)); + } } + + void Arp::arp_resolve(Packet_ptr pckt) { + debug(" %s\n", pckt->next_hop().str().c_str()); + + await_resolution(pckt, pckt->next_hop()); + + auto req = view_packet_as(inet_.createPacket(sizeof(header))); + req->init(mac_, inet_.ip_addr()); - /** Attach next-hop mac and ethertype to ethernet header */ - Ethernet::header* ethhdr = reinterpret_cast(pckt->buffer()); - ethhdr->src = mac_; - ethhdr->dest = dest_mac; - ethhdr->type = Ethernet::ETH_IP4; - - debug2(" physical> Sending packet to %s\n", mac_.str().c_str()); - linklayer_out_(pckt); -} - -void Arp::await_resolution(Packet_ptr pckt, IP4::addr) { - auto queue = waiting_packets_.find(pckt->next_hop()); - - if (queue != waiting_packets_.end()) { - debug(" Packets already queueing for this IP\n"); - queue->second->chain(pckt); - } else { - debug(" This is the first packet going to that IP\n"); - waiting_packets_.emplace(std::make_pair(pckt->next_hop(), pckt)); - } -} - -void Arp::arp_resolve(Packet_ptr pckt) { - debug(" %s\n", pckt->next_hop().str().c_str()); - - await_resolution(pckt, pckt->next_hop()); - - auto req = view_packet_as(inet_.createPacket(sizeof(header))); - req->init(mac_, inet_.ip_addr()); - - req->set_dest_mac(Ethernet::addr::BROADCAST_FRAME); - req->set_dest_ip(pckt->next_hop()); - req->set_opcode(H_request); - - linklayer_out_(req); -} - -void Arp::hh_map(Packet_ptr pckt) { - (void) pckt; - debug("ARP-resolution using the HH-hack"); - /** - // Fixed mac prefix - mac.minor = 0x01c0; //Big-endian c001 - // Destination IP - mac.major = dip.whole; - debug("ARP cache missing. Guessing Mac %s from next-hop IP: %s (dest.ip: %s)", - mac.str().c_str(), dip.str().c_str(), iphdr->daddr.str().c_str()); - **/ -} + req->set_dest_mac(Ethernet::addr::BROADCAST_FRAME); + req->set_dest_ip(pckt->next_hop()); + req->set_opcode(H_request); + + linklayer_out_(req); + } + + void Arp::hh_map(Packet_ptr pckt) { + (void) pckt; + debug("ARP-resolution using the HH-hack"); + /** + // Fixed mac prefix + mac.minor = 0x01c0; //Big-endian c001 + // Destination IP + mac.major = dip.whole; + debug("ARP cache missing. Guessing Mac %s from next-hop IP: %s (dest.ip: %s)", + mac.str().c_str(), dip.str().c_str(), iphdr->daddr.str().c_str()); + **/ + } } //< namespace net diff --git a/src/net/buffer_store.cpp b/src/net/buffer_store.cpp index 16000a4fef..8b575538e4 100644 --- a/src/net/buffer_store.cpp +++ b/src/net/buffer_store.cpp @@ -24,16 +24,16 @@ namespace net { -BufferStore::BufferStore(size_t num, size_t bufsize, size_t device_offset ) : - bufcount_ {num}, - bufsize_ {bufsize}, - device_offset_ {device_offset}, - pool_ {static_cast(memalign(PAGE_SIZE, num * bufsize))} + BufferStore::BufferStore(size_t num, size_t bufsize, size_t device_offset ) : + bufcount_ {num}, + bufsize_ {bufsize}, + device_offset_ {device_offset}, + pool_ {static_cast(memalign(PAGE_SIZE, num * bufsize))} { assert(pool_); debug (" Creating buffer store of %i * %i bytes.\n", - num, bufsize); + num, bufsize); for (buffer_t b = pool_; b < pool_ + (num * bufsize); b += bufsize) available_buffers_.push_back(b); @@ -42,62 +42,62 @@ BufferStore::BufferStore(size_t num, size_t bufsize, size_t device_offset ) : available_buffers_.size(), pool_, pool_ + (bufcount_ * bufsize_)); } -BufferStore::~BufferStore() { - free(pool_); -} + BufferStore::~BufferStore() { + free(pool_); + } -/** - * @todo : We (think we) want a list of pools, that we increase as needed. - */ -void BufferStore::increaseStorage() { - panic(" Storage pool full! Don't know how to increase pool size yet.\n"); -} + /** + * @todo : We (think we) want a list of pools, that we increase as needed. + */ + void BufferStore::increaseStorage() { + panic(" Storage pool full! Don't know how to increase pool size yet.\n"); + } -BufferStore::buffer_t BufferStore::get_raw_buffer() { - if (available_buffers_.empty()) - increaseStorage(); + BufferStore::buffer_t BufferStore::get_raw_buffer() { + if (available_buffers_.empty()) + increaseStorage(); - auto buf = available_buffers_.front(); - available_buffers_.pop_front(); + auto buf = available_buffers_.front(); + available_buffers_.pop_front(); - debug2(" Provisioned a buffer. %i buffers remaining.\n", - available_buffers_.size()); - - return buf; -} - -BufferStore::buffer_t BufferStore::get_offset_buffer() { - return get_raw_buffer() + device_offset_; -} - -void BufferStore::release_raw_buffer(buffer_t b, size_t bufsize) { - debug2(" Trying to release %i sized buffer @%p.\n", bufsize, b); - // Make sure the buffer comes from here. Otherwise, ignore it. - if (address_is_from_pool(b) - and address_is_bufstart(b) - and bufsize == bufsize_) - { - available_buffers_.push_back(b); - debug(" Releasing %p. %i available buffers.\n", b, available_buffers_.size()); - return; - } - - debug(" IGNORING buffer @%p. It isn't mine.\n", b); -} - -void BufferStore::release_offset_buffer(buffer_t b, size_t bufsize) { - debug2(" Trying to release %i + %i sized buffer @%p.\n", bufsize, device_offset_, b); - // Make sure the buffer comes from here. Otherwise, ignore it. - if (address_is_from_pool(b) - and address_is_offset_bufstart(b) - and bufsize == bufsize_ - device_offset_) - { - available_buffers_.push_back(b - device_offset_); - debug(" Releasing %p. %i available buffers.\n", b, available_buffers_.size()); - return; - } - - debug(" IGNORING buffer @%p. It isn't mine.\n", b); -} + debug2(" Provisioned a buffer. %i buffers remaining.\n", + available_buffers_.size()); + + return buf; + } + + BufferStore::buffer_t BufferStore::get_offset_buffer() { + return get_raw_buffer() + device_offset_; + } + + void BufferStore::release_raw_buffer(buffer_t b, size_t bufsize) { + debug2(" Trying to release %i sized buffer @%p.\n", bufsize, b); + // Make sure the buffer comes from here. Otherwise, ignore it. + if (address_is_from_pool(b) + and address_is_bufstart(b) + and bufsize == bufsize_) + { + available_buffers_.push_back(b); + debug(" Releasing %p. %i available buffers.\n", b, available_buffers_.size()); + return; + } + + debug(" IGNORING buffer @%p. It isn't mine.\n", b); + } + + void BufferStore::release_offset_buffer(buffer_t b, size_t bufsize) { + debug2(" Trying to release %i + %i sized buffer @%p.\n", bufsize, device_offset_, b); + // Make sure the buffer comes from here. Otherwise, ignore it. + if (address_is_from_pool(b) + and address_is_offset_bufstart(b) + and bufsize == bufsize_ - device_offset_) + { + available_buffers_.push_back(b - device_offset_); + debug(" Releasing %p. %i available buffers.\n", b, available_buffers_.size()); + return; + } + + debug(" IGNORING buffer @%p. It isn't mine.\n", b); + } } //< namespace net diff --git a/src/net/dhcp/dh4client.cpp b/src/net/dhcp/dh4client.cpp index 9e2f8740f0..94d5341fa8 100644 --- a/src/net/dhcp/dh4client.cpp +++ b/src/net/dhcp/dh4client.cpp @@ -220,29 +220,29 @@ namespace net socket.bcast(IP4::INADDR_ANY, DHCP_DEST_PORT, packet, packetlen); socket.onRead( - [this] (Socket& sock, IP4::addr addr, UDP::port_t port, - const char* data, int len) -> int - { - (void) addr; - if (port == DHCP_DEST_PORT) - { - // we have got a DHCP Offer - debug("Received possible DHCP OFFER from %s:%d\n", - addr.str().c_str(), DHCP_DEST_PORT); - this->offer(sock, data, len); - } - return -1; - }); + [this] (Socket& sock, IP4::addr addr, UDP::port_t port, + const char* data, int len) -> int + { + (void) addr; + if (port == DHCP_DEST_PORT) + { + // we have got a DHCP Offer + debug("Received possible DHCP OFFER from %s:%d\n", + addr.str().c_str(), DHCP_DEST_PORT); + this->offer(sock, data, len); + } + return -1; + }); } const dhcp_option_t* get_option(const uint8_t* options, uint8_t code) { const dhcp_option_t* opt = (const dhcp_option_t*) options; while (opt->code != code && opt->code != DHO_END) - { - // go to next option - opt = (const dhcp_option_t*) (((const uint8_t*) opt) + 2 + opt->length); - } + { + // go to next option + opt = (const dhcp_option_t*) (((const uint8_t*) opt) + 2 + opt->length); + } return opt; } @@ -260,68 +260,68 @@ namespace net opt = get_option(dhcp->options, DHO_DHCP_MESSAGE_TYPE); if (opt->code == DHO_DHCP_MESSAGE_TYPE) - { - // verify that the type is indeed DHCPOFFER - debug("Found DHCP message type %d (DHCP Offer = %d)\n", - opt->val[0], DHCPOFFER); + { + // verify that the type is indeed DHCPOFFER + debug("Found DHCP message type %d (DHCP Offer = %d)\n", + opt->val[0], DHCPOFFER); - // ignore when not a DHCP Offer - if (opt->val[0] != DHCPOFFER) return; - } + // ignore when not a DHCP Offer + if (opt->val[0] != DHCPOFFER) return; + } // ignore message when DHCP message type is missing else return; // the offered IP address: this->ipaddr = dhcp->yiaddr; MYINFO("IP ADDRESS: \t%s", - this->ipaddr.str().c_str()); + this->ipaddr.str().c_str()); opt = get_option(dhcp->options, DHO_SUBNET_MASK); if (opt->code == DHO_SUBNET_MASK) - { - memcpy(&this->netmask, opt->val, sizeof(IP4::addr)); - MYINFO("SUBNET MASK: \t%s", - this->netmask.str().c_str()); - } + { + memcpy(&this->netmask, opt->val, sizeof(IP4::addr)); + MYINFO("SUBNET MASK: \t%s", + this->netmask.str().c_str()); + } opt = get_option(dhcp->options, DHO_DHCP_LEASE_TIME); if (opt->code == DHO_DHCP_LEASE_TIME) - { - memcpy(&this->lease_time, opt->val, sizeof(this->lease_time)); - MYINFO("LEASE TIME: \t%u mins", this->lease_time / 60); - } + { + memcpy(&this->lease_time, opt->val, sizeof(this->lease_time)); + MYINFO("LEASE TIME: \t%u mins", this->lease_time / 60); + } // now validate the offer, checking for minimum information opt = get_option(dhcp->options, DHO_ROUTERS); if (opt->code == DHO_ROUTERS) - { - memcpy(&this->router, opt->val, sizeof(IP4::addr)); - MYINFO("GATEWAY: \t%s", - this->router.str().c_str()); - } + { + memcpy(&this->router, opt->val, sizeof(IP4::addr)); + MYINFO("GATEWAY: \t%s", + this->router.str().c_str()); + } // assume that the server we received the request from is the gateway else - { - opt = get_option(dhcp->options, DHO_DHCP_SERVER_IDENTIFIER); - if (opt->code == DHO_DHCP_SERVER_IDENTIFIER) { - memcpy(&this->router, opt->val, sizeof(IP4::addr)); - MYINFO("GATEWAY: \t%s", - this->router.str().c_str()); + opt = get_option(dhcp->options, DHO_DHCP_SERVER_IDENTIFIER); + if (opt->code == DHO_DHCP_SERVER_IDENTIFIER) + { + memcpy(&this->router, opt->val, sizeof(IP4::addr)); + MYINFO("GATEWAY: \t%s", + this->router.str().c_str()); + } + // silently ignore when both ROUTER and SERVER_ID is missing + else return; } - // silently ignore when both ROUTER and SERVER_ID is missing - else return; - } opt = get_option(dhcp->options, DHO_DOMAIN_NAME_SERVERS); if (opt->code == DHO_DOMAIN_NAME_SERVERS) - { - memcpy(&this->dns_server, opt->val, sizeof(IP4::addr)); - } + { + memcpy(&this->dns_server, opt->val, sizeof(IP4::addr)); + } else - { // just try using ROUTER as DNS server - this->dns_server = this->router; - } + { // just try using ROUTER as DNS server + this->dns_server = this->router; + } MYINFO("DNS SERVER: \t%s", this->dns_server.str().c_str()); // we can accept the offer now by requesting the IP! @@ -396,19 +396,19 @@ namespace net // set our onRead function to point to a hopeful DHCP ACK! sock.onRead( - [this] (Socket&, IP4::addr addr, UDP::port_t port, - const char* data, int len) -> int - { - (void) addr; - if (port == DHCP_DEST_PORT) - { - // we have hopefully got a DHCP Ack - debug("\tReceived DHCP ACK from %s:%d\n", - addr.str().c_str(), DHCP_DEST_PORT); - this->acknowledge(data, len); - } - return -1; - }); + [this] (Socket&, IP4::addr addr, UDP::port_t port, + const char* data, int len) -> int + { + (void) addr; + if (port == DHCP_DEST_PORT) + { + // we have hopefully got a DHCP Ack + debug("\tReceived DHCP ACK from %s:%d\n", + addr.str().c_str(), DHCP_DEST_PORT); + this->acknowledge(data, len); + } + return -1; + }); // send our DHCP Request sock.bcast(IP4::INADDR_ANY, DHCP_DEST_PORT, packet, packetlen); @@ -428,14 +428,14 @@ namespace net opt = get_option(dhcp->options, DHO_DHCP_MESSAGE_TYPE); if (opt->code == DHO_DHCP_MESSAGE_TYPE) - { - // verify that the type is indeed DHCPOFFER - debug("\tFound DHCP message type %d (DHCP Ack = %d)\n", - opt->val[0], DHCPACK); + { + // verify that the type is indeed DHCPOFFER + debug("\tFound DHCP message type %d (DHCP Ack = %d)\n", + opt->val[0], DHCPACK); - // ignore when not a DHCP Offer - if (opt->val[0] != DHCPACK) return; - } + // ignore when not a DHCP Offer + if (opt->val[0] != DHCPACK) return; + } // ignore message when DHCP message type is missing else return; diff --git a/src/net/dns/client.cpp b/src/net/dns/client.cpp index 3b8fffa4fb..d17d9d570b 100644 --- a/src/net/dns/client.cpp +++ b/src/net/dns/client.cpp @@ -39,14 +39,14 @@ namespace net // wait for response // FIXME: WE DO NOT CHECK TRANSACTION IDS HERE (yet), GOD HELP US ALL sock.onRead( [this, hostname, request, func] - (Socket&, IP4::addr, UDP::port_t, const char* data, int) mutable -> int - { - // original request ID = this->id; - request.parseResponse(data); + (Socket&, IP4::addr, UDP::port_t, const char* data, int) mutable -> int + { + // original request ID = this->id; + request.parseResponse(data); - // fire onResolve event - func(this->stack, hostname, request.getFirstIP4()); - return -1; - }); + // fire onResolve event + func(this->stack, hostname, request.getFirstIP4()); + return -1; + }); } } diff --git a/src/net/dns/dns.cpp b/src/net/dns/dns.cpp index a1e6a39537..56f28e6c0d 100644 --- a/src/net/dns/dns.cpp +++ b/src/net/dns/dns.cpp @@ -32,12 +32,12 @@ namespace net std::string resp; while (*(tmp)!=0) - { - int len = *tmp++; - resp.append((char*) tmp, len); - resp.append("."); - tmp += len; - } + { + int len = *tmp++; + resp.append((char*) tmp, len); + resp.append("."); + tmp += len; + } return resp; } @@ -79,7 +79,7 @@ namespace net // initial response size unsigned short packetlen = sizeof(header) + - sizeof(question) + parsed_query.size() + 1; + sizeof(question) + parsed_query.size() + 1; // set DNS QR to RESPONSE hdr.qr = DNS_QR_RESPONSE; @@ -91,45 +91,45 @@ namespace net std::vector* addrs = lookup(parsed_query); if (addrs == nullptr) - { - // not found - debug("*** Could not find: %s", parsed_query.c_str()); - hdr.ans_count = 0; - hdr.rcode = DNS::NO_ERROR; - } + { + // not found + debug("*** Could not find: %s", parsed_query.c_str()); + hdr.ans_count = 0; + hdr.rcode = DNS::NO_ERROR; + } else - { - debug("*** Found %lu results for %s", addrs->size(), parsed_query.c_str()); - // append answers - for (auto addr : *addrs) { - debug("*** Result: %s", addr.str().c_str()); - // add query - int qlen = parsed_query.size() + 1; - memcpy(buffer, query, qlen); - buffer += qlen; - packetlen += qlen; // (!) + debug("*** Found %lu results for %s", addrs->size(), parsed_query.c_str()); + // append answers + for (auto addr : *addrs) + { + debug("*** Result: %s", addr.str().c_str()); + // add query + int qlen = parsed_query.size() + 1; + memcpy(buffer, query, qlen); + buffer += qlen; + packetlen += qlen; // (!) - // add resource record - rr_data* data = (rr_data*) buffer; + // add resource record + rr_data* data = (rr_data*) buffer; - data->type = htons(DNS_TYPE_A); - data->_class = htons(DNS_CLASS_INET); - data->ttl = htons(0x7FFF); // just because - data->data_len = htons(sizeof(IP4::addr)); - buffer += sizeof(rr_data); + data->type = htons(DNS_TYPE_A); + data->_class = htons(DNS_CLASS_INET); + data->ttl = htons(0x7FFF); // just because + data->data_len = htons(sizeof(IP4::addr)); + buffer += sizeof(rr_data); - // add resource itself - *((IP4::addr*) buffer) = addr; // IPv4 address - buffer += sizeof(IP4::addr); + // add resource itself + *((IP4::addr*) buffer) = addr; // IPv4 address + buffer += sizeof(IP4::addr); - packetlen += sizeof(rr_data) + sizeof(IP4::addr); // (!) - } // addr + packetlen += sizeof(rr_data) + sizeof(IP4::addr); // (!) + } // addr - // set dns header answer count (!) - hdr.ans_count = htons((addrs->size() & 0xFFFF)); - hdr.rcode = DNS::NO_ERROR; - } + // set dns header answer count (!) + hdr.ans_count = htons((addrs->size() & 0xFFFF)); + hdr.rcode = DNS::NO_ERROR; + } return packetlen; } @@ -160,7 +160,7 @@ namespace net dns->auth_count = 0; dns->add_count = 0; - // point to the query portion + // point to the query portion char* qname = buffer + sizeof(DNS::header); // convert host to dns name format @@ -197,7 +197,7 @@ namespace net for (int i = 0; i < ntohs(dns->auth_count); i++) auth.emplace_back(reader, buffer); - // parse additional + // parse additional for (int i = 0; i < ntohs(dns->add_count); i++) addit.emplace_back(reader, buffer); @@ -231,24 +231,24 @@ namespace net // convert www.google.com to 3www6google3com void DNS::Request::dnsNameFormat(char* dns) { - int lock = 0; + int lock = 0; - std::string copy = this->hostname + "."; - int len = copy.size(); + std::string copy = this->hostname + "."; + int len = copy.size(); - for(int i = 0; i < len; i++) + for(int i = 0; i < len; i++) { - if (copy[i] == '.') + if (copy[i] == '.') { - *dns++ = i - lock; - for(; lock < i; lock++) + *dns++ = i - lock; + for(; lock < i; lock++) { - *dns++ = copy[lock]; + *dns++ = copy[lock]; } - lock++; + lock++; } } - *dns++ = '\0'; + *dns++ = '\0'; } DNS::Request::rr_t::rr_t(const char*& reader, const char* buffer) @@ -263,54 +263,54 @@ namespace net // if its an ipv4 address if (ntohs(resource.type) == DNS_TYPE_A) - { - int len = ntohs(resource.data_len); + { + int len = ntohs(resource.data_len); - this->rdata = std::string(reader, len); - reader += len; - } + this->rdata = std::string(reader, len); + reader += len; + } else - { - this->rdata = readName(reader, buffer, stop); - reader += stop; - } + { + this->rdata = readName(reader, buffer, stop); + reader += stop; + } } IP4::addr DNS::Request::rr_t::getIP4() const { switch (ntohs(resource.type)) - { - case DNS_TYPE_A: - { - IP4::addr* addr = (IP4::addr*) rdata.c_str(); - return *addr; - } - case DNS_TYPE_ALIAS: - case DNS_TYPE_NS: - default: - return IP4::addr{{0}}; - } + { + case DNS_TYPE_A: + { + IP4::addr* addr = (IP4::addr*) rdata.c_str(); + return *addr; + } + case DNS_TYPE_ALIAS: + case DNS_TYPE_NS: + default: + return IP4::addr{{0}}; + } } void DNS::Request::rr_t::print() { printf("Name: %s ", name.c_str()); switch (ntohs(resource.type)) - { - case DNS_TYPE_A: { - IP4::addr* addr = (IP4::addr*) rdata.c_str(); - printf("has IPv4 address: %s", addr->str().c_str()); + case DNS_TYPE_A: + { + IP4::addr* addr = (IP4::addr*) rdata.c_str(); + printf("has IPv4 address: %s", addr->str().c_str()); + } + break; + case DNS_TYPE_ALIAS: + printf("has alias: %s", rdata.c_str()); + break; + case DNS_TYPE_NS: + printf("has authoritative nameserver : %s", rdata.c_str()); + break; + default: + printf("has unknown resource type: %d", ntohs(resource.type)); } - break; - case DNS_TYPE_ALIAS: - printf("has alias: %s", rdata.c_str()); - break; - case DNS_TYPE_NS: - printf("has authoritative nameserver : %s", rdata.c_str()); - break; - default: - printf("has unknown resource type: %d", ntohs(resource.type)); - } printf("\n"); } @@ -325,22 +325,22 @@ namespace net unsigned char* ureader = (unsigned char*) reader; while (*ureader) - { - if (*ureader >= 192) - { - offset = (*ureader) * 256 + *(ureader+1) - 49152; // = 11000000 00000000 - ureader = (unsigned char*) buffer + offset - 1; - jumped = true; // we have jumped to another location so counting wont go up! - } - else { - name[p++] = *ureader; - } - ureader++; + if (*ureader >= 192) + { + offset = (*ureader) * 256 + *(ureader+1) - 49152; // = 11000000 00000000 + ureader = (unsigned char*) buffer + offset - 1; + jumped = true; // we have jumped to another location so counting wont go up! + } + else + { + name[p++] = *ureader; + } + ureader++; - // if we havent jumped to another location then we can count up - if (jumped == false) count++; - } + // if we havent jumped to another location then we can count up + if (jumped == false) count++; + } name.resize(p); // number of steps we actually moved forward in the packet @@ -351,16 +351,16 @@ namespace net int len = p; // same as name.size() int i; for(i = 0; i < len; i++) - { - p = name[i]; - - for(unsigned j = 0; j < p; j++) { - name[i] = name[i+1]; - i++; + p = name[i]; + + for(unsigned j = 0; j < p; j++) + { + name[i] = name[i+1]; + i++; + } + name[i] = '.'; } - name[i] = '.'; - } name[i - 1] = '\0'; // remove the last dot return name; diff --git a/src/net/ethernet.cpp b/src/net/ethernet.cpp index 42dc4aaf28..75af7441e2 100644 --- a/src/net/ethernet.cpp +++ b/src/net/ethernet.cpp @@ -26,90 +26,90 @@ namespace net { -// uint16_t(0x0000), uint32_t(0x01000000) -const Ethernet::addr Ethernet::addr::MULTICAST_FRAME {{0,0,0x01,0,0,0}}; + // uint16_t(0x0000), uint32_t(0x01000000) + const Ethernet::addr Ethernet::addr::MULTICAST_FRAME {{0,0,0x01,0,0,0}}; -// uint16_t(0xFFFF), uint32_t(0xFFFFFFFF) -const Ethernet::addr Ethernet::addr::BROADCAST_FRAME {{0xff,0xff,0xff,0xff,0xff,0xff}}; + // uint16_t(0xFFFF), uint32_t(0xFFFFFFFF) + const Ethernet::addr Ethernet::addr::BROADCAST_FRAME {{0xff,0xff,0xff,0xff,0xff,0xff}}; -// uint16_t(0x3333), uint32_t(0x01000000) -const Ethernet::addr Ethernet::addr::IPv6mcast_01 {{0x33,0x33,0x01,0,0,0}}; + // uint16_t(0x3333), uint32_t(0x01000000) + const Ethernet::addr Ethernet::addr::IPv6mcast_01 {{0x33,0x33,0x01,0,0,0}}; -// uint16_t(0x3333), uint32_t(0x02000000) -const Ethernet::addr Ethernet::addr::IPv6mcast_02 {{0x33,0x33,0x02,0,0,0}}; + // uint16_t(0x3333), uint32_t(0x02000000) + const Ethernet::addr Ethernet::addr::IPv6mcast_02 {{0x33,0x33,0x02,0,0,0}}; -static void ignore(Packet_ptr UNUSED(pckt)) noexcept { - debug(" Ignoring data (no real handler)\n"); -} + static void ignore(Packet_ptr UNUSED(pckt)) noexcept { + debug(" Ignoring data (no real handler)\n"); + } -Ethernet::Ethernet(addr mac) noexcept + Ethernet::Ethernet(addr mac) noexcept : mac_(mac), ip4_handler_{ignore}, ip6_handler_{ignore}, arp_handler_{ignore} {} -void Ethernet::transmit(Packet_ptr pckt) { - header* hdr = reinterpret_cast(pckt->buffer()); - - // Verify ethernet header - assert(hdr->dest.major != 0 || hdr->dest.minor !=0); - assert(hdr->type != 0); - - // Add source address - hdr->src = mac_; - - debug2(" Transmitting %i b, from %s -> %s. Type: %i\n", - pckt->size(), mac_.str().c_str(), hdr->dest.str().c_str(), hdr->type); - - physical_out_(pckt); -} + void Ethernet::transmit(Packet_ptr pckt) { + header* hdr = reinterpret_cast(pckt->buffer()); -void Ethernet::bottom(Packet_ptr pckt) { - assert(pckt->size() > 0); + // Verify ethernet header + assert(hdr->dest.major != 0 || hdr->dest.minor !=0); + assert(hdr->type != 0); - header* eth = reinterpret_cast(pckt->buffer()); + // Add source address + hdr->src = mac_; - /** Do we pass on ethernet headers? As for now, yes. - data += sizeof(header); - len -= sizeof(header); - */ - debug2(" %s => %s , Eth.type: 0x%x ", - eth->src.str().c_str(), eth->dest.str().c_str(), eth->type); + debug2(" Transmitting %i b, from %s -> %s. Type: %i\n", + pckt->size(), mac_.str().c_str(), hdr->dest.str().c_str(), hdr->type); - switch(eth->type) { - case ETH_IP4: - debug2("IPv4 packet\n"); - ip4_handler_(pckt); - break; - - case ETH_IP6: - debug2("IPv6 packet\n"); - ip6_handler_(pckt); - break; - - case ETH_ARP: - debug2("ARP packet\n"); - arp_handler_(pckt); - break; - - case ETH_WOL: - debug2("Wake-on-LAN packet\n"); - break; - - case ETH_VLAN: - debug("VLAN tagged frame (not yet supported)"); - break; + physical_out_(pckt); + } - default: - // This might be 802.3 LLC traffic - if (net::ntohs(eth->type) > 1500) { - debug(" UNKNOWN ethertype 0x%x\n", ntohs(eth->type)); - }else { - debug2("IEEE802.3 Length field: 0x%x\n", ntohs(eth->type)); + void Ethernet::bottom(Packet_ptr pckt) { + assert(pckt->size() > 0); + + header* eth = reinterpret_cast(pckt->buffer()); + + /** Do we pass on ethernet headers? As for now, yes. + data += sizeof(header); + len -= sizeof(header); + */ + debug2(" %s => %s , Eth.type: 0x%x ", + eth->src.str().c_str(), eth->dest.str().c_str(), eth->type); + + switch(eth->type) { + case ETH_IP4: + debug2("IPv4 packet\n"); + ip4_handler_(pckt); + break; + + case ETH_IP6: + debug2("IPv6 packet\n"); + ip6_handler_(pckt); + break; + + case ETH_ARP: + debug2("ARP packet\n"); + arp_handler_(pckt); + break; + + case ETH_WOL: + debug2("Wake-on-LAN packet\n"); + break; + + case ETH_VLAN: + debug("VLAN tagged frame (not yet supported)"); + break; + + default: + // This might be 802.3 LLC traffic + if (net::ntohs(eth->type) > 1500) { + debug(" UNKNOWN ethertype 0x%x\n", ntohs(eth->type)); + }else { + debug2("IEEE802.3 Length field: 0x%x\n", ntohs(eth->type)); + } + break; } - break; } -} } // namespace net diff --git a/src/net/inet.cpp b/src/net/inet.cpp index a22428e9e3..760c9a2931 100644 --- a/src/net/inet.cpp +++ b/src/net/inet.cpp @@ -22,10 +22,10 @@ namespace net { Inet::Inet() : - //_eth(eth0.mac()),_arp(eth0.mac(),ip) - _ip4(_ip4_list[0],_netmask_list[0]), _udp(_ip4_list[0]), - _ip6(_ip6_list[0]), - _icmp6(_ip6_list[0]), _udp6(_ip6_list[0]) + //_eth(eth0.mac()),_arp(eth0.mac(),ip) + _ip4(_ip4_list[0],_netmask_list[0]), _udp(_ip4_list[0]), + _ip6(_ip6_list[0]), + _icmp6(_ip6_list[0]), _udp6(_ip6_list[0]) { // For now we're just using the one interface auto& eth0 = Dev::eth<0,VirtioNet>(); diff --git a/src/net/inet_common.cpp b/src/net/inet_common.cpp index e5b135f7d5..e96efc4a44 100644 --- a/src/net/inet_common.cpp +++ b/src/net/inet_common.cpp @@ -23,27 +23,27 @@ namespace net { -// Should be pretty much like the example in RFC 1071, -// but using a uinon for readability -uint16_t checksum(void* data, size_t len) noexcept { + // Should be pretty much like the example in RFC 1071, + // but using a uinon for readability + uint16_t checksum(void* data, size_t len) noexcept { - uint16_t* buf = reinterpret_cast(data); + uint16_t* buf = reinterpret_cast(data); - union sum { - uint32_t whole; - uint16_t part[2]; - } sum32 {0}; + union sum { + uint32_t whole; + uint16_t part[2]; + } sum32 {0}; - // Iterate in short int steps. - for (uint16_t* i = buf; i < (buf + len / 2); ++i) - sum32.whole += *i; + // Iterate in short int steps. + for (uint16_t* i = buf; i < (buf + len / 2); ++i) + sum32.whole += *i; - // odd-length case - if (len & 1) { - sum32.whole += reinterpret_cast(buf)[len - 1]; - } + // odd-length case + if (len & 1) { + sum32.whole += reinterpret_cast(buf)[len - 1]; + } - return ~(sum32.part[0] + sum32.part[1]); -} + return ~(sum32.part[0] + sum32.part[1]); + } } //< namespace net diff --git a/src/net/ip4.cpp b/src/net/ip4.cpp index 537e8da023..ad962b5ba0 100644 --- a/src/net/ip4.cpp +++ b/src/net/ip4.cpp @@ -24,10 +24,10 @@ namespace net { -const IP4::addr IP4::INADDR_ANY {{0,0,0,0}}; -const IP4::addr IP4::INADDR_BCAST {{0xff,0xff,0xff,0xff}}; + const IP4::addr IP4::INADDR_ANY {{0,0,0,0}}; + const IP4::addr IP4::INADDR_BCAST {{0xff,0xff,0xff,0xff}}; -IP4::IP4(Inet& inet) noexcept: + IP4::IP4(Inet& inet) noexcept: stack_{inet} { // Default gateway is addr 1 in the subnet. @@ -35,79 +35,79 @@ IP4::IP4(Inet& inet) noexcept: // gateway_.whole = (local_ip_.whole & netmask_.whole) | DEFAULT_GATEWAY; } -void IP4::bottom(Packet_ptr pckt) { - debug2(" got the data.\n"); + void IP4::bottom(Packet_ptr pckt) { + debug2(" got the data.\n"); - auto data = pckt->buffer(); - ip_header* hdr = &reinterpret_cast(data)->ip_hdr; + auto data = pckt->buffer(); + ip_header* hdr = &reinterpret_cast(data)->ip_hdr; - debug2("\t Source IP: %s Dest.IP: %s\n", - hdr->saddr.str().c_str(), hdr->daddr.str().c_str()); + debug2("\t Source IP: %s Dest.IP: %s\n", + hdr->saddr.str().c_str(), hdr->daddr.str().c_str()); - switch(hdr->protocol){ - case IP4_ICMP: - debug2("\t Type: ICMP\n"); - icmp_handler_(pckt); - break; - case IP4_UDP: - debug2("\t Type: UDP\n"); - udp_handler_(pckt); - break; - case IP4_TCP: - tcp_handler_(pckt); - debug2("\t Type: TCP\n"); - break; - default: - debug("\t Type: UNKNOWN %i\n", hdr->protocol); - break; + switch(hdr->protocol){ + case IP4_ICMP: + debug2("\t Type: ICMP\n"); + icmp_handler_(pckt); + break; + case IP4_UDP: + debug2("\t Type: UDP\n"); + udp_handler_(pckt); + break; + case IP4_TCP: + tcp_handler_(pckt); + debug2("\t Type: TCP\n"); + break; + default: + debug("\t Type: UNKNOWN %i\n", hdr->protocol); + break; + } } -} -uint16_t IP4::checksum(ip_header* hdr) { - return net::checksum(reinterpret_cast(hdr), sizeof(ip_header)); -} + uint16_t IP4::checksum(ip_header* hdr) { + return net::checksum(reinterpret_cast(hdr), sizeof(ip_header)); + } -void IP4::transmit(Packet_ptr pckt) { - assert(pckt->size() > sizeof(IP4::full_header)); + void IP4::transmit(Packet_ptr pckt) { + assert(pckt->size() > sizeof(IP4::full_header)); - full_header* full_hdr = reinterpret_cast(pckt->buffer()); - ip_header* hdr = &full_hdr->ip_hdr; + full_header* full_hdr = reinterpret_cast(pckt->buffer()); + ip_header* hdr = &full_hdr->ip_hdr; - auto ip4_pckt = std::static_pointer_cast(pckt); - ip4_pckt->make_flight_ready(); + auto ip4_pckt = std::static_pointer_cast(pckt); + ip4_pckt->make_flight_ready(); - // Create local and target subnets - addr target, local; - target.whole = hdr->daddr.whole & stack_.netmask().whole; - local.whole = stack_.ip_addr().whole & stack_.netmask().whole; + // Create local and target subnets + addr target, local; + target.whole = hdr->daddr.whole & stack_.netmask().whole; + local.whole = stack_.ip_addr().whole & stack_.netmask().whole; - // Compare subnets to know where to send packet - pckt->next_hop(target == local ? hdr->daddr : stack_.router()); + // Compare subnets to know where to send packet + pckt->next_hop(target == local ? hdr->daddr : stack_.router()); - debug(" Next hop for %s, (netmask %s, local IP: %s, gateway: %s) == %s\n", - hdr->daddr.str().c_str(), - stack_.netmask().str().c_str(), - stack_.ip_addr().str().c_str(), - stack_.router().str().c_str(), - target == local ? "DIRECT" : "GATEWAY"); + debug(" Next hop for %s, (netmask %s, local IP: %s, gateway: %s) == %s\n", + hdr->daddr.str().c_str(), + stack_.netmask().str().c_str(), + stack_.ip_addr().str().c_str(), + stack_.router().str().c_str(), + target == local ? "DIRECT" : "GATEWAY"); - debug(" my ip: %s, Next hop: %s, Packet size: %i IP4-size: %i\n", - stack_.ip_addr().str().c_str(), - pckt->next_hop().str().c_str(), - pckt->size(), - ip4_pckt->ip4_segment_size() - ); + debug(" my ip: %s, Next hop: %s, Packet size: %i IP4-size: %i\n", + stack_.ip_addr().str().c_str(), + pckt->next_hop().str().c_str(), + pckt->size(), + ip4_pckt->ip4_segment_size() + ); - linklayer_out_(pckt); -} + linklayer_out_(pckt); + } -// Empty handler for delegates initialization -void ignore_ip4_up(Packet_ptr UNUSED(pckt)) { - debug(" Empty handler. Ignoring.\n"); -} + // Empty handler for delegates initialization + void ignore_ip4_up(Packet_ptr UNUSED(pckt)) { + debug(" Empty handler. Ignoring.\n"); + } -void ignore_ip4_down(Packet_ptr UNUSED(pckt)) { - debug("Link layer> No handler - DROP!\n"); -} + void ignore_ip4_down(Packet_ptr UNUSED(pckt)) { + debug("Link layer> No handler - DROP!\n"); + } } //< namespace net diff --git a/src/net/ip4/icmpv4.cpp b/src/net/ip4/icmpv4.cpp index 5a7b4a113f..3f9e897135 100644 --- a/src/net/ip4/icmpv4.cpp +++ b/src/net/ip4/icmpv4.cpp @@ -24,68 +24,68 @@ namespace net { -ICMPv4::ICMPv4(Inet& inet) : - inet_{inet} + ICMPv4::ICMPv4(Inet& inet) : + inet_{inet} {} -void ICMPv4::bottom(Packet_ptr pckt) { - if (pckt->size() < sizeof(full_header)) // Drop if not a full header - return; + void ICMPv4::bottom(Packet_ptr pckt) { + if (pckt->size() < sizeof(full_header)) // Drop if not a full header + return; - full_header* full_hdr = reinterpret_cast(pckt->buffer()); - icmp_header* hdr = &full_hdr->icmp_hdr; + full_header* full_hdr = reinterpret_cast(pckt->buffer()); + icmp_header* hdr = &full_hdr->icmp_hdr; #ifdef DEBUG - auto ip_address = full_hdr->ip_hdr.saddr.str().c_str(); + auto ip_address = full_hdr->ip_hdr.saddr.str().c_str(); #endif - switch(hdr->type) { - case (ICMP_ECHO): - debug(" PING from %s\n", ip_address); - ping_reply(full_hdr, pckt->size()); - break; - case (ICMP_ECHO_REPLY): - debug(" PING Reply from %s\n", ip_address); - break; + switch(hdr->type) { + case (ICMP_ECHO): + debug(" PING from %s\n", ip_address); + ping_reply(full_hdr, pckt->size()); + break; + case (ICMP_ECHO_REPLY): + debug(" PING Reply from %s\n", ip_address); + break; + } } -} -void ICMPv4::ping_reply(full_header* full_hdr, uint16_t size) { - auto packet_ptr = inet_.createPacket(size); - auto buf = packet_ptr->buffer(); + void ICMPv4::ping_reply(full_header* full_hdr, uint16_t size) { + auto packet_ptr = inet_.createPacket(size); + auto buf = packet_ptr->buffer(); - icmp_header* hdr = &reinterpret_cast(buf)->icmp_hdr; - hdr->type = ICMP_ECHO_REPLY; - hdr->code = 0; - hdr->identifier = full_hdr->icmp_hdr.identifier; - hdr->sequence = full_hdr->icmp_hdr.sequence; + icmp_header* hdr = &reinterpret_cast(buf)->icmp_hdr; + hdr->type = ICMP_ECHO_REPLY; + hdr->code = 0; + hdr->identifier = full_hdr->icmp_hdr.identifier; + hdr->sequence = full_hdr->icmp_hdr.sequence; - debug(" Rest of header IN: 0x%lx OUT: 0x%lx\n", - full_hdr->icmp_hdr.rest, hdr->rest); + debug(" Rest of header IN: 0x%lx OUT: 0x%lx\n", + full_hdr->icmp_hdr.rest, hdr->rest); - debug(" Transmitting answer\n"); + debug(" Transmitting answer\n"); - // Populate response IP header - auto ip4_pckt = std::static_pointer_cast(packet_ptr); - ip4_pckt->init(); - ip4_pckt->set_src(full_hdr->ip_hdr.daddr); - ip4_pckt->set_dst(full_hdr->ip_hdr.saddr); - ip4_pckt->set_protocol(IP4::IP4_ICMP); + // Populate response IP header + auto ip4_pckt = std::static_pointer_cast(packet_ptr); + ip4_pckt->init(); + ip4_pckt->set_src(full_hdr->ip_hdr.daddr); + ip4_pckt->set_dst(full_hdr->ip_hdr.saddr); + ip4_pckt->set_protocol(IP4::IP4_ICMP); - // Copy payload from old to new packet - uint8_t* payload = reinterpret_cast(hdr) + sizeof(icmp_header); - uint8_t* source = reinterpret_cast(&full_hdr->icmp_hdr) + sizeof(icmp_header); - memcpy(payload, source, size - sizeof(full_header)); + // Copy payload from old to new packet + uint8_t* payload = reinterpret_cast(hdr) + sizeof(icmp_header); + uint8_t* source = reinterpret_cast(&full_hdr->icmp_hdr) + sizeof(icmp_header); + memcpy(payload, source, size - sizeof(full_header)); - hdr->checksum = 0; - hdr->checksum = net::checksum(reinterpret_cast(hdr), - size - sizeof(full_header) + sizeof(icmp_header)); + hdr->checksum = 0; + hdr->checksum = net::checksum(reinterpret_cast(hdr), + size - sizeof(full_header) + sizeof(icmp_header)); - network_layer_out_(packet_ptr); -} + network_layer_out_(packet_ptr); + } -void icmp_default_out(Packet_ptr UNUSED(pckt)) { - debug(" No handler. DROP!\n"); -} + void icmp_default_out(Packet_ptr UNUSED(pckt)) { + debug(" No handler. DROP!\n"); + } } //< namespace net diff --git a/src/net/ip4/udp.cpp b/src/net/ip4/udp.cpp index 7ef9208f86..9517873299 100644 --- a/src/net/ip4/udp.cpp +++ b/src/net/ip4/udp.cpp @@ -23,70 +23,70 @@ namespace net { -void UDP::bottom(Packet_ptr pckt) -{ - debug(" Got data"); - std::shared_ptr udp = + void UDP::bottom(Packet_ptr pckt) + { + debug(" Got data"); + std::shared_ptr udp = std::static_pointer_cast (pckt); - debug("\t Source port: %i, Dest. Port: %i Length: %i\n", - udp->src_port(), udp->dst_port(), udp->length()); + debug("\t Source port: %i, Dest. Port: %i Length: %i\n", + udp->src_port(), udp->dst_port(), udp->length()); - auto it = ports_.find(udp->dst_port()); - if (it != ports_.end()) - { - debug(" Someone's listening to this port. Forwarding...\n"); - it->second.internal_read(udp); - } + auto it = ports_.find(udp->dst_port()); + if (it != ports_.end()) + { + debug(" Someone's listening to this port. Forwarding...\n"); + it->second.internal_read(udp); + } - debug(" Nobody's listening to this port. Drop!\n"); -} + debug(" Nobody's listening to this port. Drop!\n"); + } -UDP::Socket& UDP::bind(UDP::port_t port) -{ - debug(" Binding to port %i\n", port); - /// ... !!! - auto it = ports_.find(port); - if (it == ports_.end()) { - // create new socket - auto res = ports_.emplace( - std::piecewise_construct, - std::forward_as_tuple(port), - std::forward_as_tuple(stack_, port)); - it = res.first; + UDP::Socket& UDP::bind(UDP::port_t port) + { + debug(" Binding to port %i\n", port); + /// ... !!! + auto it = ports_.find(port); + if (it == ports_.end()) { + // create new socket + auto res = ports_.emplace( + std::piecewise_construct, + std::forward_as_tuple(port), + std::forward_as_tuple(stack_, port)); + it = res.first; + } + return it->second; } - return it->second; -} -UDP::Socket& UDP::bind() { + UDP::Socket& UDP::bind() { - if (ports_.size() >= 0xfc00) - panic("UPD Socket: All ports taken!"); + if (ports_.size() >= 0xfc00) + panic("UPD Socket: All ports taken!"); - debug("UDP finding free ephemeral port\n"); - while (ports_.find(++current_port_) != ports_.end()) - if (current_port_ == 0) current_port_ = 1025; // prevent automatic ports under 1024 + debug("UDP finding free ephemeral port\n"); + while (ports_.find(++current_port_) != ports_.end()) + if (current_port_ == 0) current_port_ = 1025; // prevent automatic ports under 1024 - debug("UDP binding to %i port\n", current_port_); - return bind(current_port_); -} + debug("UDP binding to %i port\n", current_port_); + return bind(current_port_); + } -void UDP::transmit(std::shared_ptr udp) { - debug2(" Transmitting %i bytes (seg=%i) from %s to %s:%i\n", - udp->length(), udp->ip4_segment_size(), - udp->src().str().c_str(), - udp->dst().str().c_str(), udp->dst_port()); + void UDP::transmit(std::shared_ptr udp) { + debug2(" Transmitting %i bytes (seg=%i) from %s to %s:%i\n", + udp->length(), udp->ip4_segment_size(), + udp->src().str().c_str(), + udp->dst().str().c_str(), udp->dst_port()); - assert(udp->length() >= sizeof(UDP::udp_header)); - assert(udp->protocol() == IP4::IP4_UDP); + assert(udp->length() >= sizeof(UDP::udp_header)); + assert(udp->protocol() == IP4::IP4_UDP); - Packet_ptr pckt = Packet::packet(udp); - network_layer_out_(pckt); -} + Packet_ptr pckt = Packet::packet(udp); + network_layer_out_(pckt); + } -void ignore_udp(Packet_ptr) -{ - debug("Network> No handler - DROP!\n"); -} + void ignore_udp(Packet_ptr) + { + debug("Network> No handler - DROP!\n"); + } } //< namespace net diff --git a/src/net/ip4/udp_socket.cpp b/src/net/ip4/udp_socket.cpp index 46ebfbc8fd..a5eea02023 100644 --- a/src/net/ip4/udp_socket.cpp +++ b/src/net/ip4/udp_socket.cpp @@ -29,7 +29,7 @@ namespace net } void Socket::packet_init(std::shared_ptr p, - addr srcIP, addr destIP, port port, uint16_t length) + addr srcIP, addr destIP, port port, uint16_t length) { p->init(); p->header().sport = htons(this->l_port); @@ -42,7 +42,7 @@ namespace net } int Socket::internal_write(addr srcIP, addr destIP, - port port, const uint8_t* buffer, int length) + port port, const uint8_t* buffer, int length) { // the maximum we can write per packet: const int WRITE_MAX = stack.MTU() - PacketUDP::HEADERS_SIZE; @@ -50,47 +50,47 @@ namespace net int rem = length; while (rem >= WRITE_MAX) - { - // create some packet p (and convert it to PacketUDP) - auto p = stack.createPacket(stack.MTU()); - // fill buffer (at payload position) - memcpy(p->buffer() + PacketUDP::HEADERS_SIZE, buffer, WRITE_MAX); + { + // create some packet p (and convert it to PacketUDP) + auto p = stack.createPacket(stack.MTU()); + // fill buffer (at payload position) + memcpy(p->buffer() + PacketUDP::HEADERS_SIZE, buffer, WRITE_MAX); - // initialize packet with several infos - auto p2 = std::static_pointer_cast(p); - packet_init(p2, srcIP, destIP, port, WRITE_MAX); - // ship the packet - stack.udp().transmit(p2); + // initialize packet with several infos + auto p2 = std::static_pointer_cast(p); + packet_init(p2, srcIP, destIP, port, WRITE_MAX); + // ship the packet + stack.udp().transmit(p2); - // next buffer part - buffer += WRITE_MAX; rem -= WRITE_MAX; - } + // next buffer part + buffer += WRITE_MAX; rem -= WRITE_MAX; + } if (rem) - { - // copy remainder - size_t size = PacketUDP::HEADERS_SIZE + rem; + { + // copy remainder + size_t size = PacketUDP::HEADERS_SIZE + rem; - // create some packet p - auto p = stack.createPacket(size); - memcpy(p->buffer() + PacketUDP::HEADERS_SIZE, buffer, rem); + // create some packet p + auto p = stack.createPacket(size); + memcpy(p->buffer() + PacketUDP::HEADERS_SIZE, buffer, rem); - // initialize packet with several infos - auto p2 = std::static_pointer_cast(p); - packet_init(p2, srcIP, destIP, port, rem); - // ship the packet - stack.udp().transmit(p2); - } + // initialize packet with several infos + auto p2 = std::static_pointer_cast(p); + packet_init(p2, srcIP, destIP, port, rem); + // ship the packet + stack.udp().transmit(p2); + } return length; } // internal_write() int Socket::sendto(addr destIP, port port, - const void* buffer, int len) + const void* buffer, int len) { return internal_write(local_addr(), destIP, port, (const uint8_t*) buffer, len); } int Socket::bcast(addr srcIP, port port, - const void* buffer, int len) + const void* buffer, int len) { return internal_write(srcIP, IP4::INADDR_BCAST, port, (const uint8_t*) buffer, len); diff --git a/src/net/ip6/icmp6.cpp b/src/net/ip6/icmp6.cpp index b58907e3b1..f36c2e18da 100644 --- a/src/net/ip6/icmp6.cpp +++ b/src/net/ip6/icmp6.cpp @@ -44,92 +44,92 @@ namespace net std::string ICMPv6::code_string(uint8_t type, uint8_t code) { switch (type) - { - /// error codes /// - case 1: - /// delivery problems /// - switch (code) { - case 0: - return "No route to destination"; + /// error codes /// case 1: - return "Communication with dest administratively prohibited"; + /// delivery problems /// + switch (code) + { + case 0: + return "No route to destination"; + case 1: + return "Communication with dest administratively prohibited"; + case 2: + return "Beyond scope of source address"; + case 3: + return "Address unreachable"; + case 4: + return "Port unreachable"; + case 5: + return "Source address failed ingress/egress policy"; + case 6: + return "Reject route to destination"; + case 7: + return "Error in source routing header"; + default: + return "ERROR Invalid ICMP type"; + } case 2: - return "Beyond scope of source address"; + /// size problems /// + return "Packet too big"; + case 3: - return "Address unreachable"; + /// time problems /// + switch (code) + { + case 0: + return "Hop limit exceeded in traffic"; + case 1: + return "Fragment reassembly time exceeded"; + default: + return "ERROR Invalid ICMP code"; + } case 4: - return "Port unreachable"; - case 5: - return "Source address failed ingress/egress policy"; - case 6: - return "Reject route to destination"; - case 7: - return "Error in source routing header"; - default: - return "ERROR Invalid ICMP type"; - } - case 2: - /// size problems /// - return "Packet too big"; + /// parameter problems /// + switch (code) + { + case 0: + return "Erroneous header field"; + case 1: + return "Unrecognized next header"; + case 2: + return "Unrecognized IPv6 option"; + default: + return "ERROR Invalid ICMP code"; + } - case 3: - /// time problems /// - switch (code) - { - case 0: - return "Hop limit exceeded in traffic"; - case 1: - return "Fragment reassembly time exceeded"; - default: - return "ERROR Invalid ICMP code"; - } - case 4: - /// parameter problems /// - switch (code) - { - case 0: - return "Erroneous header field"; - case 1: - return "Unrecognized next header"; - case 2: - return "Unrecognized IPv6 option"; - default: - return "ERROR Invalid ICMP code"; - } - - /// echo feature /// - case ECHO_REQUEST: - return "Echo request"; - case ECHO_REPLY: - return "Echo reply"; + /// echo feature /// + case ECHO_REQUEST: + return "Echo request"; + case ECHO_REPLY: + return "Echo reply"; - /// multicast feature /// - case 130: - return "Multicast listener query"; - case 131: - return "Multicast listener report"; - case 132: - return "Multicast listener done"; + /// multicast feature /// + case 130: + return "Multicast listener query"; + case 131: + return "Multicast listener report"; + case 132: + return "Multicast listener done"; - /// neighbor discovery protocol /// - case ND_ROUTER_SOL: - return "NDP Router solicitation request"; - case ND_ROUTER_ADV: - return "NDP Router advertisement"; - case ND_NEIGHB_SOL: - return "NDP Neighbor solicitation request"; - case ND_NEIGHB_ADV: - return "NDP Neighbor advertisement"; - case ND_REDIRECT: - return "NDP Redirect message"; + /// neighbor discovery protocol /// + case ND_ROUTER_SOL: + return "NDP Router solicitation request"; + case ND_ROUTER_ADV: + return "NDP Router advertisement"; + case ND_NEIGHB_SOL: + return "NDP Neighbor solicitation request"; + case ND_NEIGHB_ADV: + return "NDP Neighbor advertisement"; + case ND_REDIRECT: + return "NDP Redirect message"; - case 143: - return "Multicast Listener Discovery (MLDv2) reports (RFC 3810)"; + case 143: + return "Multicast Listener Discovery (MLDv2) reports (RFC 3810)"; - default: - return "Unknown type: " + std::to_string((int) type); - } + default: + return "Unknown type: " + std::to_string((int) type); + } } int ICMPv6::bottom(Packet_ptr pckt) @@ -139,27 +139,27 @@ namespace net type_t type = icmp->type(); if (listeners.find(type) != listeners.end()) - { - return listeners[type](*this, icmp); - } + { + return listeners[type](*this, icmp); + } else - { - debug(">>> IPv6 -> ICMPv6 bottom (no handler installed)\n"); - debug("ICMPv6 type %d: %s\n", - (int) icmp->type(), code_string(icmp->type(), icmp->code()).c_str()); + { + debug(">>> IPv6 -> ICMPv6 bottom (no handler installed)\n"); + debug("ICMPv6 type %d: %s\n", + (int) icmp->type(), code_string(icmp->type(), icmp->code()).c_str()); - /* - // show correct checksum - intptr_t chksum = icmp->checksum(); - debug("ICMPv6 checksum: %p \n",(void*) chksum); + /* + // show correct checksum + intptr_t chksum = icmp->checksum(); + debug("ICMPv6 checksum: %p \n",(void*) chksum); - // show our recalculated checksum - icmp->header().checksum_ = 0; - chksum = checksum(icmp); - debug("ICMPv6 our estimate: %p \n", (void*) chksum ); - */ - return -1; - } + // show our recalculated checksum + icmp->header().checksum_ = 0; + chksum = checksum(icmp); + debug("ICMPv6 our estimate: %p \n", (void*) chksum ); + */ + return -1; + } } int ICMPv6::transmit(std::shared_ptr& pckt) { @@ -189,18 +189,18 @@ namespace net //assert(hdr.next() == 58); // ICMPv6 /** - RFC 4443 - 2.3. Message Checksum Calculation + RFC 4443 + 2.3. Message Checksum Calculation - The checksum is the 16-bit one's complement of the one's complement - sum of the entire ICMPv6 message, starting with the ICMPv6 message - type field, and prepended with a "pseudo-header" of IPv6 header - fields, as specified in [IPv6, Section 8.1]. The Next Header value - used in the pseudo-header is 58. (The inclusion of a pseudo-header - in the ICMPv6 checksum is a change from IPv4; see [IPv6] for the - rationale for this change.) + The checksum is the 16-bit one's complement of the one's complement + sum of the entire ICMPv6 message, starting with the ICMPv6 message + type field, and prepended with a "pseudo-header" of IPv6 header + fields, as specified in [IPv6, Section 8.1]. The Next Header value + used in the pseudo-header is 58. (The inclusion of a pseudo-header + in the ICMPv6 checksum is a change from IPv4; see [IPv6] for the + rationale for this change.) - For computing the checksum, the checksum field is first set to zero. + For computing the checksum, the checksum field is first set to zero. **/ union { @@ -214,7 +214,7 @@ namespace net uint16_t* it_end = it + sizeof(pseudo_header) / 2; while (it < it_end) - sum.whole += *(it++); + sum.whole += *(it++); // compute sum of data it = (uint16_t*) pckt->payload(); @@ -243,21 +243,21 @@ namespace net icmp->type = ICMPv6::ECHO_REPLY; if (pckt->dst().is_multicast()) - { - // We won't be changing source address for multicast ping - debug("Was multicast ping6: no change for source and dest\n"); - } + { + // We won't be changing source address for multicast ping + debug("Was multicast ping6: no change for source and dest\n"); + } else - { - printf("Normal ping6: source is us\n"); - printf("src is %s\n", pckt->src().str().c_str()); - printf("dst is %s\n", pckt->dst().str().c_str()); + { + printf("Normal ping6: source is us\n"); + printf("src is %s\n", pckt->src().str().c_str()); + printf("dst is %s\n", pckt->dst().str().c_str()); - printf("multicast is %s\n", IP6::addr::link_all_nodes.str().c_str()); - // normal ping: send packet to source, from us - pckt->set_dst(pckt->src()); - pckt->set_src(caller.local_ip()); - } + printf("multicast is %s\n", IP6::addr::link_all_nodes.str().c_str()); + // normal ping: send packet to source, from us + pckt->set_dst(pckt->src()); + pckt->set_src(caller.local_ip()); + } // calculate and set checksum // NOTE: do this after changing packet contents! icmp->checksum = 0; @@ -288,9 +288,9 @@ namespace net // ether-broadcast an IPv6 packet to all routers // IPv6mcast_02: 33:33:00:00:00:02 auto pckt = IP6::create( - IP6::PROTO_ICMPv6, - Ethernet::addr::IPv6mcast_02, - IP6::addr::link_unspecified); + IP6::PROTO_ICMPv6, + Ethernet::addr::IPv6mcast_02, + IP6::addr::link_unspecified); // RFC4861 4.1. Router Solicitation Message Format pckt->set_hoplimit(255); diff --git a/src/net/ip6/ip6.cpp b/src/net/ip6/ip6.cpp index 029f3657a3..8ff9de8e1d 100644 --- a/src/net/ip6/ip6.cpp +++ b/src/net/ip6/ip6.cpp @@ -47,35 +47,35 @@ namespace net uint8_t IP6::parse6(uint8_t*& reader, uint8_t next) { switch (next) - { - case PROTO_HOPOPT: - case PROTO_OPTSv6: - { - debug(">>> IPv6 options header %s", protocol_name(next).c_str()); + { + case PROTO_HOPOPT: + case PROTO_OPTSv6: + { + debug(">>> IPv6 options header %s", protocol_name(next).c_str()); - options_header& opts = *(options_header*) reader; - reader += opts.size(); + options_header& opts = *(options_header*) reader; + reader += opts.size(); - debug("OPTSv6 size: %d\n", opts.size()); - debug("OPTSv6 ext size: %d\n", opts.extended()); + debug("OPTSv6 size: %d\n", opts.size()); + debug("OPTSv6 ext size: %d\n", opts.extended()); - next = opts.next(); - debug("OPTSv6 next: %s\n", protocol_name(next).c_str()); - } break; - case PROTO_ICMPv6: - break; - case PROTO_UDP: - break; + next = opts.next(); + debug("OPTSv6 next: %s\n", protocol_name(next).c_str()); + } break; + case PROTO_ICMPv6: + break; + case PROTO_UDP: + break; - default: - debug("Not parsing: %s\n", protocol_name(next).c_str()); - } + default: + debug("Not parsing: %s\n", protocol_name(next).c_str()); + } return next; } - void IP6::bottom(Packet_ptr pckt) - { + void IP6::bottom(Packet_ptr pckt) + { debug(">>> IPv6 packet:"); @@ -92,20 +92,20 @@ namespace net uint8_t next = hdr.next(); while (next != PROTO_NoNext) - { - auto it = proto_handlers.find(next); - if (it != proto_handlers.end()) { - // forward packet to handler - pckt->set_payload(reader); - it->second(pckt); + auto it = proto_handlers.find(next); + if (it != proto_handlers.end()) + { + // forward packet to handler + pckt->set_payload(reader); + it->second(pckt); + } + else + // just print information + next = parse6(reader, next); } - else - // just print information - next = parse6(reader, next); - } - }; + }; static const std::string lut = "0123456789abcdef"; @@ -117,12 +117,12 @@ namespace net const uint8_t* octet = i8; for (int i = 0; i < 16; i++) - { - ret[counter++] = lut[(octet[i] & 0xF0) >> 4]; - ret[counter++] = lut[(octet[i] & 0x0F) >> 0]; - if (i & 1) - ret[counter++] = ':'; - } + { + ret[counter++] = lut[(octet[i] & 0xF0) >> 4]; + ret[counter++] = lut[(octet[i] & 0x0F) >> 0]; + if (i & 1) + ret[counter++] = ':'; + } ret.resize(counter-1); return ret; } @@ -138,7 +138,7 @@ namespace net } std::shared_ptr IP6::create(uint8_t proto, - Ethernet::addr ether_dest, const IP6::addr& ip6_dest) + Ethernet::addr ether_dest, const IP6::addr& ip6_dest) { // arbitrarily big buffer uint8_t* data = new uint8_t[1500]; diff --git a/src/net/ip6/udp6.cpp b/src/net/ip6/udp6.cpp index e89aaf33dd..550fa7aad4 100644 --- a/src/net/ip6/udp6.cpp +++ b/src/net/ip6/udp6.cpp @@ -35,10 +35,10 @@ namespace net // check for listeners on dst port if (listeners.find(port) != listeners.end()) - { - // make the call to the listener on that port - return listeners[port](P6); - } + { + // make the call to the listener on that port + return listeners[port](P6); + } // was not forwarded, so just return -1 debug("... dumping packet, no listeners\n"); return -1; @@ -83,7 +83,7 @@ namespace net // normally we would start at &icmp_echo::type, but // it is after all the first element of the icmp message memcpy(data + sizeof(UDPv6::pseudo_header), this->payload(), - datalen - sizeof(UDPv6::pseudo_header)); + datalen - sizeof(UDPv6::pseudo_header)); // calculate csum and free data on return header().chksum = net::checksum(data, datalen); @@ -91,7 +91,7 @@ namespace net } std::shared_ptr UDPv6::create( - Ethernet::addr ether_dest, const IP6::addr& ip6_dest, UDPv6::port_t port) + Ethernet::addr ether_dest, const IP6::addr& ip6_dest, UDPv6::port_t port) { auto packet = IP6::create(IP6::PROTO_UDP, ether_dest, ip6_dest); auto udp_packet = view_packet_as (packet); diff --git a/src/net/tcp.cpp b/src/net/tcp.cpp index adfe3165e5..96b0df8f81 100644 --- a/src/net/tcp.cpp +++ b/src/net/tcp.cpp @@ -24,218 +24,218 @@ using namespace net; TCP::TCP(IPStack& inet) : - inet_(inet), - listeners_(), - connections_(), - MAX_SEG_LIFETIME(30s) + inet_(inet), + listeners_(), + connections_(), + MAX_SEG_LIFETIME(30s) { } /* - Note: There is different approaches to how to handle listeners & connections. - Need to discuss and decide for the best one. + Note: There is different approaches to how to handle listeners & connections. + Need to discuss and decide for the best one. - Best solution(?): - Preallocate a pool with listening connections. - When threshold is reach, remove/add new ones, similar to TCP window. + Best solution(?): + Preallocate a pool with listening connections. + When threshold is reach, remove/add new ones, similar to TCP window. - Current solution: - Simple. + Current solution: + Simple. */ TCP::Connection& TCP::bind(Port port) { - auto listen_conn_it = listeners_.find(port); - // Already a listening socket. - if(listen_conn_it != listeners_.end()) { - throw TCPException{"Port is already taken."}; - } - auto& connection = (listeners_.emplace(port, Connection{*this, port})).first->second; - debug(" Bound to port %i \n", port); - connection.open(false); - return connection; + auto listen_conn_it = listeners_.find(port); + // Already a listening socket. + if(listen_conn_it != listeners_.end()) { + throw TCPException{"Port is already taken."}; + } + auto& connection = (listeners_.emplace(port, Connection{*this, port})).first->second; + debug(" Bound to port %i \n", port); + connection.open(false); + return connection; } /* - Active open a new connection to the given remote. + Active open a new connection to the given remote. - @WARNING: Callback is added when returned (TCP::connect(...).onSuccess(...)), - and open() is called before callback is added. + @WARNING: Callback is added when returned (TCP::connect(...).onSuccess(...)), + and open() is called before callback is added. */ TCP::Connection_ptr TCP::connect(Socket remote) { - std::shared_ptr connection = add_connection(free_port(), remote); - connection->open(true); - return connection; + std::shared_ptr connection = add_connection(free_port(), remote); + connection->open(true); + return connection; } /* - Active open a new connection to the given remote. + Active open a new connection to the given remote. */ void TCP::connect(Socket remote, Connection::ConnectCallback callback) { - auto connection = add_connection(free_port(), remote); - connection->onConnect(callback).open(true); + auto connection = add_connection(free_port(), remote); + connection->onConnect(callback).open(true); } TCP::Seq TCP::generate_iss() { - // Do something to get a iss. - return rand(); + // Do something to get a iss. + return rand(); } /* - TODO: Check if there is any ports free. + TODO: Check if there is any ports free. */ TCP::Port TCP::free_port() { - if(++current_ephemeral_ == 0) - current_ephemeral_ = 1025; - // Avoid giving a port that is bound to a service. - while(listeners_.find(current_ephemeral_) != listeners_.end()) - current_ephemeral_++; + if(++current_ephemeral_ == 0) + current_ephemeral_ = 1025; + // Avoid giving a port that is bound to a service. + while(listeners_.find(current_ephemeral_) != listeners_.end()) + current_ephemeral_++; - return current_ephemeral_; + return current_ephemeral_; } uint16_t TCP::checksum(TCP::Packet_ptr packet) { - // TCP header - TCP::Header* tcp_hdr = &(packet->header()); - // Pseudo header - TCP::Pseudo_header pseudo_hdr; - - int tcp_length = packet->tcp_length(); - - pseudo_hdr.saddr.whole = packet->src().whole; - pseudo_hdr.daddr.whole = packet->dst().whole; - pseudo_hdr.zero = 0; - pseudo_hdr.proto = IP4::IP4_TCP; - pseudo_hdr.tcp_length = htons(tcp_length); - - union { - uint32_t whole; - uint16_t part[2]; - } sum; - - sum.whole = 0; - - // Compute sum of pseudo header - for (uint16_t* it = (uint16_t*)&pseudo_hdr; it < (uint16_t*)&pseudo_hdr + sizeof(pseudo_hdr)/2; it++) - sum.whole += *it; - - // Compute sum sum the actual header and data - for (uint16_t* it = (uint16_t*)tcp_hdr; it < (uint16_t*)tcp_hdr + tcp_length/2; it++) - sum.whole+= *it; - - // The odd-numbered case - if (tcp_length & 1) { - debug(" ODD number of bytes. 0-pading \n"); - union { - uint16_t whole; - uint8_t part[2]; - } last_chunk; - last_chunk.part[0] = ((uint8_t*)tcp_hdr)[tcp_length - 1]; - last_chunk.part[1] = 0; - sum.whole += last_chunk.whole; - } - - debug2("header()); + // Pseudo header + TCP::Pseudo_header pseudo_hdr; + + int tcp_length = packet->tcp_length(); + + pseudo_hdr.saddr.whole = packet->src().whole; + pseudo_hdr.daddr.whole = packet->dst().whole; + pseudo_hdr.zero = 0; + pseudo_hdr.proto = IP4::IP4_TCP; + pseudo_hdr.tcp_length = htons(tcp_length); + + union { + uint32_t whole; + uint16_t part[2]; + } sum; + + sum.whole = 0; + + // Compute sum of pseudo header + for (uint16_t* it = (uint16_t*)&pseudo_hdr; it < (uint16_t*)&pseudo_hdr + sizeof(pseudo_hdr)/2; it++) + sum.whole += *it; + + // Compute sum sum the actual header and data + for (uint16_t* it = (uint16_t*)tcp_hdr; it < (uint16_t*)tcp_hdr + tcp_length/2; it++) + sum.whole+= *it; + + // The odd-numbered case + if (tcp_length & 1) { + debug(" ODD number of bytes. 0-pading \n"); + union { + uint16_t whole; + uint8_t part[2]; + } last_chunk; + last_chunk.part[0] = ((uint8_t*)tcp_hdr)[tcp_length - 1]; + last_chunk.part[1] = 0; + sum.whole += last_chunk.whole; + } + + debug2("(packet_ptr); - debug(" TCP Packet received - Source: %s, Destination: %s \n", - packet->source().to_string().c_str(), packet->destination().to_string().c_str()); + // Translate into a TCP::Packet. This will be used inside the TCP-scope. + auto packet = std::static_pointer_cast(packet_ptr); + debug(" TCP Packet received - Source: %s, Destination: %s \n", + packet->source().to_string().c_str(), packet->destination().to_string().c_str()); - // Do checksum - if(checksum(packet)) { - debug(" TCP Packet Checksum != 0 \n"); - } - - Connection::Tuple tuple { packet->dst_port(), packet->source() }; - - // Try to find the receiver - auto conn_it = connections_.find(tuple); - // Connection found - if(conn_it != connections_.end()) { - debug(" Connection found: %s \n", conn_it->second->to_string().c_str()); - conn_it->second->receive(packet); - } - // No connection found - else { - // Is there a listener? - auto listen_conn_it = listeners_.find(packet->dst_port()); - debug(" No connection found - looking for listener..\n"); - // Listener found => Create listening Connection - if(listen_conn_it != listeners_.end()) { - auto& listen_conn = listen_conn_it->second; - debug(" Listener found: %s ...\n", listen_conn.to_string().c_str()); - auto connection = (connections_.emplace(tuple, std::make_shared(listen_conn)).first->second); - // Set remote - connection->set_remote(packet->source()); - debug(" ... Creating connection: %s \n", connection->to_string().c_str()); + // Do checksum + if(checksum(packet)) { + debug(" TCP Packet Checksum != 0 \n"); + } + + Connection::Tuple tuple { packet->dst_port(), packet->source() }; + + // Try to find the receiver + auto conn_it = connections_.find(tuple); + // Connection found + if(conn_it != connections_.end()) { + debug(" Connection found: %s \n", conn_it->second->to_string().c_str()); + conn_it->second->receive(packet); + } + // No connection found + else { + // Is there a listener? + auto listen_conn_it = listeners_.find(packet->dst_port()); + debug(" No connection found - looking for listener..\n"); + // Listener found => Create listening Connection + if(listen_conn_it != listeners_.end()) { + auto& listen_conn = listen_conn_it->second; + debug(" Listener found: %s ...\n", listen_conn.to_string().c_str()); + auto connection = (connections_.emplace(tuple, std::make_shared(listen_conn)).first->second); + // Set remote + connection->set_remote(packet->source()); + debug(" ... Creating connection: %s \n", connection->to_string().c_str()); - connection->receive(packet); - } - // No listener found - else { - drop(packet); - } - } + connection->receive(packet); + } + // No listener found + else { + drop(packet); + } + } } /* - Show all connections for TCP as a string. + Show all connections for TCP as a string. - Format: - [Protocol][Recv][Send][Local][Remote][State] + Format: + [Protocol][Recv][Send][Local][Remote][State] - TODO: Make sure Recv, Send, In, Out is correct and add them to output. Also, alignment? + TODO: Make sure Recv, Send, In, Out is correct and add them to output. Also, alignment? */ string TCP::status() const { - // Write all connections in a cute list. - stringstream ss; - ss << "LISTENING SOCKETS:\n"; - for(auto listen_it : listeners_) { - ss << listen_it.second.to_string() << "\n"; - } - ss << "\nCONNECTIONS:\n" << "Proto\tRecv\tSend\tIn\tOut\tLocal\t\t\tRemote\t\t\tState\n"; - for(auto con_it : connections_) { - auto& c = *(con_it.second); - ss << "tcp4\t" - << " " << "\t" << " " << "\t" - << " " << "\t" << " " << "\t" - << c.local().to_string() << "\t\t" << c.remote().to_string() << "\t\t" - << c.state().to_string() << "\n"; - } - return ss.str(); + // Write all connections in a cute list. + stringstream ss; + ss << "LISTENING SOCKETS:\n"; + for(auto listen_it : listeners_) { + ss << listen_it.second.to_string() << "\n"; + } + ss << "\nCONNECTIONS:\n" << "Proto\tRecv\tSend\tIn\tOut\tLocal\t\t\tRemote\t\t\tState\n"; + for(auto con_it : connections_) { + auto& c = *(con_it.second); + ss << "tcp4\t" + << " " << "\t" << " " << "\t" + << " " << "\t" << " " << "\t" + << c.local().to_string() << "\t\t" << c.remote().to_string() << "\t\t" + << c.state().to_string() << "\n"; + } + return ss.str(); } /*TCP::Socket& TCP::add_listener(TCP::Socket&& socket) { -}*/ + }*/ TCP::Connection_ptr TCP::add_connection(Port local_port, TCP::Socket remote) { - return (connections_.emplace( - Connection::Tuple{ local_port, remote }, - std::make_shared(*this, local_port, remote)) - ).first->second; + return (connections_.emplace( + Connection::Tuple{ local_port, remote }, + std::make_shared(*this, local_port, remote)) + ).first->second; } void TCP::close_connection(TCP::Connection& conn) { - debug(" Closing connection: %s \n", conn.to_string().c_str()); - connections_.erase(conn.tuple()); - debug2(" TCP Status: \n%s \n", status().c_str()); + debug(" Closing connection: %s \n", conn.to_string().c_str()); + connections_.erase(conn.tuple()); + debug2(" TCP Status: \n%s \n", status().c_str()); } void TCP::drop(TCP::Packet_ptr) { - //debug(" Packet was dropped - no recipient: %s \n", packet->destination().to_string().c_str()); + //debug(" Packet was dropped - no recipient: %s \n", packet->destination().to_string().c_str()); } void TCP::transmit(TCP::Packet_ptr packet) { - // Translate into a net::Packet_ptr and send away. - // Generate checksum. - packet->set_checksum(TCP::checksum(packet)); - //packet->set_checksum(checksum(packet)); - _network_layer_out(packet); -} \ No newline at end of file + // Translate into a net::Packet_ptr and send away. + // Generate checksum. + packet->set_checksum(TCP::checksum(packet)); + //packet->set_checksum(checksum(packet)); + _network_layer_out(packet); +} diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index c7fc2b70e6..c0de3db285 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -26,416 +26,416 @@ using Connection = TCP::Connection; using namespace std; /* - This is most likely used in a ACTIVE open + This is most likely used in a ACTIVE open */ Connection::Connection(TCP& host, Port local_port, Socket remote) : - host_(host), - local_port_(local_port), - remote_(remote), - state_(&Connection::Closed::instance()), - prev_state_(state_), - control_block(), - receive_buffer_(host.buffer_limit()), - send_buffer_(host.buffer_limit()), - time_wait_started(0) + host_(host), + local_port_(local_port), + remote_(remote), + state_(&Connection::Closed::instance()), + prev_state_(state_), + control_block(), + receive_buffer_(host.buffer_limit()), + send_buffer_(host.buffer_limit()), + time_wait_started(0) { } /* - This is most likely used in a PASSIVE open + This is most likely used in a PASSIVE open */ Connection::Connection(TCP& host, Port local_port) : - host_(host), - local_port_(local_port), - remote_(TCP::Socket()), - state_(&Connection::Closed::instance()), - prev_state_(state_), - control_block(), - receive_buffer_(host.buffer_limit()), - send_buffer_(host.buffer_limit()), - time_wait_started(0) + host_(host), + local_port_(local_port), + remote_(TCP::Socket()), + state_(&Connection::Closed::instance()), + prev_state_(state_), + control_block(), + receive_buffer_(host.buffer_limit()), + send_buffer_(host.buffer_limit()), + time_wait_started(0) { } size_t Connection::read(char* buffer, size_t n) { - debug(" Reading %u bytes of data from RCV buffer. Total amount of packets stored: %u\n", - n, receive_buffer_.size()); - try { - return state_->receive(*this, buffer, n); - } catch(TCPException err) { - signal_error(err); - return 0; - } + debug(" Reading %u bytes of data from RCV buffer. Total amount of packets stored: %u\n", + n, receive_buffer_.size()); + try { + return state_->receive(*this, buffer, n); + } catch(TCPException err) { + signal_error(err); + return 0; + } } std::string Connection::read(size_t n) { - if(n == 0) { - // Read all data. - n = receive_buffer_.data_size(); - } - char buffer[n]; - size_t length = read(&buffer[0], n); - return {buffer, length}; + if(n == 0) { + // Read all data. + n = receive_buffer_.data_size(); + } + char buffer[n]; + size_t length = read(&buffer[0], n); + return {buffer, length}; } size_t Connection::read_from_receive_buffer(char* buffer, size_t n) { - size_t bytes_read = 0; - // Read data to buffer until either whole buffer is emptied, or the user got all the data requested. - while(!receive_buffer_.empty() and bytes_read < n) - { - // Packet in front - auto packet = receive_buffer_.front(); - // Where to begin reading - char* begin = packet->data()+receive_buffer_.data_offset(); - // Read this iteration - size_t total{0}; - // Remaining bytes to read. - size_t remaining = n - bytes_read; - // Trying to read over more than one packet - if( remaining >= (packet->data_length() - receive_buffer_.data_offset()) ) { - debug2(" Remaining >: %u Current p: %u\n", - remaining, packet->data_length() - receive_buffer_.data_offset()); - // Reading whole packet - total = packet->data_length(); - // Removing packet from receive buffer. - receive_buffer_.pop(); - // Next packet will start from beginning. - receive_buffer_.set_data_offset(0); - } - // Reading less than one packet. - else { - debug2(" Remaining <: %u\n", remaining); - total = remaining; - receive_buffer_.set_data_offset(packet->data_length() - remaining); - } - memcpy(buffer+bytes_read, begin, total); - bytes_read += total; - } - - return bytes_read; + size_t bytes_read = 0; + // Read data to buffer until either whole buffer is emptied, or the user got all the data requested. + while(!receive_buffer_.empty() and bytes_read < n) + { + // Packet in front + auto packet = receive_buffer_.front(); + // Where to begin reading + char* begin = packet->data()+receive_buffer_.data_offset(); + // Read this iteration + size_t total{0}; + // Remaining bytes to read. + size_t remaining = n - bytes_read; + // Trying to read over more than one packet + if( remaining >= (packet->data_length() - receive_buffer_.data_offset()) ) { + debug2(" Remaining >: %u Current p: %u\n", + remaining, packet->data_length() - receive_buffer_.data_offset()); + // Reading whole packet + total = packet->data_length(); + // Removing packet from receive buffer. + receive_buffer_.pop(); + // Next packet will start from beginning. + receive_buffer_.set_data_offset(0); + } + // Reading less than one packet. + else { + debug2(" Remaining <: %u\n", remaining); + total = remaining; + receive_buffer_.set_data_offset(packet->data_length() - remaining); + } + memcpy(buffer+bytes_read, begin, total); + bytes_read += total; + } + + return bytes_read; } bool Connection::add_to_receive_buffer(TCP::Packet_ptr packet) { - return receive_buffer_.add(packet); + return receive_buffer_.add(packet); } size_t Connection::write(const char* buffer, size_t n, bool PUSH) { - debug(" Asking to write %u bytes of data to SND buffer. \n", n); - try { - return state_->send(*this, buffer, n, PUSH); - } catch(TCPException err) { - signal_error(err); - return 0; - } + debug(" Asking to write %u bytes of data to SND buffer. \n", n); + try { + return state_->send(*this, buffer, n, PUSH); + } catch(TCPException err) { + signal_error(err); + return 0; + } } size_t Connection::write_to_send_buffer(const char* buffer, size_t n, bool PUSH) { - size_t bytes_written{0}; - size_t remaining{n}; - do { - auto packet = create_outgoing_packet(); - packet->set_seq(control_block.SND.NXT).set_ack(control_block.RCV.NXT).set_flag(ACK); - // calculate how much the packet can be filled with - auto packet_limit = (uint32_t)MSDS() - packet->header_size(); - size_t written = packet->fill(buffer + (n-remaining), std::min(packet_limit, remaining)); - bytes_written += written; - remaining -= written; + size_t bytes_written{0}; + size_t remaining{n}; + do { + auto packet = create_outgoing_packet(); + packet->set_seq(control_block.SND.NXT).set_ack(control_block.RCV.NXT).set_flag(ACK); + // calculate how much the packet can be filled with + auto packet_limit = (uint32_t)MSDS() - packet->header_size(); + size_t written = packet->fill(buffer + (n-remaining), std::min(packet_limit, remaining)); + bytes_written += written; + remaining -= written; - debug2(" Packet Limit: %u - Written: %u - Remaining: %u\n", - packet_limit, written, remaining); + debug2(" Packet Limit: %u - Written: %u - Remaining: %u\n", + packet_limit, written, remaining); - // If last packet, add PUSH. - if(!remaining and PUSH) - packet->set_flag(PSH); + // If last packet, add PUSH. + if(!remaining and PUSH) + packet->set_flag(PSH); - // Advance outgoing sequence number (SND.NXT) with the length of the data. - control_block.SND.NXT += packet->data_length(); - } while(remaining and !send_buffer_.full()); + // Advance outgoing sequence number (SND.NXT) with the length of the data. + control_block.SND.NXT += packet->data_length(); + } while(remaining and !send_buffer_.full()); - return bytes_written; + return bytes_written; } /* - If ACTIVE: - Need a remote Socket. + If ACTIVE: + Need a remote Socket. */ void Connection::open(bool active) { - try { - debug(" Trying to open Connection...\n"); - state_->open(*this, active); - } - // No remote host, or state isnt valid for opening. - catch (TCPException e) { - debug(" Cannot open Connection. \n"); - signal_error(e); - } + try { + debug(" Trying to open Connection...\n"); + state_->open(*this, active); + } + // No remote host, or state isnt valid for opening. + catch (TCPException e) { + debug(" Cannot open Connection. \n"); + signal_error(e); + } } void Connection::close() { - debug(" Active close on connection. \n"); - try { - state_->close(*this); - if(is_state(Closed::instance())) - signal_close(); - } catch(TCPException err) { - signal_error(err); - } + debug(" Active close on connection. \n"); + try { + state_->close(*this); + if(is_state(Closed::instance())) + signal_close(); + } catch(TCPException err) { + signal_error(err); + } } string Connection::to_string() const { - ostringstream os; - os << local().to_string() << "\t" << remote_.to_string() << "\t" << state_->to_string(); - return os.str(); + ostringstream os; + os << local().to_string() << "\t" << remote_.to_string() << "\t" << state_->to_string(); + return os.str(); } /* - Where the magic happens. + Where the magic happens. */ void Connection::receive(TCP::Packet_ptr incoming) { - signal_packet_received(incoming); - - if(incoming->has_options()) { - try { - parse_options(incoming); - } - catch(TCPBadOptionException err) { - printf(" %s \n", err.what()); - } - } - - // Change window accordingly. TODO: Not sure if this is how you do it. - control_block.SND.WND = incoming->win(); - - // Let state handle what to do when incoming packet arrives, and modify the outgoing packet. - switch(state_->handle(*this, incoming)) { - case State::OK: { - // Do nothing. - break; - } - case State::CLOSED: { - debug(" State handle finished with CLOSED. We're done, ask host() to delete the connection. \n"); - signal_close(); - break; - }; - case State::CLOSE: { - debug(" State handle finished with CLOSE. onDisconnect has been called, close the connection. \n"); - state_->close(*this); - break; - }; - } + signal_packet_received(incoming); + + if(incoming->has_options()) { + try { + parse_options(incoming); + } + catch(TCPBadOptionException err) { + printf(" %s \n", err.what()); + } + } + + // Change window accordingly. TODO: Not sure if this is how you do it. + control_block.SND.WND = incoming->win(); + + // Let state handle what to do when incoming packet arrives, and modify the outgoing packet. + switch(state_->handle(*this, incoming)) { + case State::OK: { + // Do nothing. + break; + } + case State::CLOSED: { + debug(" State handle finished with CLOSED. We're done, ask host() to delete the connection. \n"); + signal_close(); + break; + }; + case State::CLOSE: { + debug(" State handle finished with CLOSE. onDisconnect has been called, close the connection. \n"); + state_->close(*this); + break; + }; + } } bool Connection::is_listening() const { - return is_state(Listen::instance()); + return is_state(Listen::instance()); } bool Connection::is_connected() const { - return is_state(Established::instance()); + return is_state(Established::instance()); } bool Connection::is_closing() const { - return (is_state(Closing::instance()) or is_state(LastAck::instance()) or is_state(TimeWait::instance())); + return (is_state(Closing::instance()) or is_state(LastAck::instance()) or is_state(TimeWait::instance())); } bool Connection::is_writable() const { - return (is_connected() and (!send_buffer_.full())); + return (is_connected() and (!send_buffer_.full())); } Connection::~Connection() { - // Do all necessary clean up. - // Free up buffers etc. - debug2(" Bye bye... \n"); + // Do all necessary clean up. + // Free up buffers etc. + debug2(" Bye bye... \n"); } TCP::Packet_ptr Connection::create_outgoing_packet() { - auto packet = std::static_pointer_cast((host_.inet_).createPacket(TCP::Packet::HEADERS_SIZE)); + auto packet = std::static_pointer_cast((host_.inet_).createPacket(TCP::Packet::HEADERS_SIZE)); - packet->init(); - // Set Source (local == the current connection) - packet->set_source(local()); - // Set Destination (remote) - packet->set_destination(remote_); + packet->init(); + // Set Source (local == the current connection) + packet->set_source(local()); + // Set Destination (remote) + packet->set_destination(remote_); - packet->set_win_size(control_block.SND.WND); + packet->set_win_size(control_block.SND.WND); - // Set SEQ and ACK - I think this is OK.. - packet->set_seq(control_block.SND.NXT).set_ack(control_block.RCV.NXT); - debug(" Outgoing packet created: %s \n", packet->to_string().c_str()); + // Set SEQ and ACK - I think this is OK.. + packet->set_seq(control_block.SND.NXT).set_ack(control_block.RCV.NXT); + debug(" Outgoing packet created: %s \n", packet->to_string().c_str()); - // Will also add the packet to the back of the send queue. - send_buffer_.push(packet); + // Will also add the packet to the back of the send queue. + send_buffer_.push(packet); - return packet; + return packet; } void Connection::transmit() { - assert(! send_buffer_.empty() ); + assert(! send_buffer_.empty() ); - debug(" Transmitting: [ %i ] packets. \n", send_buffer_.size()); - while(! send_buffer_.empty() ) { - auto packet = send_buffer_.front(); - assert(! packet->destination().is_empty()); - transmit(packet); - send_buffer_.pop(); - } + debug(" Transmitting: [ %i ] packets. \n", send_buffer_.size()); + while(! send_buffer_.empty() ) { + auto packet = send_buffer_.front(); + assert(! packet->destination().is_empty()); + transmit(packet); + send_buffer_.pop(); + } } void Connection::transmit(TCP::Packet_ptr packet) { - debug(" Transmitting: %s \n", packet->to_string().c_str()); - host_.transmit(packet); - // Don't think we would like to retransmit reset packets..? - //if(!packet->isset(RST)) - // add_retransmission(packet); + debug(" Transmitting: %s \n", packet->to_string().c_str()); + host_.transmit(packet); + // Don't think we would like to retransmit reset packets..? + //if(!packet->isset(RST)) + // add_retransmission(packet); } TCP::Packet_ptr Connection::outgoing_packet() { - if(send_buffer_.empty()) - create_outgoing_packet(); - return send_buffer_.back(); + if(send_buffer_.empty()) + create_outgoing_packet(); + return send_buffer_.back(); } TCP::Seq Connection::generate_iss() { - return host_.generate_iss(); + return host_.generate_iss(); } void Connection::set_state(State& state) { - prev_state_ = state_; - state_ = &state; - debug(" %s => %s \n", - prev_state_->to_string().c_str(), state_->to_string().c_str()); + prev_state_ = state_; + state_ = &state; + debug(" %s => %s \n", + prev_state_->to_string().c_str(), state_->to_string().c_str()); } void Connection::add_retransmission(TCP::Packet_ptr packet) { - debug2(" Packet added to retransmission. \n"); - auto self = shared_from_this(); - hw::PIT::instance().onTimeout(RTO(), [packet, self] { - // Packet hasnt been ACKed. - if(packet->seq() > self->tcb().SND.UNA) { - debug(" Packet unacknowledge, retransmitting...\n"); - self->transmit(packet); - } else { - debug2(" Packet acknowledged %s \n", packet->to_string().c_str()); - // Signal user? - } - }); + debug2(" Packet added to retransmission. \n"); + auto self = shared_from_this(); + hw::PIT::instance().onTimeout(RTO(), [packet, self] { + // Packet hasnt been ACKed. + if(packet->seq() > self->tcb().SND.UNA) { + debug(" Packet unacknowledge, retransmitting...\n"); + self->transmit(packet); + } else { + debug2(" Packet acknowledged %s \n", packet->to_string().c_str()); + // Signal user? + } + }); } /* - Next compute a Smoothed Round Trip Time (SRTT) as: + Next compute a Smoothed Round Trip Time (SRTT) as: - SRTT = ( ALPHA * SRTT ) + ((1-ALPHA) * RTT) + SRTT = ( ALPHA * SRTT ) + ((1-ALPHA) * RTT) - and based on this, compute the retransmission timeout (RTO) as: + and based on this, compute the retransmission timeout (RTO) as: - RTO = min[UBOUND,max[LBOUND,(BETA*SRTT)]] + RTO = min[UBOUND,max[LBOUND,(BETA*SRTT)]] - where UBOUND is an upper bound on the timeout (e.g., 1 minute), - LBOUND is a lower bound on the timeout (e.g., 1 second), ALPHA is - a smoothing factor (e.g., .8 to .9), and BETA is a delay variance - factor (e.g., 1.3 to 2.0). + where UBOUND is an upper bound on the timeout (e.g., 1 minute), + LBOUND is a lower bound on the timeout (e.g., 1 second), ALPHA is + a smoothing factor (e.g., .8 to .9), and BETA is a delay variance + factor (e.g., 1.3 to 2.0). */ std::chrono::milliseconds Connection::RTO() const { - return 1s; + return 1s; } void Connection::start_time_wait_timeout() { - debug2(" Time Wait timer started. \n"); - time_wait_started = OS::cycles_since_boot(); - auto timeout = 2 * host().MSL(); // 60 seconds - // Passing "this"..? - hw::PIT::instance().onTimeout(timeout,[this, timeout] { - // The timer hasnt been updated - if( OS::cycles_since_boot() >= (time_wait_started + timeout.count()) ) { - signal_close(); - } else { - debug2(" time_wait_started has been updated. \n"); - } - }); + debug2(" Time Wait timer started. \n"); + time_wait_started = OS::cycles_since_boot(); + auto timeout = 2 * host().MSL(); // 60 seconds + // Passing "this"..? + hw::PIT::instance().onTimeout(timeout,[this, timeout] { + // The timer hasnt been updated + if( OS::cycles_since_boot() >= (time_wait_started + timeout.count()) ) { + signal_close(); + } else { + debug2(" time_wait_started has been updated. \n"); + } + }); } void Connection::signal_close() { - debug(" It's time to delete this connection. \n"); - host_.close_connection(*this); + debug(" It's time to delete this connection. \n"); + host_.close_connection(*this); } std::string Connection::TCB::to_string() const { - ostringstream os; - os << "SND" - << " .UNA = " << SND.UNA - << " .NXT = " << SND.NXT - << " .WND = " << SND.WND - << " .UP = " << SND.UP - << " .WL1 = " << SND.WL1 - << " .WL2 = " << SND.WL2 - << " ISS = " << ISS - << "\n RCV" - << " .NXT = " << RCV.NXT - << " .WND = " << RCV.WND - << " .UP = " << RCV.UP - << " IRS = " << IRS; - return os.str(); + ostringstream os; + os << "SND" + << " .UNA = " << SND.UNA + << " .NXT = " << SND.NXT + << " .WND = " << SND.WND + << " .UP = " << SND.UP + << " .WL1 = " << SND.WL1 + << " .WL2 = " << SND.WL2 + << " ISS = " << ISS + << "\n RCV" + << " .NXT = " << RCV.NXT + << " .WND = " << RCV.WND + << " .UP = " << RCV.UP + << " IRS = " << IRS; + return os.str(); } void Connection::parse_options(TCP::Packet_ptr packet) { - assert(packet->has_options()); - debug(" Parsing options. Offset: %u, Options: %u \n", - packet->offset(), packet->options_length()); + assert(packet->has_options()); + debug(" Parsing options. Offset: %u, Options: %u \n", + packet->offset(), packet->options_length()); - auto* opt = packet->options(); + auto* opt = packet->options(); - while((char*)opt < packet->data()) { + while((char*)opt < packet->data()) { - auto* option = (TCP::Option*)opt; + auto* option = (TCP::Option*)opt; - switch(option->kind) { - - case Option::END: { - return; - } - - case Option::NOP: { - opt++; - break; - } - - case Option::MSS: { - // unlikely - if(option->length != 4) - throw TCPBadOptionException{Option::MSS, "length != 4"}; - // unlikely - if(!packet->isset(SYN)) - throw TCPBadOptionException{Option::MSS, "Non-SYN packet"}; + switch(option->kind) { + + case Option::END: { + return; + } + + case Option::NOP: { + opt++; + break; + } + + case Option::MSS: { + // unlikely + if(option->length != 4) + throw TCPBadOptionException{Option::MSS, "length != 4"}; + // unlikely + if(!packet->isset(SYN)) + throw TCPBadOptionException{Option::MSS, "Non-SYN packet"}; - auto* opt_mss = (Option::opt_mss*)option; - uint16_t mss = ntohs(opt_mss->mss); - control_block.SND.MSS = mss; - debug2(" MSS: %u \n", mss); - opt += option->length; - break; - } - - default: - return; - } - } + auto* opt_mss = (Option::opt_mss*)option; + uint16_t mss = ntohs(opt_mss->mss); + control_block.SND.MSS = mss; + debug2(" MSS: %u \n", mss); + opt += option->length; + break; + } + + default: + return; + } + } } void Connection::add_option(TCP::Option::Kind kind, TCP::Packet_ptr packet) { - switch(kind) { - - case Option::MSS: { - packet->add_option(host_.MSS()); - debug2(" Packet: %s - MSS: %u\n", - packet->to_string().c_str(), ntohs(*(uint16_t*)(packet->options()+2))); - break; - } - default: - break; - } + switch(kind) { + + case Option::MSS: { + packet->add_option(host_.MSS()); + debug2(" Packet: %s - MSS: %u\n", + packet->to_string().c_str(), ntohs(*(uint16_t*)(packet->options()+2))); + break; + } + default: + break; + } } diff --git a/src/net/tcp_connection_states.cpp b/src/net/tcp_connection_states.cpp index 1df39c391b..86916b22a0 100644 --- a/src/net/tcp_connection_states.cpp +++ b/src/net/tcp_connection_states.cpp @@ -22,311 +22,311 @@ using namespace std; ///////////////////////////////////////////////////////////////////// /* - COMMON STATE FUNCTIONS + COMMON STATE FUNCTIONS */ ///////////////////////////////////////////////////////////////////// /* - 1. Check Sequence + 1. Check Sequence */ /* - SYN-RECEIVED STATE - ESTABLISHED STATE - FIN-WAIT-1 STATE - FIN-WAIT-2 STATE - CLOSE-WAIT STATE - CLOSING STATE - LAST-ACK STATE - TIME-WAIT STATE + SYN-RECEIVED STATE + ESTABLISHED STATE + FIN-WAIT-1 STATE + FIN-WAIT-2 STATE + CLOSE-WAIT STATE + CLOSING STATE + LAST-ACK STATE + TIME-WAIT STATE - Segments are processed in sequence. Initial tests on arrival - are used to discard old duplicates, but further processing is - done in SEG.SEQ order. If a segment's contents straddle the - boundary between old and new, only the new parts should be - processed. + Segments are processed in sequence. Initial tests on arrival + are used to discard old duplicates, but further processing is + done in SEG.SEQ order. If a segment's contents straddle the + boundary between old and new, only the new parts should be + processed. - There are four cases for the acceptability test for an incoming - segment: + There are four cases for the acceptability test for an incoming + segment: - Segment Receive Test - Length Window - ------- ------- ------------------------------------------- + Segment Receive Test + Length Window + ------- ------- ------------------------------------------- - 0 0 SEG.SEQ = RCV.NXT + 0 0 SEG.SEQ = RCV.NXT - 0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND + 0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND - >0 0 not acceptable + >0 0 not acceptable - >0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND - or RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND + >0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND + or RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND - If the RCV.WND is zero, no segments will be acceptable, but - special allowance should be made to accept valid ACKs, URGs and - RSTs. + If the RCV.WND is zero, no segments will be acceptable, but + special allowance should be made to accept valid ACKs, URGs and + RSTs. - If an incoming segment is not acceptable, an acknowledgment - should be sent in reply (unless the RST bit is set, if so drop - the segment and return): + If an incoming segment is not acceptable, an acknowledgment + should be sent in reply (unless the RST bit is set, if so drop + the segment and return): - + - After sending the acknowledgment, drop the unacceptable segment - and return. + After sending the acknowledgment, drop the unacceptable segment + and return. - In the following it is assumed that the segment is the idealized - segment that begins at RCV.NXT and does not exceed the window. - One could tailor actual segments to fit this assumption by - trimming off any portions that lie outside the window (including - SYN and FIN), and only processing further if the segment then - begins at RCV.NXT. Segments with higher begining sequence - numbers may be held for later processing. + In the following it is assumed that the segment is the idealized + segment that begins at RCV.NXT and does not exceed the window. + One could tailor actual segments to fit this assumption by + trimming off any portions that lie outside the window (including + SYN and FIN), and only processing further if the segment then + begins at RCV.NXT. Segments with higher begining sequence + numbers may be held for later processing. */ /* - TODO: Optimize this one. It checks for the same things. + TODO: Optimize this one. It checks for the same things. */ bool Connection::State::check_seq(Connection& tcp, TCP::Packet_ptr in) { - auto& tcb = tcp.tcb(); - bool acceptable = false; - debug2(" TCB: %s \n",tcb.to_string().c_str()); - // #1 - if( in->seq() == tcb.RCV.NXT ) { - acceptable = true; - } - // #2 - else if( tcb.RCV.NXT <= in->seq() and in->seq() < tcb.RCV.NXT + tcb.RCV.WND ) { - acceptable = true; - } - // #3 (INVALID) - else if( in->seq() + in->data_length()-1 > tcb.RCV.NXT+tcb.RCV.WND ) { - acceptable = false; - } - // #4 - else if( (tcb.RCV.NXT <= in->seq() and in->seq() < tcb.RCV.NXT + tcb.RCV.WND) - or ( tcb.RCV.NXT <= in->seq()+in->data_length()-1 and in->seq()+in->data_length()-1 < tcb.RCV.NXT+tcb.RCV.WND ) ) { - acceptable = true; - } - /* - If an incoming segment is not acceptable, an acknowledgment - should be sent in reply (unless the RST bit is set, if so drop - the segment and return): - - - - After sending the acknowledgment, drop the unacceptable segment - and return. - */ - if(!acceptable) { - if(!in->isset(RST)) { - tcp.outgoing_packet()->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); - tcp.transmit(); - } - tcp.drop(in, "Unacceptable SEQ."); - return false; - } - debug2(" Acceptable SEQ: %u \n", in->seq()); - // is acceptable. - return true; + auto& tcb = tcp.tcb(); + bool acceptable = false; + debug2(" TCB: %s \n",tcb.to_string().c_str()); + // #1 + if( in->seq() == tcb.RCV.NXT ) { + acceptable = true; + } + // #2 + else if( tcb.RCV.NXT <= in->seq() and in->seq() < tcb.RCV.NXT + tcb.RCV.WND ) { + acceptable = true; + } + // #3 (INVALID) + else if( in->seq() + in->data_length()-1 > tcb.RCV.NXT+tcb.RCV.WND ) { + acceptable = false; + } + // #4 + else if( (tcb.RCV.NXT <= in->seq() and in->seq() < tcb.RCV.NXT + tcb.RCV.WND) + or ( tcb.RCV.NXT <= in->seq()+in->data_length()-1 and in->seq()+in->data_length()-1 < tcb.RCV.NXT+tcb.RCV.WND ) ) { + acceptable = true; + } + /* + If an incoming segment is not acceptable, an acknowledgment + should be sent in reply (unless the RST bit is set, if so drop + the segment and return): + + + + After sending the acknowledgment, drop the unacceptable segment + and return. + */ + if(!acceptable) { + if(!in->isset(RST)) { + tcp.outgoing_packet()->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); + tcp.transmit(); + } + tcp.drop(in, "Unacceptable SEQ."); + return false; + } + debug2(" Acceptable SEQ: %u \n", in->seq()); + // is acceptable. + return true; } /* - 4. Check SYN + 4. Check SYN */ /* - SYN-RECEIVED - ESTABLISHED STATE - FIN-WAIT STATE-1 - FIN-WAIT STATE-2 - CLOSE-WAIT STATE - CLOSING STATE - LAST-ACK STATE - TIME-WAIT STATE - - If the SYN is in the window it is an error, send a reset, any - outstanding RECEIVEs and SEND should receive "reset" responses, - all segment queues should be flushed, the user should also - receive an unsolicited general "connection reset" signal, enter - the CLOSED state, delete the TCB, and return. - - If the SYN is not in the window this step would not be reached - and an ack would have been sent in the first step (sequence - number check). + SYN-RECEIVED + ESTABLISHED STATE + FIN-WAIT STATE-1 + FIN-WAIT STATE-2 + CLOSE-WAIT STATE + CLOSING STATE + LAST-ACK STATE + TIME-WAIT STATE + + If the SYN is in the window it is an error, send a reset, any + outstanding RECEIVEs and SEND should receive "reset" responses, + all segment queues should be flushed, the user should also + receive an unsolicited general "connection reset" signal, enter + the CLOSED state, delete the TCB, and return. + + If the SYN is not in the window this step would not be reached + and an ack would have been sent in the first step (sequence + number check). */ void Connection::State::unallowed_syn_reset_connection(Connection& tcp, TCP::Packet_ptr in) { - assert(in->isset(SYN)); - debug(" Unallowed SYN for STATE: %s, reseting connection.\n", - tcp.state().to_string().c_str()); - // Not sure if this is the correct way to send a "reset response" - tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); - tcp.transmit(); - tcp.signal_disconnect(Disconnect::RESET); + assert(in->isset(SYN)); + debug(" Unallowed SYN for STATE: %s, reseting connection.\n", + tcp.state().to_string().c_str()); + // Not sure if this is the correct way to send a "reset response" + tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); + tcp.transmit(); + tcp.signal_disconnect(Disconnect::RESET); } /* - 5. Check ACK + 5. Check ACK */ bool Connection::State::check_ack(Connection& tcp, TCP::Packet_ptr in) { - // 5. ACK bit - debug2(" Checking for ACK in STATE: %s \n", tcp.state().to_string().c_str()); - if( in->isset(ACK) ) { - auto& tcb = tcp.tcb(); - /* - If SND.UNA < SEG.ACK =< SND.NXT then, set SND.UNA <- SEG.ACK. - Any segments on the retransmission queue which are thereby - entirely acknowledged are removed. Users should receive - positive acknowledgments for buffers which have been SENT and - fully acknowledged (i.e., SEND buffer should be returned with - "ok" response). If the ACK is a duplicate - (SEG.ACK < SND.UNA), it can be ignored. If the ACK acks - something not yet sent (SEG.ACK > SND.NXT) then send an ACK, - drop the segment, and return. - */ - if( tcb.SND.UNA < in->ack() and in->ack() <= tcb.SND.NXT ) { - tcb.SND.UNA = in->ack(); - // tcp.signal_sent(); - // return that buffer has been SENT - currently no support to receipt sent buffer. - - /* - If SND.UNA < SEG.ACK =< SND.NXT, the send window should be - updated. If (SND.WL1 < SEG.SEQ or (SND.WL1 = SEG.SEQ and - SND.WL2 =< SEG.ACK)), set SND.WND <- SEG.WND, set - SND.WL1 <- SEG.SEQ, and set SND.WL2 <- SEG.ACK. - */ - if( tcb.SND.WL1 < in->seq() or ( tcb.SND.WL1 = in->seq() and tcb.SND.WL2 <= in->ack() ) ) { - tcb.SND.WND = in->win(); - tcb.SND.WL1 = in->seq(); - tcb.SND.WL2 = in->ack(); - } - /* - Note that SND.WND is an offset from SND.UNA, that SND.WL1 - records the sequence number of the last segment used to update - SND.WND, and that SND.WL2 records the acknowledgment number of - the last segment used to update SND.WND. The check here - prevents using old segments to update the window. - */ - - } - /* If the ACK acks something not yet sent (SEG.ACK > SND.NXT) then send an ACK, drop the segment, and return. */ - else if( in->ack() > tcb.SND.NXT ) { - tcp.outgoing_packet()->set_flag(ACK); - tcp.transmit(); - tcp.drop(in, "ACK > SND.NXT"); - return false; - } - /* If the ACK is a duplicate (SEG.ACK < SND.UNA), it can be ignored. */ - /*else if( in->ack() < tcb.SND.UNA ) { - // ignore. - }*/ - return true; + // 5. ACK bit + debug2(" Checking for ACK in STATE: %s \n", tcp.state().to_string().c_str()); + if( in->isset(ACK) ) { + auto& tcb = tcp.tcb(); + /* + If SND.UNA < SEG.ACK =< SND.NXT then, set SND.UNA <- SEG.ACK. + Any segments on the retransmission queue which are thereby + entirely acknowledged are removed. Users should receive + positive acknowledgments for buffers which have been SENT and + fully acknowledged (i.e., SEND buffer should be returned with + "ok" response). If the ACK is a duplicate + (SEG.ACK < SND.UNA), it can be ignored. If the ACK acks + something not yet sent (SEG.ACK > SND.NXT) then send an ACK, + drop the segment, and return. + */ + if( tcb.SND.UNA < in->ack() and in->ack() <= tcb.SND.NXT ) { + tcb.SND.UNA = in->ack(); + // tcp.signal_sent(); + // return that buffer has been SENT - currently no support to receipt sent buffer. + + /* + If SND.UNA < SEG.ACK =< SND.NXT, the send window should be + updated. If (SND.WL1 < SEG.SEQ or (SND.WL1 = SEG.SEQ and + SND.WL2 =< SEG.ACK)), set SND.WND <- SEG.WND, set + SND.WL1 <- SEG.SEQ, and set SND.WL2 <- SEG.ACK. + */ + if( tcb.SND.WL1 < in->seq() or ( tcb.SND.WL1 = in->seq() and tcb.SND.WL2 <= in->ack() ) ) { + tcb.SND.WND = in->win(); + tcb.SND.WL1 = in->seq(); + tcb.SND.WL2 = in->ack(); + } + /* + Note that SND.WND is an offset from SND.UNA, that SND.WL1 + records the sequence number of the last segment used to update + SND.WND, and that SND.WL2 records the acknowledgment number of + the last segment used to update SND.WND. The check here + prevents using old segments to update the window. + */ + } - // ACK not set. - else { - tcp.drop(in, "!ACK"); - return false; + /* If the ACK acks something not yet sent (SEG.ACK > SND.NXT) then send an ACK, drop the segment, and return. */ + else if( in->ack() > tcb.SND.NXT ) { + tcp.outgoing_packet()->set_flag(ACK); + tcp.transmit(); + tcp.drop(in, "ACK > SND.NXT"); + return false; } + /* If the ACK is a duplicate (SEG.ACK < SND.UNA), it can be ignored. */ + /*else if( in->ack() < tcb.SND.UNA ) { + // ignore. + }*/ + return true; + } + // ACK not set. + else { + tcp.drop(in, "!ACK"); + return false; + } } /* - 7. Process the segment text + 7. Process the segment text */ /* - Once in the ESTABLISHED state, it is possible to deliver segment - text to user RECEIVE buffers. Text from segments can be moved - into buffers until either the buffer is full or the segment is - empty. If the segment empties and carries an PUSH flag, then - the user is informed, when the buffer is returned, that a PUSH - has been received. + Once in the ESTABLISHED state, it is possible to deliver segment + text to user RECEIVE buffers. Text from segments can be moved + into buffers until either the buffer is full or the segment is + empty. If the segment empties and carries an PUSH flag, then + the user is informed, when the buffer is returned, that a PUSH + has been received. - When the TCP takes responsibility for delivering the data to the - user it must also acknowledge the receipt of the data. + When the TCP takes responsibility for delivering the data to the + user it must also acknowledge the receipt of the data. - Once the TCP takes responsibility for the data it advances - RCV.NXT over the data accepted, and adjusts RCV.WND as - apporopriate to the current buffer availability. The total of - RCV.NXT and RCV.WND should not be reduced. + Once the TCP takes responsibility for the data it advances + RCV.NXT over the data accepted, and adjusts RCV.WND as + apporopriate to the current buffer availability. The total of + RCV.NXT and RCV.WND should not be reduced. - Please note the window management suggestions in section 3.7. + Please note the window management suggestions in section 3.7. - Send an acknowledgment of the form: + Send an acknowledgment of the form: - + - This acknowledgment should be piggybacked on a segment being - transmitted if possible without incurring undue delay. + This acknowledgment should be piggybacked on a segment being + transmitted if possible without incurring undue delay. */ void Connection::State::process_segment(Connection& tcp, TCP::Packet_ptr in) { - assert(in->has_data()); - - auto& tcb = tcp.tcb(); - int length = in->data_length(); - debug(" Received packet with DATA-LENGTH: %i. Add to receive buffer. \n", length); - if(!tcp.add_to_receive_buffer(in)) { - tcp.signal_error({"Receive buffer is full!"}); // Redo to BufferException? - return; // Don't ACK, sender need to resend. - } - tcb.RCV.NXT += length; - auto snd_nxt = tcb.SND.NXT; - debug2(" Advanced RCV.NXT: %u. SND.NXT = %u \n", tcb.RCV.NXT, snd_nxt); - if(in->isset(PSH)) { - debug(" Packet carries PUSH. Notify user.\n"); - tcp.signal_receive(true); - } else if(tcp.receive_buffer().full()) { - // Buffer is now full - debug(" Receive buffer is full. Notify user. \n"); - tcp.signal_receive(false); - } - /* - Once the TCP takes responsibility for the data it advances - RCV.NXT over the data accepted, and adjusts RCV.WND as - apporopriate to the current buffer availability. The total of - RCV.NXT and RCV.WND should not be reduced. - */ - if(tcb.SND.NXT == snd_nxt) { - tcp.outgoing_packet()->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); - tcp.transmit(); - } else { - debug2(" SND.NXT > snd_nxt, this packet has already been acknowledged. \n"); - } + assert(in->has_data()); + + auto& tcb = tcp.tcb(); + int length = in->data_length(); + debug(" Received packet with DATA-LENGTH: %i. Add to receive buffer. \n", length); + if(!tcp.add_to_receive_buffer(in)) { + tcp.signal_error({"Receive buffer is full!"}); // Redo to BufferException? + return; // Don't ACK, sender need to resend. + } + tcb.RCV.NXT += length; + auto snd_nxt = tcb.SND.NXT; + debug2(" Advanced RCV.NXT: %u. SND.NXT = %u \n", tcb.RCV.NXT, snd_nxt); + if(in->isset(PSH)) { + debug(" Packet carries PUSH. Notify user.\n"); + tcp.signal_receive(true); + } else if(tcp.receive_buffer().full()) { + // Buffer is now full + debug(" Receive buffer is full. Notify user. \n"); + tcp.signal_receive(false); + } + /* + Once the TCP takes responsibility for the data it advances + RCV.NXT over the data accepted, and adjusts RCV.WND as + apporopriate to the current buffer availability. The total of + RCV.NXT and RCV.WND should not be reduced. + */ + if(tcb.SND.NXT == snd_nxt) { + tcp.outgoing_packet()->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); + tcp.transmit(); + } else { + debug2(" SND.NXT > snd_nxt, this packet has already been acknowledged. \n"); + } } /* - 8. Check FIN + 8. Check FIN */ /* - If the FIN bit is set, signal the user "connection closing" and - return any pending RECEIVEs with same message, advance RCV.NXT - over the FIN, and send an acknowledgment for the FIN. Note that - FIN implies PUSH for any segment text not yet delivered to the - user. + If the FIN bit is set, signal the user "connection closing" and + return any pending RECEIVEs with same message, advance RCV.NXT + over the FIN, and send an acknowledgment for the FIN. Note that + FIN implies PUSH for any segment text not yet delivered to the + user. */ void Connection::State::process_fin(Connection& tcp, TCP::Packet_ptr in) { - debug(" Processing FIN bit in STATE: %s \n", tcp.state().to_string().c_str()); - assert(in->isset(FIN)); - auto& tcb = tcp.tcb(); - tcp.signal_disconnect(Disconnect::CLOSING); - // Advance RCV.NXT over the FIN? - tcb.RCV.NXT++; - //auto fin = in->data_length(); - //tcb.RCV.NXT += fin; - tcp.outgoing_packet()->set_ack(tcb.RCV.NXT).set_flag(ACK); - tcp.transmit(); - if(!tcp.receive_buffer().empty()) { - tcp.signal_receive(true); - } + debug(" Processing FIN bit in STATE: %s \n", tcp.state().to_string().c_str()); + assert(in->isset(FIN)); + auto& tcb = tcp.tcb(); + tcp.signal_disconnect(Disconnect::CLOSING); + // Advance RCV.NXT over the FIN? + tcb.RCV.NXT++; + //auto fin = in->data_length(); + //tcb.RCV.NXT += fin; + tcp.outgoing_packet()->set_ack(tcb.RCV.NXT).set_flag(ACK); + tcp.transmit(); + if(!tcp.receive_buffer().empty()) { + tcp.signal_receive(true); + } } /* - Send a reset segment: + Send a reset segment: - + All queued SENDs and RECEIVEs should be given "connection reset" notification; all segments queued for transmission (except for the @@ -334,546 +334,546 @@ void Connection::State::process_fin(Connection& tcp, TCP::Packet_ptr in) { TCB, enter CLOSED state, and return. */ void Connection::State::send_reset(Connection& tcp) { - tcp.send_buffer_.clear(); - tcp.outgoing_packet()->set_seq(tcp.tcb().SND.NXT).set_ack(0).set_flag(RST); - tcp.transmit(); + tcp.send_buffer_.clear(); + tcp.outgoing_packet()->set_seq(tcp.tcb().SND.NXT).set_ack(0).set_flag(RST); + tcp.transmit(); } /* - Fallback. + Fallback. */ void Connection::State::open(Connection&, bool) { - throw TCPException{"Connection already exists."}; + throw TCPException{"Connection already exists."}; } size_t Connection::State::send(Connection&, const char*, size_t, bool) { - throw TCPException{"Connection closing."}; + throw TCPException{"Connection closing."}; } size_t Connection::State::receive(Connection&, char*, size_t) { - throw TCPException{"Connection closing."}; + throw TCPException{"Connection closing."}; } void Connection::State::close(Connection&) { - throw TCPException{"Connection closing."}; + throw TCPException{"Connection closing."}; } void Connection::State::abort(Connection&) { - // Do nothing. + // Do nothing. } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /* - CLOSED + CLOSED */ ///////////////////////////////////////////////////////////////////// void Connection::Closed::open(Connection& tcp, bool active) { - if(active) { - // There is a remote host - if(!tcp.remote().is_empty()) { - auto& tcb = tcp.tcb(); - tcb.ISS = tcp.generate_iss(); - auto packet = tcp.outgoing_packet(); - packet->set_seq(tcb.ISS).set_flag(SYN); + if(active) { + // There is a remote host + if(!tcp.remote().is_empty()) { + auto& tcb = tcp.tcb(); + tcb.ISS = tcp.generate_iss(); + auto packet = tcp.outgoing_packet(); + packet->set_seq(tcb.ISS).set_flag(SYN); - /* - Add MSS option. - */ - tcp.add_option(Option::MSS, packet); - - tcb.SND.UNA = tcb.ISS; - tcb.SND.NXT = tcb.ISS+1; - tcp.transmit(); - tcp.set_state(SynSent::instance()); - } else { - throw TCPException{"No remote host set."}; - } - } else { - tcp.set_state(Connection::Listen::instance()); - } + /* + Add MSS option. + */ + tcp.add_option(Option::MSS, packet); + + tcb.SND.UNA = tcb.ISS; + tcb.SND.NXT = tcb.ISS+1; + tcp.transmit(); + tcp.set_state(SynSent::instance()); + } else { + throw TCPException{"No remote host set."}; + } + } else { + tcp.set_state(Connection::Listen::instance()); + } } size_t Connection::Closed::send(Connection&, const char*, size_t, bool) { - throw TCPException{"Connection does not exist."}; + throw TCPException{"Connection does not exist."}; } State::Result Connection::Closed::handle(Connection& tcp, TCP::Packet_ptr in) { - if(in->isset(RST)) { - return OK; - } - if(!in->isset(ACK)) { - tcp.outgoing_packet()->set_seq(0).set_ack(in->seq() + in->data_length()).set_flags(RST | ACK); - } else { - tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); - } - tcp.transmit(); - return OK; + if(in->isset(RST)) { + return OK; + } + if(!in->isset(ACK)) { + tcp.outgoing_packet()->set_seq(0).set_ack(in->seq() + in->data_length()).set_flags(RST | ACK); + } else { + tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); + } + tcp.transmit(); + return OK; } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /* - LISTEN + LISTEN */ ///////////////////////////////////////////////////////////////////// void Connection::Listen::open(Connection& tcp, bool) { - if(!tcp.remote().is_empty()) { - auto& tcb = tcp.tcb(); - tcb.ISS = tcp.generate_iss(); - tcp.outgoing_packet()->set_seq(tcb.ISS).set_flag(SYN); - tcb.SND.UNA = tcb.ISS; - tcb.SND.NXT = tcb.ISS+1; - tcp.transmit(); - tcp.set_state(SynSent::instance()); - } else { - throw TCPException{"No remote host set."}; - } + if(!tcp.remote().is_empty()) { + auto& tcb = tcp.tcb(); + tcb.ISS = tcp.generate_iss(); + tcp.outgoing_packet()->set_seq(tcb.ISS).set_flag(SYN); + tcb.SND.UNA = tcb.ISS; + tcb.SND.NXT = tcb.ISS+1; + tcp.transmit(); + tcp.set_state(SynSent::instance()); + } else { + throw TCPException{"No remote host set."}; + } } size_t Connection::Listen::send(Connection&, const char*, size_t, bool) { - // TODO: Skip this? - /* - If the foreign socket is specified, then change the connection - from passive to active, select an ISS. Send a SYN segment, set - SND.UNA to ISS, SND.NXT to ISS+1. Enter SYN-SENT state. Data - associated with SEND may be sent with SYN segment or queued for - transmission after entering ESTABLISHED state. The urgent bit if - requested in the command must be sent with the data segments sent - as a result of this command. If there is no room to queue the - request, respond with "error: insufficient resources". If - Foreign socket was not specified, then return "error: foreign - socket unspecified". - */ - - return 0; + // TODO: Skip this? + /* + If the foreign socket is specified, then change the connection + from passive to active, select an ISS. Send a SYN segment, set + SND.UNA to ISS, SND.NXT to ISS+1. Enter SYN-SENT state. Data + associated with SEND may be sent with SYN segment or queued for + transmission after entering ESTABLISHED state. The urgent bit if + requested in the command must be sent with the data segments sent + as a result of this command. If there is no room to queue the + request, respond with "error: insufficient resources". If + Foreign socket was not specified, then return "error: foreign + socket unspecified". + */ + + return 0; } void Connection::Listen::close(Connection& tcp) { - /* - Any outstanding RECEIVEs are returned with "error: closing" - responses. Delete TCB, enter CLOSED state, and return. - */ + /* + Any outstanding RECEIVEs are returned with "error: closing" + responses. Delete TCB, enter CLOSED state, and return. + */ - // tcp.signal_disconnect("Closing") - tcp.set_state(Closed::instance()); + // tcp.signal_disconnect("Closing") + tcp.set_state(Closed::instance()); } State::Result Connection::Listen::handle(Connection& tcp, TCP::Packet_ptr in) { - if(in->isset(RST)) { - // ignore - return OK; - } - if(in->isset(ACK)) { - tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); - tcp.transmit(); - return OK; - } - if(in->isset(SYN)) { - if(!tcp.signal_accept()) { - // TODO: Reject more gracefully? - return CLOSED; - } - auto& tcb = tcp.tcb(); - tcb.RCV.NXT = in->seq()+1; - tcb.IRS = in->seq(); - tcb.ISS = tcp.generate_iss(); - tcb.SND.NXT = tcb.ISS+1; - tcb.SND.UNA = tcb.ISS; - debug(" Received SYN Packet: %s TCB Updated:\n %s \n", - in->to_string().c_str(), tcp.tcb().to_string().c_str()); - - auto packet = tcp.outgoing_packet(); - packet->set_seq(tcb.ISS).set_ack(tcb.RCV.NXT).set_flags(SYN | ACK); + if(in->isset(RST)) { + // ignore + return OK; + } + if(in->isset(ACK)) { + tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); + tcp.transmit(); + return OK; + } + if(in->isset(SYN)) { + if(!tcp.signal_accept()) { + // TODO: Reject more gracefully? + return CLOSED; + } + auto& tcb = tcp.tcb(); + tcb.RCV.NXT = in->seq()+1; + tcb.IRS = in->seq(); + tcb.ISS = tcp.generate_iss(); + tcb.SND.NXT = tcb.ISS+1; + tcb.SND.UNA = tcb.ISS; + debug(" Received SYN Packet: %s TCB Updated:\n %s \n", + in->to_string().c_str(), tcp.tcb().to_string().c_str()); + + auto packet = tcp.outgoing_packet(); + packet->set_seq(tcb.ISS).set_ack(tcb.RCV.NXT).set_flags(SYN | ACK); - /* - Add MSS option. - TODO: Send even if we havent received MSS option? - */ - tcp.add_option(Option::MSS, packet); + /* + Add MSS option. + TODO: Send even if we havent received MSS option? + */ + tcp.add_option(Option::MSS, packet); - tcp.transmit(); - tcp.set_state(SynReceived::instance()); + tcp.transmit(); + tcp.set_state(SynReceived::instance()); - return OK; - } - return OK; + return OK; + } + return OK; } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /* - SYN-SENT + SYN-SENT */ ///////////////////////////////////////////////////////////////////// size_t Connection::SynSent::send(Connection& tcp, const char* buffer, size_t n, bool push) { - /* - Queue the data for transmission after entering ESTABLISHED state. - If no space to queue, respond with "error: insufficient - resources". - */ - return tcp.write_to_send_buffer(buffer, n, push); + /* + Queue the data for transmission after entering ESTABLISHED state. + If no space to queue, respond with "error: insufficient + resources". + */ + return tcp.write_to_send_buffer(buffer, n, push); } void Connection::SynSent::close(Connection& tcp) { - /* - Delete the TCB and return "error: closing" responses to any - queued SENDs, or RECEIVEs. - */ + /* + Delete the TCB and return "error: closing" responses to any + queued SENDs, or RECEIVEs. + */ - // tcp.signal_disconnect("Closing") - tcp.set_state(Closed::instance()); + // tcp.signal_disconnect("Closing") + tcp.set_state(Closed::instance()); } State::Result Connection::SynSent::handle(Connection& tcp, TCP::Packet_ptr in) { - auto& tcb = tcp.tcb(); - // 1. check ACK - if(in->isset(ACK)) { - // If SEG.ACK =< ISS, or SEG.ACK > SND.NXT - if(in->ack() <= tcb.ISS or in->ack() > tcb.SND.NXT) { - // send a reset - if(!in->isset(RST)) { - tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); - tcp.transmit(); - return OK; - } - // (unless the RST bit is set, if so drop the segment and return) - else { - tcp.drop(in, "RST"); - return OK; - } - // If SND.UNA =< SEG.ACK =< SND.NXT then the ACK is acceptable. - } - } - // 2. check RST - if(in->isset(RST)) { - if(in->isset(ACK)) { - tcp.signal_error(TCPException{"Connection reset."}); - tcp.drop(in, "RST with acceptable ACK"); - return CLOSED; - } else { - tcp.drop(in, "RST"); - return OK; - } - /* - If the ACK was acceptable then signal the user "error: - connection reset", drop the segment, enter CLOSED state, - delete TCB, and return. Otherwise (no ACK) drop the segment - and return. - */ - - } - // 3. Check security - - // 4. check SYN - /* - This step should be reached only if the ACK is ok, or there is - no ACK, and it the segment did not contain a RST. - - If the SYN bit is on and the security/compartment and precedence - are acceptable then, RCV.NXT is set to SEG.SEQ+1, IRS is set to - SEG.SEQ. SND.UNA should be advanced to equal SEG.ACK (if there - is an ACK), and any segments on the retransmission queue which - are thereby acknowledged should be removed. - - If SND.UNA > ISS (our SYN has been ACKed), change the connection - state to ESTABLISHED, form an ACK segment - - - - and send it. Data or controls which were queued for - transmission may be included. If there are other controls or - text in the segment then continue processing at the sixth step - below where the URG bit is checked, otherwise return. - - Otherwise enter SYN-RECEIVED, form a SYN,ACK segment - - - - and send it. If there are other controls or text in the - segment, queue them for processing after the ESTABLISHED state - has been reached, return. - */ + auto& tcb = tcp.tcb(); + // 1. check ACK + if(in->isset(ACK)) { + // If SEG.ACK =< ISS, or SEG.ACK > SND.NXT + if(in->ack() <= tcb.ISS or in->ack() > tcb.SND.NXT) { + // send a reset + if(!in->isset(RST)) { + tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); + tcp.transmit(); + return OK; + } + // (unless the RST bit is set, if so drop the segment and return) + else { + tcp.drop(in, "RST"); + return OK; + } + // If SND.UNA =< SEG.ACK =< SND.NXT then the ACK is acceptable. + } + } + // 2. check RST + if(in->isset(RST)) { + if(in->isset(ACK)) { + tcp.signal_error(TCPException{"Connection reset."}); + tcp.drop(in, "RST with acceptable ACK"); + return CLOSED; + } else { + tcp.drop(in, "RST"); + return OK; + } /* - TODO: Fix this one according to the text above. + If the ACK was acceptable then signal the user "error: + connection reset", drop the segment, enter CLOSED state, + delete TCB, and return. Otherwise (no ACK) drop the segment + and return. */ - if(in->isset(SYN)) { - tcb.RCV.NXT = in->seq()+1; - tcb.IRS = in->seq(); - tcb.SND.UNA = in->ack(); + + } + // 3. Check security + + // 4. check SYN + /* + This step should be reached only if the ACK is ok, or there is + no ACK, and it the segment did not contain a RST. + + If the SYN bit is on and the security/compartment and precedence + are acceptable then, RCV.NXT is set to SEG.SEQ+1, IRS is set to + SEG.SEQ. SND.UNA should be advanced to equal SEG.ACK (if there + is an ACK), and any segments on the retransmission queue which + are thereby acknowledged should be removed. + + If SND.UNA > ISS (our SYN has been ACKed), change the connection + state to ESTABLISHED, form an ACK segment + + + + and send it. Data or controls which were queued for + transmission may be included. If there are other controls or + text in the segment then continue processing at the sixth step + below where the URG bit is checked, otherwise return. + + Otherwise enter SYN-RECEIVED, form a SYN,ACK segment + + + + and send it. If there are other controls or text in the + segment, queue them for processing after the ESTABLISHED state + has been reached, return. + */ + /* + TODO: Fix this one according to the text above. + */ + if(in->isset(SYN)) { + tcb.RCV.NXT = in->seq()+1; + tcb.IRS = in->seq(); + tcb.SND.UNA = in->ack(); - // (our SYN has been ACKed) - if(tcb.SND.UNA > tcb.ISS) { - tcp.set_state(Connection::Established::instance()); - TCP::Seq snd_nxt = tcb.SND.NXT; - tcp.signal_connect(); // NOTE: User callback - if(tcb.SND.NXT == snd_nxt) { - tcp.outgoing_packet()->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); - tcp.transmit(); - } - // State is now ESTABLISHED. - // Experimental, also makes unessecary process. - //in->clear_flag(SYN); - //tcp.state().handle(tcp, in); + // (our SYN has been ACKed) + if(tcb.SND.UNA > tcb.ISS) { + tcp.set_state(Connection::Established::instance()); + TCP::Seq snd_nxt = tcb.SND.NXT; + tcp.signal_connect(); // NOTE: User callback + if(tcb.SND.NXT == snd_nxt) { + tcp.outgoing_packet()->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); + tcp.transmit(); + } + // State is now ESTABLISHED. + // Experimental, also makes unessecary process. + //in->clear_flag(SYN); + //tcp.state().handle(tcp, in); - // 7. process segment text - if(in->has_data()) { - process_segment(tcp, in); - } - - // 8. check FIN bit - if(in->isset(FIN)) { - process_fin(tcp, in); - tcp.set_state(Connection::CloseWait::instance()); - return OK; - } - return OK; - } - // Otherwise enter SYN-RECEIVED, form a SYN,ACK segment - else { - tcp.outgoing_packet()->set_seq(tcb.ISS).set_ack(tcb.RCV.NXT).set_flags(SYN | ACK); - tcp.transmit(); - tcp.set_state(Connection::SynReceived::instance()); - if(in->has_data()) { - tcp.add_to_receive_buffer(in); - // Advance RCV.NXT ?? - tcb.RCV.NXT += in->data_length(); - } - return OK; - /* - If there are other controls or text in the - segment, queue them for processing after the ESTABLISHED state - has been reached, return. - - HOW? return tcp.receive(in); ? - */ - } + // 7. process segment text + if(in->has_data()) { + process_segment(tcp, in); + } + + // 8. check FIN bit + if(in->isset(FIN)) { + process_fin(tcp, in); + tcp.set_state(Connection::CloseWait::instance()); + return OK; + } + return OK; } - tcp.drop(in); - return OK; + // Otherwise enter SYN-RECEIVED, form a SYN,ACK segment + else { + tcp.outgoing_packet()->set_seq(tcb.ISS).set_ack(tcb.RCV.NXT).set_flags(SYN | ACK); + tcp.transmit(); + tcp.set_state(Connection::SynReceived::instance()); + if(in->has_data()) { + tcp.add_to_receive_buffer(in); + // Advance RCV.NXT ?? + tcb.RCV.NXT += in->data_length(); + } + return OK; + /* + If there are other controls or text in the + segment, queue them for processing after the ESTABLISHED state + has been reached, return. + + HOW? return tcp.receive(in); ? + */ + } + } + tcp.drop(in); + return OK; } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /* - SYN-RECEIVED + SYN-RECEIVED */ ///////////////////////////////////////////////////////////////////// size_t Connection::SynReceived::send(Connection& tcp, const char* buffer, size_t n, bool push) { - /* - Queue the data for transmission after entering ESTABLISHED state. - If no space to queue, respond with "error: insufficient - resources". - */ - return tcp.write_to_send_buffer(buffer, n, push); + /* + Queue the data for transmission after entering ESTABLISHED state. + If no space to queue, respond with "error: insufficient + resources". + */ + return tcp.write_to_send_buffer(buffer, n, push); } void Connection::SynReceived::close(Connection& tcp) { - /* - If no SENDs have been issued and there is no pending data to send, - then form a FIN segment and send it, and enter FIN-WAIT-1 state; - otherwise queue for processing after entering ESTABLISHED state. - */ - // Dont know how to queue for close for processing... - auto& tcb = tcp.tcb(); - tcp.outgoing_packet()->set_seq(tcb.SND.NXT++).set_ack(tcb.RCV.NXT).set_flags(ACK | FIN); - tcp.transmit(); - tcp.set_state(Connection::FinWait1::instance()); + /* + If no SENDs have been issued and there is no pending data to send, + then form a FIN segment and send it, and enter FIN-WAIT-1 state; + otherwise queue for processing after entering ESTABLISHED state. + */ + // Dont know how to queue for close for processing... + auto& tcb = tcp.tcb(); + tcp.outgoing_packet()->set_seq(tcb.SND.NXT++).set_ack(tcb.RCV.NXT).set_flags(ACK | FIN); + tcp.transmit(); + tcp.set_state(Connection::FinWait1::instance()); } void Connection::SynReceived::abort(Connection& tcp) { - send_reset(tcp); + send_reset(tcp); } State::Result Connection::SynReceived::handle(Connection& tcp, TCP::Packet_ptr in) { - // 1. check sequence - if(! check_seq(tcp, in) ) { - return OK; - } - // 2. check RST - if(in->isset(RST)) { - /* - If this connection was initiated with a passive OPEN (i.e., - came from the LISTEN state), then return this connection to - LISTEN state and return. The user need not be informed. If - this connection was initiated with an active OPEN (i.e., came - from SYN-SENT state) then the connection was refused, signal - the user "connection refused". In either case, all segments - on the retransmission queue should be removed. And in the - active OPEN case, enter the CLOSED state and delete the TCB, - and return. - */ - // Since we create a new connection when it starts listening, we don't wanna do this, but just delete it. - - if(tcp.prev_state().to_string() == Connection::SynSent::instance().to_string()) { - tcp.signal_disconnect(Disconnect::REFUSED); - } - - return CLOSED; - } - // 3. check security - - // 4. check SYN - if( in->isset(SYN) ) { - unallowed_syn_reset_connection(tcp, in); - return CLOSED; - } - - // 5. check ACK - if(in->isset(ACK)) { - auto& tcb = tcp.tcb(); - /* - If SND.UNA =< SEG.ACK =< SND.NXT then enter ESTABLISHED state - and continue processing. - */ - if(tcb.SND.UNA <= in->ack() and in->ack() <= tcb.SND.NXT) { - debug(" SND.UNA =< SEG.ACK =< SND.NXT, continue in ESTABLISHED. \n"); - tcp.set_state(Connection::Established::instance()); - tcp.signal_connect(); // NOTE: User callback - return tcp.state().handle(tcp,in); // TODO: Fix. This is kinda bad, need to make the above steps again. - } - /* - If the segment acknowledgment is not acceptable, form a - reset segment, and send it. - */ - else { - tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); - tcp.transmit(); - } - } - // ACK is missing - else { - tcp.drop(in, "SYN-RCV: !ACK"); - return OK; - } - - // 8. check FIN - if(in->isset(FIN)) { - process_fin(tcp, in); - tcp.set_state(Connection::CloseWait::instance()); - return OK; - } - return OK; + // 1. check sequence + if(! check_seq(tcp, in) ) { + return OK; + } + // 2. check RST + if(in->isset(RST)) { + /* + If this connection was initiated with a passive OPEN (i.e., + came from the LISTEN state), then return this connection to + LISTEN state and return. The user need not be informed. If + this connection was initiated with an active OPEN (i.e., came + from SYN-SENT state) then the connection was refused, signal + the user "connection refused". In either case, all segments + on the retransmission queue should be removed. And in the + active OPEN case, enter the CLOSED state and delete the TCB, + and return. + */ + // Since we create a new connection when it starts listening, we don't wanna do this, but just delete it. + + if(tcp.prev_state().to_string() == Connection::SynSent::instance().to_string()) { + tcp.signal_disconnect(Disconnect::REFUSED); + } + + return CLOSED; + } + // 3. check security + + // 4. check SYN + if( in->isset(SYN) ) { + unallowed_syn_reset_connection(tcp, in); + return CLOSED; + } + + // 5. check ACK + if(in->isset(ACK)) { + auto& tcb = tcp.tcb(); + /* + If SND.UNA =< SEG.ACK =< SND.NXT then enter ESTABLISHED state + and continue processing. + */ + if(tcb.SND.UNA <= in->ack() and in->ack() <= tcb.SND.NXT) { + debug(" SND.UNA =< SEG.ACK =< SND.NXT, continue in ESTABLISHED. \n"); + tcp.set_state(Connection::Established::instance()); + tcp.signal_connect(); // NOTE: User callback + return tcp.state().handle(tcp,in); // TODO: Fix. This is kinda bad, need to make the above steps again. + } + /* + If the segment acknowledgment is not acceptable, form a + reset segment, and send it. + */ + else { + tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); + tcp.transmit(); + } + } + // ACK is missing + else { + tcp.drop(in, "SYN-RCV: !ACK"); + return OK; + } + + // 8. check FIN + if(in->isset(FIN)) { + process_fin(tcp, in); + tcp.set_state(Connection::CloseWait::instance()); + return OK; + } + return OK; } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /* - ESTABLISHED + ESTABLISHED */ ///////////////////////////////////////////////////////////////////// /* - Segmentize the buffer and send it with a piggybacked - acknowledgment (acknowledgment value = RCV.NXT). If there is - insufficient space to remember this buffer, simply return "error: - insufficient resources". + Segmentize the buffer and send it with a piggybacked + acknowledgment (acknowledgment value = RCV.NXT). If there is + insufficient space to remember this buffer, simply return "error: + insufficient resources". - If the urgent flag is set, then SND.UP <- SND.NXT-1 and set the - urgent pointer in the outgoing segments. + If the urgent flag is set, then SND.UP <- SND.NXT-1 and set the + urgent pointer in the outgoing segments. */ size_t Connection::Established::send(Connection& tcp, const char* buffer, size_t n, bool push) { - debug(" Sending data with the length of %u. PUSH: %d \n", n, push); - auto bytes_written = tcp.write_to_send_buffer(buffer, n, push); - tcp.transmit(); - return bytes_written; - /* - 3.7 Data Communication - The sender of data keeps track of the next sequence number to use in - the variable SND.NXT. The receiver of data keeps track of the next - sequence number to expect in the variable RCV.NXT. The sender of data - keeps track of the oldest unacknowledged sequence number in the - variable SND.UNA. If the data flow is momentarily idle and all data - sent has been acknowledged then the three variables will be equal. - - When the sender creates a segment and transmits it the sender advances - SND.NXT. When the receiver accepts a segment it advances RCV.NXT and - sends an acknowledgment. When the data sender receives an - acknowledgment it advances SND.UNA. The extent to which the values of - these variables differ is a measure of the delay in the communication. - The amount by which the variables are advanced is the length of the - data in the segment. Note that once in the ESTABLISHED state all - segments must carry current acknowledgment information. - */ + debug(" Sending data with the length of %u. PUSH: %d \n", n, push); + auto bytes_written = tcp.write_to_send_buffer(buffer, n, push); + tcp.transmit(); + return bytes_written; + /* + 3.7 Data Communication + The sender of data keeps track of the next sequence number to use in + the variable SND.NXT. The receiver of data keeps track of the next + sequence number to expect in the variable RCV.NXT. The sender of data + keeps track of the oldest unacknowledged sequence number in the + variable SND.UNA. If the data flow is momentarily idle and all data + sent has been acknowledged then the three variables will be equal. + + When the sender creates a segment and transmits it the sender advances + SND.NXT. When the receiver accepts a segment it advances RCV.NXT and + sends an acknowledgment. When the data sender receives an + acknowledgment it advances SND.UNA. The extent to which the values of + these variables differ is a measure of the delay in the communication. + The amount by which the variables are advanced is the length of the + data in the segment. Note that once in the ESTABLISHED state all + segments must carry current acknowledgment information. + */ } size_t Connection::Established::receive(Connection& tcp, char* buffer, size_t n) { - return tcp.read_from_receive_buffer(buffer, n); + return tcp.read_from_receive_buffer(buffer, n); } void Connection::Established::close(Connection& tcp) { - auto& tcb = tcp.tcb(); - tcp.outgoing_packet()->set_seq(tcb.SND.NXT++).set_ack(tcb.RCV.NXT).set_flags(ACK | FIN); - tcp.transmit(); - tcp.set_state(Connection::FinWait1::instance()); + auto& tcb = tcp.tcb(); + tcp.outgoing_packet()->set_seq(tcb.SND.NXT++).set_ack(tcb.RCV.NXT).set_flags(ACK | FIN); + tcp.transmit(); + tcp.set_state(Connection::FinWait1::instance()); } void Connection::Established::abort(Connection& tcp) { - send_reset(tcp); + send_reset(tcp); } State::Result Connection::Established::handle(Connection& tcp, TCP::Packet_ptr in) { - // 1. check SEQ - if(! check_seq(tcp, in) ) { - return OK; - } - - // 2. check RST - if( in->isset(RST) ) { - tcp.signal_disconnect(Disconnect::RESET); - return CLOSED; // close - } + // 1. check SEQ + if(! check_seq(tcp, in) ) { + return OK; + } - // 3. check security + // 2. check RST + if( in->isset(RST) ) { + tcp.signal_disconnect(Disconnect::RESET); + return CLOSED; // close + } - // 4. check SYN - if( in->isset(SYN) ) { - unallowed_syn_reset_connection(tcp, in); - return CLOSED; - } + // 3. check security - // 5. check ACK - if( ! check_ack(tcp, in) ) { - return OK; - } - // 6. check URG - DEPRECATED - - // 7. proccess the segment text - if(in->has_data()) { - process_segment(tcp, in); - } + // 4. check SYN + if( in->isset(SYN) ) { + unallowed_syn_reset_connection(tcp, in); + return CLOSED; + } - // 8. check FIN bit - if(in->isset(FIN)) { - process_fin(tcp, in); - tcp.set_state(Connection::CloseWait::instance()); - return CLOSE; - } - return OK; + // 5. check ACK + if( ! check_ack(tcp, in) ) { + return OK; + } + // 6. check URG - DEPRECATED + + // 7. proccess the segment text + if(in->has_data()) { + process_segment(tcp, in); + } + + // 8. check FIN bit + if(in->isset(FIN)) { + process_fin(tcp, in); + tcp.set_state(Connection::CloseWait::instance()); + return CLOSE; + } + return OK; } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /* - FIN-WAIT-1 + FIN-WAIT-1 */ ///////////////////////////////////////////////////////////////////// size_t Connection::FinWait1::receive(Connection& tcp, char* buffer, size_t n) { - return tcp.read_from_receive_buffer(buffer, n); + return tcp.read_from_receive_buffer(buffer, n); } void Connection::FinWait1::close(Connection&) { @@ -881,78 +881,78 @@ void Connection::FinWait1::close(Connection&) { } void Connection::FinWait1::abort(Connection& tcp) { - send_reset(tcp); + send_reset(tcp); } State::Result Connection::FinWait1::handle(Connection& tcp, TCP::Packet_ptr in) { - // 1. Check sequence number - if(! check_seq(tcp, in) ) { - return OK; - } - - // 2. check RST - if( in->isset(RST) ) { - tcp.signal_disconnect(Disconnect::RESET); - return CLOSED; // close - } - - // 4. check SYN - if( in->isset(SYN) ) { - unallowed_syn_reset_connection(tcp, in); - return CLOSED; - } - - // 5. check ACK - if( ! check_ack(tcp, in) ) { - return OK; - } + // 1. Check sequence number + if(! check_seq(tcp, in) ) { + return OK; + } + + // 2. check RST + if( in->isset(RST) ) { + tcp.signal_disconnect(Disconnect::RESET); + return CLOSED; // close + } + + // 4. check SYN + if( in->isset(SYN) ) { + unallowed_syn_reset_connection(tcp, in); + return CLOSED; + } + + // 5. check ACK + if( ! check_ack(tcp, in) ) { + return OK; + } + /* + In addition to the processing for the ESTABLISHED state, if + our FIN is now acknowledged then enter FIN-WAIT-2 and continue + processing in that state. + */ + debug2(" Current TCB:\n %s \n", tcp.tcb().to_string().c_str()); + if(in->ack() == tcp.tcb().SND.NXT) { + // TODO: I guess or FIN is ACK'ed..? + tcp.set_state(Connection::FinWait2::instance()); + return tcp.state().handle(tcp, in); // TODO: Is this OK? + } + + // 7. proccess the segment text + if(in->has_data()) { + process_segment(tcp, in); + } + + // 8. check FIN + if(in->isset(FIN)) { + process_fin(tcp, in); + debug2(" FIN isset. TCB:\n %s \n", tcp.tcb().to_string().c_str()); /* - In addition to the processing for the ESTABLISHED state, if - our FIN is now acknowledged then enter FIN-WAIT-2 and continue - processing in that state. + If our FIN has been ACKed (perhaps in this segment), then + enter TIME-WAIT, start the time-wait timer, turn off the other + timers; otherwise enter the CLOSING state. */ - debug2(" Current TCB:\n %s \n", tcp.tcb().to_string().c_str()); if(in->ack() == tcp.tcb().SND.NXT) { - // TODO: I guess or FIN is ACK'ed..? - tcp.set_state(Connection::FinWait2::instance()); - return tcp.state().handle(tcp, in); // TODO: Is this OK? + // TODO: I guess or FIN is ACK'ed..? + tcp.set_state(TimeWait::instance()); + tcp.start_time_wait_timeout(); + } else { + tcp.set_state(Closing::instance()); } - - // 7. proccess the segment text - if(in->has_data()) { - process_segment(tcp, in); - } - - // 8. check FIN - if(in->isset(FIN)) { - process_fin(tcp, in); - debug2(" FIN isset. TCB:\n %s \n", tcp.tcb().to_string().c_str()); - /* - If our FIN has been ACKed (perhaps in this segment), then - enter TIME-WAIT, start the time-wait timer, turn off the other - timers; otherwise enter the CLOSING state. - */ - if(in->ack() == tcp.tcb().SND.NXT) { - // TODO: I guess or FIN is ACK'ed..? - tcp.set_state(TimeWait::instance()); - tcp.start_time_wait_timeout(); - } else { - tcp.set_state(Closing::instance()); - } - } - return OK; + } + return OK; } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /* - FIN-WAIT-2 + FIN-WAIT-2 */ ///////////////////////////////////////////////////////////////////// size_t Connection::FinWait2::receive(Connection& tcp, char* buffer, size_t n) { - return tcp.read_from_receive_buffer(buffer, n); + return tcp.read_from_receive_buffer(buffer, n); } void Connection::FinWait2::close(Connection&) { @@ -960,247 +960,247 @@ void Connection::FinWait2::close(Connection&) { } void Connection::FinWait2::abort(Connection& tcp) { - send_reset(tcp); + send_reset(tcp); } State::Result Connection::FinWait2::handle(Connection& tcp, TCP::Packet_ptr in) { - // 1. check SEQ - if(! check_seq(tcp, in) ) { - return OK; - } - - // 2. check RST - if( in->isset(RST) ) { - tcp.signal_disconnect(Disconnect::RESET); - return CLOSED; // close - } - - // 4. check SYN - if( in->isset(SYN) ) { - unallowed_syn_reset_connection(tcp, in); - return CLOSED; - } - - // 5. check ACK - if( ! check_ack(tcp, in) ) { - return OK; - } + // 1. check SEQ + if(! check_seq(tcp, in) ) { + return OK; + } + + // 2. check RST + if( in->isset(RST) ) { + tcp.signal_disconnect(Disconnect::RESET); + return CLOSED; // close + } + + // 4. check SYN + if( in->isset(SYN) ) { + unallowed_syn_reset_connection(tcp, in); + return CLOSED; + } + + // 5. check ACK + if( ! check_ack(tcp, in) ) { + return OK; + } - // 7. proccess the segment text - if(in->has_data()) { - process_segment(tcp, in); - } + // 7. proccess the segment text + if(in->has_data()) { + process_segment(tcp, in); + } - // 8. check FIN - if(in->isset(FIN)) { - process_fin(tcp, in); - /* - Enter the TIME-WAIT state. Start the time-wait timer, turn off the other timers. - */ - tcp.set_state(Connection::TimeWait::instance()); - tcp.start_time_wait_timeout(); - } - return OK; + // 8. check FIN + if(in->isset(FIN)) { + process_fin(tcp, in); + /* + Enter the TIME-WAIT state. Start the time-wait timer, turn off the other timers. + */ + tcp.set_state(Connection::TimeWait::instance()); + tcp.start_time_wait_timeout(); + } + return OK; } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /* - CLOSE-WAIT + CLOSE-WAIT */ ///////////////////////////////////////////////////////////////////// size_t Connection::CloseWait::send(Connection& tcp, const char* buffer, size_t n, bool push) { - debug(" Sending data with the length of %u. PUSH: %d \n", n, push); - auto bytes_written = tcp.write_to_send_buffer(buffer, n, push); - tcp.transmit(); - return bytes_written; + debug(" Sending data with the length of %u. PUSH: %d \n", n, push); + auto bytes_written = tcp.write_to_send_buffer(buffer, n, push); + tcp.transmit(); + return bytes_written; } size_t Connection::CloseWait::receive(Connection& tcp, char* buffer, size_t n) { - return tcp.read_from_receive_buffer(buffer, n); + return tcp.read_from_receive_buffer(buffer, n); } void Connection::CloseWait::close(Connection& tcp) { - /* - Queue this request until all preceding SENDs have been - segmentized; then send a FIN segment, enter CLOSING state. - */ - auto& tcb = tcp.tcb(); - tcp.outgoing_packet()->set_seq(tcb.SND.NXT++).set_ack(tcb.RCV.NXT).set_flags(ACK | FIN); - tcp.transmit(); - tcp.set_state(Connection::Closing::instance()); + /* + Queue this request until all preceding SENDs have been + segmentized; then send a FIN segment, enter CLOSING state. + */ + auto& tcb = tcp.tcb(); + tcp.outgoing_packet()->set_seq(tcb.SND.NXT++).set_ack(tcb.RCV.NXT).set_flags(ACK | FIN); + tcp.transmit(); + tcp.set_state(Connection::Closing::instance()); } void Connection::CloseWait::abort(Connection& tcp) { - send_reset(tcp); + send_reset(tcp); } State::Result Connection::CloseWait::handle(Connection& tcp, TCP::Packet_ptr in) { - // 1. check SEQ - if(! check_seq(tcp, in) ) { - return OK; - } - - // 2. check RST - if( in->isset(RST) ) { - tcp.signal_disconnect(Disconnect::RESET); - return CLOSED; // close - } - - // 4. check SYN - if( in->isset(SYN) ) { - unallowed_syn_reset_connection(tcp, in); - return CLOSED; - } - - // 5. check ACK - if( ! check_ack(tcp, in) ) { - return OK; - } + // 1. check SEQ + if(! check_seq(tcp, in) ) { + return OK; + } + + // 2. check RST + if( in->isset(RST) ) { + tcp.signal_disconnect(Disconnect::RESET); + return CLOSED; // close + } + + // 4. check SYN + if( in->isset(SYN) ) { + unallowed_syn_reset_connection(tcp, in); + return CLOSED; + } + + // 5. check ACK + if( ! check_ack(tcp, in) ) { + return OK; + } - // 7. proccess the segment text - // This should not occur, since a FIN has been received from the remote side. Ignore the segment text. + // 7. proccess the segment text + // This should not occur, since a FIN has been received from the remote side. Ignore the segment text. - // 8. check FIN - if(in->isset(FIN)) { - process_fin(tcp, in); - // Remain in state - return OK; - } + // 8. check FIN + if(in->isset(FIN)) { + process_fin(tcp, in); + // Remain in state return OK; + } + return OK; } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /* - CLOSING + CLOSING */ ///////////////////////////////////////////////////////////////////// State::Result Connection::Closing::handle(Connection& tcp, TCP::Packet_ptr in) { - // 1. Check sequence number - if(! check_seq(tcp, in) ) { - return OK; - } - - // 2. check RST - if( in->isset(RST) ) { - return CLOSED; // close - } - - // 4. check SYN - if( in->isset(SYN) ) { - unallowed_syn_reset_connection(tcp, in); - return CLOSED; - } - - // 5. check ACK - if( ! check_ack(tcp, in)) { - return CLOSED; - } - /* - In addition to the processing for the ESTABLISHED state, if - the ACK acknowledges our FIN then enter the TIME-WAIT state, - otherwise ignore the segment. - */ - if(in->ack() == tcp.tcb().SND.NXT) { - // TODO: I guess or FIN is ACK'ed..? - tcp.set_state(TimeWait::instance()); - tcp.start_time_wait_timeout(); - } - - - // 7. proccess the segment text - // This should not occur, since a FIN has been received from the remote side. Ignore the segment text. - - // 8. check FIN - if(in->isset(FIN)) { - process_fin(tcp, in); - // Remain in state - return OK; - } + // 1. Check sequence number + if(! check_seq(tcp, in) ) { + return OK; + } + + // 2. check RST + if( in->isset(RST) ) { + return CLOSED; // close + } + + // 4. check SYN + if( in->isset(SYN) ) { + unallowed_syn_reset_connection(tcp, in); + return CLOSED; + } + + // 5. check ACK + if( ! check_ack(tcp, in)) { + return CLOSED; + } + /* + In addition to the processing for the ESTABLISHED state, if + the ACK acknowledges our FIN then enter the TIME-WAIT state, + otherwise ignore the segment. + */ + if(in->ack() == tcp.tcb().SND.NXT) { + // TODO: I guess or FIN is ACK'ed..? + tcp.set_state(TimeWait::instance()); + tcp.start_time_wait_timeout(); + } + + + // 7. proccess the segment text + // This should not occur, since a FIN has been received from the remote side. Ignore the segment text. + + // 8. check FIN + if(in->isset(FIN)) { + process_fin(tcp, in); + // Remain in state return OK; + } + return OK; } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /* - LAST-ACK + LAST-ACK */ ///////////////////////////////////////////////////////////////////// State::Result Connection::LastAck::handle(Connection& tcp, TCP::Packet_ptr in) { - // 1. Check sequence number - if(! check_seq(tcp, in) ) { - return OK; - } - - // 2. check RST - if( in->isset(RST) ) { - return CLOSED; // close - } - - // 4. check SYN - if( in->isset(SYN) ) { - unallowed_syn_reset_connection(tcp, in); - return CLOSED; - } - - if( ! check_ack(tcp, in)) { - return CLOSED; - } - - // 7. proccess the segment text - // This should not occur, since a FIN has been received from the remote side. Ignore the segment text. - - // 8. check FIN - if(in->isset(FIN)) { - process_fin(tcp, in); - // Remain in state - return OK; - } + // 1. Check sequence number + if(! check_seq(tcp, in) ) { return OK; + } + + // 2. check RST + if( in->isset(RST) ) { + return CLOSED; // close + } + + // 4. check SYN + if( in->isset(SYN) ) { + unallowed_syn_reset_connection(tcp, in); + return CLOSED; + } + + if( ! check_ack(tcp, in)) { + return CLOSED; + } + + // 7. proccess the segment text + // This should not occur, since a FIN has been received from the remote side. Ignore the segment text. + + // 8. check FIN + if(in->isset(FIN)) { + process_fin(tcp, in); + // Remain in state + return OK; + } + return OK; } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /* - TIME-WAIT + TIME-WAIT */ ///////////////////////////////////////////////////////////////////// State::Result Connection::TimeWait::handle(Connection& tcp, TCP::Packet_ptr in) { - // 1. Check sequence number - if(! check_seq(tcp, in) ) { - return OK; - } - - // 2. check RST - if( in->isset(RST) ) { - return CLOSED; // close - } - - // 4. check SYN - if( in->isset(SYN) ) { - unallowed_syn_reset_connection(tcp, in); - return CLOSED; - } - - // 7. proccess the segment text - // This should not occur, since a FIN has been received from the remote side. Ignore the segment text. - - // 8. check FIN - if(in->isset(FIN)) { - process_fin(tcp, in); - // Remain in state - tcp.start_time_wait_timeout(); - return OK; - } + // 1. Check sequence number + if(! check_seq(tcp, in) ) { + return OK; + } + + // 2. check RST + if( in->isset(RST) ) { + return CLOSED; // close + } + + // 4. check SYN + if( in->isset(SYN) ) { + unallowed_syn_reset_connection(tcp, in); + return CLOSED; + } + + // 7. proccess the segment text + // This should not occur, since a FIN has been received from the remote side. Ignore the segment text. + + // 8. check FIN + if(in->isset(FIN)) { + process_fin(tcp, in); + // Remain in state + tcp.start_time_wait_timeout(); return OK; + } + return OK; } ///////////////////////////////////////////////////////////////////// diff --git a/src/virtio/block.cpp b/src/virtio/block.cpp index 534d1665bd..6c42fff3b7 100644 --- a/src/virtio/block.cpp +++ b/src/virtio/block.cpp @@ -29,41 +29,41 @@ #define FEAT(x) (1 << x) VirtioBlk::VirtioBlk(hw::PCI_Device& d) - : Virtio(d), - req(queue_size(0), 0, iobase()), - request_counter(0) +: Virtio(d), + req(queue_size(0), 0, iobase()), + request_counter(0) { INFO("VirtioBlk", "Driver initializing"); uint32_t needed_features = - FEAT(VIRTIO_BLK_F_BLK_SIZE); + FEAT(VIRTIO_BLK_F_BLK_SIZE); negotiate_features(needed_features); CHECK(features() & FEAT(VIRTIO_BLK_F_BARRIER), - "Barrier is enabled"); + "Barrier is enabled"); CHECK(features() & FEAT(VIRTIO_BLK_F_SIZE_MAX), - "Size-max is known"); + "Size-max is known"); CHECK(features() & FEAT(VIRTIO_BLK_F_SEG_MAX), - "Seg-max is known"); + "Seg-max is known"); CHECK(features() & FEAT(VIRTIO_BLK_F_GEOMETRY), - "Geometry structure is used"); + "Geometry structure is used"); CHECK(features() & FEAT(VIRTIO_BLK_F_RO), - "Device is read-only"); + "Device is read-only"); CHECK(features() & FEAT(VIRTIO_BLK_F_BLK_SIZE), - "Block-size is known"); + "Block-size is known"); CHECK(features() & FEAT(VIRTIO_BLK_F_SCSI), - "SCSI is enabled :("); + "SCSI is enabled :("); CHECK(features() & FEAT(VIRTIO_BLK_F_FLUSH), - "Flush enabled"); + "Flush enabled"); CHECK ((features() & needed_features) == needed_features, - "Negotiated needed features"); + "Negotiated needed features"); // Step 1 - Initialize REQ queue auto success = assign_queue(0, (uint32_t) req.queue_desc()); CHECK(success, "Request queue assigned (0x%x) to device", - (uint32_t) req.queue_desc()); + (uint32_t) req.queue_desc()); // Step 3 - Fill receive queue with buffers // DEBUG: Disable @@ -84,7 +84,7 @@ VirtioBlk::VirtioBlk(hw::PCI_Device& d) // Done INFO("VirtioBlk", "Block device with %llu sectors capacity", - config.capacity); + config.capacity); //CHECK(config.status == VIRTIO_BLK_S_OK, "Link up\n"); req.kick(); } @@ -105,21 +105,21 @@ void VirtioBlk::irq_handler() // Step 2. A) - one of the queues have changed if (isr & 1) - { - // This now means service RX & TX interchangeably - service_RX(); - } + { + // This now means service RX & TX interchangeably + service_RX(); + } // Step 2. B) if (isr & 2) - { - debug("\t Configuration change:\n"); + { + debug("\t Configuration change:\n"); - // Getting the MAC + status - //debug("\t Old status: 0x%x\n", config.status); - get_config(); - //debug("\t New status: 0x%x \n", config.status); - } + // Getting the MAC + status + //debug("\t Old status: 0x%x\n", config.status); + get_config(); + //debug("\t New status: 0x%x \n", config.status); + } IRQ_manager::eoi(irq()); } @@ -134,28 +134,28 @@ void VirtioBlk::service_RX() //printf("service_RX() reading from VirtioBlk device\n"); while ((hdr = (request_t*) req.dequeue(len)) != nullptr) - { - printf("service_RX() received %u bytes for sector %llu\n", - len, hdr->hdr.sector); - vbr = &hdr->data; + { + printf("service_RX() received %u bytes for sector %llu\n", + len, hdr->hdr.sector); + vbr = &hdr->data; - printf("service_RX() received %u bytes data response\n", len); - printf("Received handler: %p\n", vbr->handler); + printf("service_RX() received %u bytes data response\n", len); + printf("Received handler: %p\n", vbr->handler); - uint8_t* copy = new uint8_t[SECTOR_SIZE]; - memcpy(copy, vbr->sector, SECTOR_SIZE); - auto buf = buffer_t(copy, std::default_delete()); + uint8_t* copy = new uint8_t[SECTOR_SIZE]; + memcpy(copy, vbr->sector, SECTOR_SIZE); + auto buf = buffer_t(copy, std::default_delete()); - printf("Calling handler: %p\n", vbr->handler); - (*vbr->handler)(buf); - delete vbr->handler; + printf("Calling handler: %p\n", vbr->handler); + (*vbr->handler)(buf); + delete vbr->handler; - received++; - } + received++; + } if (received == 0) - { - //printf("service_RX() error processing requests\n"); - } + { + //printf("service_RX() error processing requests\n"); + } req.enable_interrupts(); } diff --git a/src/virtio/console.cpp b/src/virtio/console.cpp index 480ec1bf54..1d73459d21 100644 --- a/src/virtio/console.cpp +++ b/src/virtio/console.cpp @@ -26,58 +26,58 @@ extern "C" #define FEAT(x) (1 << x) VirtioCon::VirtioCon(hw::PCI_Device& d) - : Virtio(d), - rx(queue_size(0), 0, iobase()), - tx(queue_size(1), 1, iobase()), - ctl_rx(queue_size(2), 2, iobase()), - ctl_tx(queue_size(3), 3, iobase()) +: Virtio(d), + rx(queue_size(0), 0, iobase()), + tx(queue_size(1), 1, iobase()), + ctl_rx(queue_size(2), 2, iobase()), + ctl_tx(queue_size(3), 3, iobase()) { INFO("VirtioCon", "Driver initializing"); uint32_t needed_features = - FEAT(VIRTIO_CONSOLE_F_MULTIPORT); + FEAT(VIRTIO_CONSOLE_F_MULTIPORT); negotiate_features(needed_features); CHECK(features() & FEAT(VIRTIO_CONSOLE_F_SIZE), - "Valid console dimensions"); + "Valid console dimensions"); CHECK(features() & FEAT(VIRTIO_CONSOLE_F_MULTIPORT), - "Multiple ports support"); + "Multiple ports support"); CHECK(features() & FEAT(VIRTIO_CONSOLE_F_EMERG_WRITE), - "Emergency write support"); + "Emergency write support"); CHECK ((features() & needed_features) == needed_features, - "Negotiated needed features"); + "Negotiated needed features"); // Step 1 - Initialize queues auto success = assign_queue(0, (uint32_t) rx.queue_desc()); CHECK(success, "Receive queue assigned (0x%x) to device", - (uint32_t) rx.queue_desc()); + (uint32_t) rx.queue_desc()); success = assign_queue(1, (uint32_t) tx.queue_desc()); CHECK(success, "Transmit queue assigned (0x%x) to device", - (uint32_t) tx.queue_desc()); + (uint32_t) tx.queue_desc()); success = assign_queue(2, (uint32_t) ctl_rx.queue_desc()); CHECK(success, "Control rx queue assigned (0x%x) to device", - (uint32_t) ctl_rx.queue_desc()); + (uint32_t) ctl_rx.queue_desc()); success = assign_queue(3, (uint32_t) ctl_tx.queue_desc()); CHECK(success, "Control tx queue assigned (0x%x) to device", - (uint32_t) ctl_tx.queue_desc()); + (uint32_t) ctl_tx.queue_desc()); /* - success = assign_queue(4, (uint32_t) rx1.queue_desc()); - CHECK(success, "rx1 queue assigned (0x%x) to device", + success = assign_queue(4, (uint32_t) rx1.queue_desc()); + CHECK(success, "rx1 queue assigned (0x%x) to device", (uint32_t) rx1.queue_desc()); - success = assign_queue(5, (uint32_t) tx1.queue_desc()); - CHECK(success, "tx1 queue assigned (0x%x) to device", + success = assign_queue(5, (uint32_t) tx1.queue_desc()); + CHECK(success, "tx1 queue assigned (0x%x) to device", (uint32_t) tx1.queue_desc()); */ // Step 3 - Fill receive queue with buffers INFO("VirtioCon", "Queue size rx: %d tx: %d\n", - rx.size(), tx.size()); + rx.size(), tx.size()); // Get device configuration get_config(); @@ -93,7 +93,7 @@ VirtioCon::VirtioCon(hw::PCI_Device& d) // Done INFO("VirtioCon", "Console with size (%u, %u), %u ports", - config.cols, config.rows, config.max_nr_ports); + config.cols, config.rows, config.max_nr_ports); rx.kick(); } @@ -113,20 +113,20 @@ void VirtioCon::irq_handler() // Step 2. A) - one of the queues have changed if (isr & 1) - { - // This now means service RX & TX interchangeably - service_RX(); - } + { + // This now means service RX & TX interchangeably + service_RX(); + } // Step 2. B) if (isr & 2) - { - debug("\t Configuration change:\n"); + { + debug("\t Configuration change:\n"); - //debug("\t Old status: 0x%x\n", config.status); - get_config(); - //debug("\t New status: 0x%x \n", config.status); - } + //debug("\t Old status: 0x%x\n", config.status); + get_config(); + //debug("\t New status: 0x%x \n", config.status); + } IRQ_manager::eoi(irq()); } @@ -135,32 +135,32 @@ void VirtioCon::service_RX() rx.disable_interrupts(); while (rx.new_incoming()) - { - uint32_t len = 0; - char* condata = (char*) rx.dequeue(&len); + { + uint32_t len = 0; + char* condata = (char*) rx.dequeue(&len); - uint32_t dontcare; - rx.dequeue(&dontcare); + uint32_t dontcare; + rx.dequeue(&dontcare); - if (condata) - { - //printf("service_RX() received %u bytes from virtio console\n", len); - //printf("Data: %s\n", condata); - //vbr->handler(0, vbr->sector); - } - else - { - // acknowledgement - //printf("No data, just len = %d\n", len); + if (condata) + { + //printf("service_RX() received %u bytes from virtio console\n", len); + //printf("Data: %s\n", condata); + //vbr->handler(0, vbr->sector); + } + else + { + // acknowledgement + //printf("No data, just len = %d\n", len); + } } - } rx.enable_interrupts(); } void VirtioCon::write ( - const void* data, - size_t len) + const void* data, + size_t len) { char* heapdata = new char[len]; memcpy(heapdata, data, len); diff --git a/src/virtio/virtio.cpp b/src/virtio/virtio.cpp index 50cbe5c438..db78c0e026 100644 --- a/src/virtio/virtio.cpp +++ b/src/virtio/virtio.cpp @@ -85,9 +85,9 @@ Virtio::Virtio(hw::PCI_Device& dev) // 3. Set DRIVER status bit hw::outp(_iobase + VIRTIO_PCI_STATUS, - hw::inp(_iobase + VIRTIO_PCI_STATUS) | - VIRTIO_CONFIG_S_ACKNOWLEDGE | - VIRTIO_CONFIG_S_DRIVER); + hw::inp(_iobase + VIRTIO_PCI_STATUS) | + VIRTIO_CONFIG_S_ACKNOWLEDGE | + VIRTIO_CONFIG_S_DRIVER); // THE REMAINING STEPS MUST BE DONE IN A SUBCLASS @@ -119,8 +119,8 @@ Virtio::Virtio(hw::PCI_Device& dev) // uint32_t queue_size = hw::inpd(_iobase + 0x0C); /* printf(queue_size > 0 and queue_size != PCI_WTF ? - "\t [x] Queue Size : 0x%lx \n" : - "\t [ ] No qeuue Size? : 0x%lx \n" ,queue_size); */ + "\t [x] Queue Size : 0x%lx \n" : + "\t [ ] No qeuue Size? : 0x%lx \n" ,queue_size); */ } @@ -200,13 +200,13 @@ void Virtio::enable_irq_handler(){ } /** void Virtio::enable_irq_handler(IRQ_manager::irq_delegate d){ - //_irq=0; //Works only if IRQ2INTR(_irq), since 0 overlaps an exception. - //IRQ_manager::set_handler(IRQ2INTR(_irq), irq_virtio_entry); + //_irq=0; //Works only if IRQ2INTR(_irq), since 0 overlaps an exception. + //IRQ_manager::set_handler(IRQ2INTR(_irq), irq_virtio_entry); - IRQ_manager::subscribe(_irq,d); + IRQ_manager::subscribe(_irq,d); - IRQ_manager::enable_irq(_irq); - }*/ + IRQ_manager::enable_irq(_irq); + }*/ diff --git a/src/virtio/virtionet.cpp b/src/virtio/virtionet.cpp index c21b35decf..d957d94a62 100644 --- a/src/virtio/virtionet.cpp +++ b/src/virtio/virtionet.cpp @@ -300,9 +300,9 @@ void VirtioNet::service_queues(){ void VirtioNet::add_to_tx_buffer(net::Packet_ptr pckt){ if (transmit_queue_) - transmit_queue_->chain(pckt); - else - transmit_queue_ = pckt; + transmit_queue_->chain(pckt); + else + transmit_queue_ = pckt; #ifdef DEBUG size_t chain_length = 1; diff --git a/test/IDE/service.cpp b/test/IDE/service.cpp index e607b2acb8..8d184015d5 100644 --- a/test/IDE/service.cpp +++ b/test/IDE/service.cpp @@ -36,12 +36,12 @@ void Service::start() printf("MAGIC sig: 0x%x\n\n", mbr->magic); ide.read(0, 3, [] (hw::IDE::buffer_t data) { - static int i = 0; - uint8_t* buf = (uint8_t*)data.get(); - printf("Async read, Block %d:\n", i); - for (int i = 0; i < 512; i++) - printf("%x ", buf[i]); - printf("\n"); - i++; - }); + static int i = 0; + uint8_t* buf = (uint8_t*)data.get(); + printf("Async read, Block %d:\n", i); + for (int i = 0; i < 512; i++) + printf("%x ", buf[i]); + printf("\n"); + i++; + }); } diff --git a/test/IRQ_PIC/service.cpp b/test/IRQ_PIC/service.cpp index 47740ca8b8..a0b33a05b2 100644 --- a/test/IRQ_PIC/service.cpp +++ b/test/IRQ_PIC/service.cpp @@ -35,7 +35,7 @@ std::unique_ptr > inet; We're going to use the network- and keyboard interrupts for now, using UDP to trigger the NIC irq. - **/ +**/ void Service::start() { @@ -111,10 +111,10 @@ void Service::start() /** - A custom IRQ-handler for the serial port - It doesn't send eoi, but it should work anyway - since we're using auto-EOI-mode for IRQ < 8 (master) - */ + A custom IRQ-handler for the serial port + It doesn't send eoi, but it should work anyway + since we're using auto-EOI-mode for IRQ < 8 (master) + */ IRQ_manager::subscribe(4, [](){ uint16_t serial_port1 = 0x3F8; //IRQ_manager::eoi(4); @@ -127,11 +127,11 @@ void Service::start() /* - IRQ_manager::subscribe(11,[](){ - // Calling eoi here will turn the IRQ line on and loop forever. - IRQ_manager::eoi(11); - INFO("IRQ","Network IRQ\n"); - });*/ + IRQ_manager::subscribe(11,[](){ + // Calling eoi here will turn the IRQ line on and loop forever. + IRQ_manager::eoi(11); + INFO("IRQ","Network IRQ\n"); + });*/ // Enabling a timer causes freeze in debug mode, for some reason diff --git a/test/STL/service.cpp b/test/STL/service.cpp index b64d21b0cd..d08d5b3c3f 100644 --- a/test/STL/service.cpp +++ b/test/STL/service.cpp @@ -19,7 +19,7 @@ A very superficial test to verify that basic STL is working This is useful when we mess with / replace STL implementations - **/ +**/ #include @@ -41,60 +41,60 @@ int clock_gettime(clockid_t clk_id, struct timespec *tp){ using namespace std; const lest::test specification[] = -{ { - SCENARIO( "vectors can be sized and resized" "[vector]" ) { - - GIVEN( "A vector with some items" ) { - std::vector v( 5 ); - - EXPECT( v.size() == 5u ); - EXPECT( v.capacity() >= 5u ); - - WHEN( "the size is increased" ) { - v.resize( 10 ); - - THEN( "the size and capacity change" ) { - EXPECT( v.size() == 10u); - EXPECT( v.capacity() >= 10u ); - } - } - WHEN( "the size is reduced" ) { - v.resize( 0 ); - - THEN( "the size changes but not capacity" ) { - EXPECT( v.size() == 0u ); - EXPECT( v.capacity() >= 5u ); - } - } - WHEN( "more capacity is reserved" ) { - v.reserve( 10 ); - - THEN( "the capacity changes but not the size" ) { - EXPECT( v.size() == 5u ); - EXPECT( v.capacity() >= 10u ); - } - WHEN( "less capacity is reserved again" ) { - v.reserve( 7 ); - - THEN( "capacity remains unchanged" ) { - EXPECT( v.capacity() >= 10u ); - } - } - } - WHEN( "less capacity is reserved" ) { - v.reserve( 0 ); - - THEN( "neither size nor capacity are changed" ) { - EXPECT( v.size() == 5u ); - EXPECT( v.capacity() >= 5u ); - } - } + SCENARIO( "vectors can be sized and resized" "[vector]" ) + { + + GIVEN( "A vector with some items" ) { + std::vector v( 5 ); + + EXPECT( v.size() == 5u ); + EXPECT( v.capacity() >= 5u ); + + WHEN( "the size is increased" ) { + v.resize( 10 ); + + THEN( "the size and capacity change" ) { + EXPECT( v.size() == 10u); + EXPECT( v.capacity() >= 10u ); + } + } + WHEN( "the size is reduced" ) { + v.resize( 0 ); + + THEN( "the size changes but not capacity" ) { + EXPECT( v.size() == 0u ); + EXPECT( v.capacity() >= 5u ); + } + } + WHEN( "more capacity is reserved" ) { + v.reserve( 10 ); + + THEN( "the capacity changes but not the size" ) { + EXPECT( v.size() == 5u ); + EXPECT( v.capacity() >= 10u ); + } + WHEN( "less capacity is reserved again" ) { + v.reserve( 7 ); + + THEN( "capacity remains unchanged" ) { + EXPECT( v.capacity() >= 10u ); + } + } + } + WHEN( "less capacity is reserved" ) { + v.reserve( 0 ); + + THEN( "neither size nor capacity are changed" ) { + EXPECT( v.size() == 5u ); + EXPECT( v.capacity() >= 5u ); + } + } + } } } - } -}; + }; #define MYINFO(X,...) INFO("Test STL",X,##__VA_ARGS__) diff --git a/test/bufstore/service.cpp b/test/bufstore/service.cpp index 272875e72f..2643e76d7a 100644 --- a/test/bufstore/service.cpp +++ b/test/bufstore/service.cpp @@ -64,7 +64,7 @@ void Service::start() // Reinitialize the first packet packet = std::make_shared(bufstore_.get_offset_buffer(), - bufstore_.offset_bufsize(), 1500, release); + bufstore_.offset_bufsize(), 1500, release); CHECKSERT(bufstore_.buffers_available() == bufcount_ - 1, "Bufcount is now %i", bufcount_ -1); @@ -84,8 +84,8 @@ void Service::start() while(tail && i < bufcount_ - 1 ) { tail = tail->detach_tail(); CHECKSERT(bufstore_.buffers_available() == i, - "Bufcount is now %i == %i", i, - bufstore_.buffers_available()); + "Bufcount is now %i == %i", i, + bufstore_.buffers_available()); i++; } diff --git a/test/fat/fat16.cpp b/test/fat/fat16.cpp index a912a85432..cd5b386a04 100644 --- a/test/fat/fat16.cpp +++ b/test/fat/fat16.cpp @@ -37,48 +37,48 @@ void Service::start() // auto-mount filesystem disk->mount( - [disk] (fs::error_t err) - { - CHECK(!err, "Filesystem auto-mounted"); - assert(!err); + [disk] (fs::error_t err) + { + CHECK(!err, "Filesystem auto-mounted"); + assert(!err); - auto& fs = disk->fs(); - printf("\t\t%s filesystem\n", fs.name().c_str()); + auto& fs = disk->fs(); + printf("\t\t%s filesystem\n", fs.name().c_str()); - auto vec = fs::new_shared_vector(); - err = fs.ls("/", vec); - CHECK(!err, "List root directory"); - assert(!err); + auto vec = fs::new_shared_vector(); + err = fs.ls("/", vec); + CHECK(!err, "List root directory"); + assert(!err); - CHECK(vec->size() == 1, "Exactly one ent in root dir"); - assert(vec->size() == 1); + CHECK(vec->size() == 1, "Exactly one ent in root dir"); + assert(vec->size() == 1); - auto& e = vec->at(0); - CHECK(e.is_file(), "Ent is a file"); - CHECK(e.name() == "banana.txt", "Ent is 'banana.txt'"); + auto& e = vec->at(0); + CHECK(e.is_file(), "Ent is a file"); + CHECK(e.name() == "banana.txt", "Ent is 'banana.txt'"); - }); + }); // re-mount on VBR1 disk->mount(disk->VBR1, - [disk] (fs::error_t err) - { - CHECK(!err, "Filesystem mounted on VBR1"); - assert(!err); + [disk] (fs::error_t err) + { + CHECK(!err, "Filesystem mounted on VBR1"); + assert(!err); - // verify that we can read file - auto& fs = disk->fs(); - auto ent = fs.stat("/banana.txt"); - CHECK(ent.is_valid(), "Stat file in root dir"); - CHECK(ent.is_file(), "Entity is file"); - CHECK(!ent.is_dir(), "Entity is not directory"); - CHECK(ent.name() == "banana.txt", "Name is 'banana.txt'"); + // verify that we can read file + auto& fs = disk->fs(); + auto ent = fs.stat("/banana.txt"); + CHECK(ent.is_valid(), "Stat file in root dir"); + CHECK(ent.is_file(), "Entity is file"); + CHECK(!ent.is_dir(), "Entity is not directory"); + CHECK(ent.name() == "banana.txt", "Name is 'banana.txt'"); - // try reading banana-file - auto buf = fs.read(ent, 0, ent.size); - std::string banana((char*) buf.buffer.get(), buf.len); + // try reading banana-file + auto buf = fs.read(ent, 0, ent.size); + std::string banana((char*) buf.buffer.get(), buf.len); - std::string internal_banana = - R"( ____ ___ + std::string internal_banana = + R"( ____ ___ | _ \ ___ _ _.' _ `. _ | [_) )' _ `._ _ ___ ! \ | | (_) | _ |:;.| _ <| (_) | \ | |' _ `| \| | _ | .:;| @@ -87,11 +87,11 @@ void Service::start() !::, `-!_| | | |\ | | | | | \ !_!.' ':;! !::; ":;:!.!.\_!_!_!.!-'-':;:'' '''! ';:' `::;::;' '' ., . - `: .,. `' .::... . .::;::;' - `..:;::;:.. ::;::;:;:;, :;::;' + `: .,. `' .::... . .::;::;' + `..:;::;:.. ::;::;:;:;, :;::;' "-:;::;:;: ':;::;:'' ;.-' ""`---...________...---'"" -)"; + )"; printf("%s\n", internal_banana.c_str()); CHECK(banana == internal_banana, "Correct banana #1"); diff --git a/test/fat/fat32.cpp b/test/fat/fat32.cpp index 972652e3bf..bceb0eac6a 100644 --- a/test/fat/fat32.cpp +++ b/test/fat/fat32.cpp @@ -24,7 +24,7 @@ std::shared_ptr disk; std::string internal_banana = - R"( ____ ___ + R"( ____ ___ | _ \ ___ _ _.' _ `. _ | [_) )' _ `._ _ ___ ! \ | | (_) | _ |:;.| _ <| (_) | \ | |' _ `| \| | _ | .:;| @@ -33,11 +33,11 @@ std::string internal_banana = !::, `-!_| | | |\ | | | | | \ !_!.' ':;! !::; ":;:!.!.\_!_!_!.!-'-':;:'' '''! ';:' `::;::;' '' ., . - `: .,. `' .::... . .::;::;' - `..:;::;:.. ::;::;:;:;, :;::;' + `: .,. `' .::... . .::;::;' + `..:;::;:.. ::;::;:;:;, :;::;' "-:;::;:;: ':;::;:'' ;.-' ""`---...________...---'"" -)"; + )"; void Service::start() { diff --git a/test/memdisk/bigdisk.cpp b/test/memdisk/bigdisk.cpp index d04b021d5e..3d76c9f528 100644 --- a/test/memdisk/bigdisk.cpp +++ b/test/memdisk/bigdisk.cpp @@ -38,9 +38,9 @@ void Service::start() // verify nothing bad happened CHECK(!!(buf), "Buffer for sector 0 is valid"); if (!buf) - { - panic("Failed to read sector 0 on memdisk device\n"); - } + { + panic("Failed to read sector 0 on memdisk device\n"); + } // verify MBR has signature const uint8_t* mbr = buf.get(); assert(mbr[0x1FE] == 0x55); diff --git a/test/memdisk/twosector.cpp b/test/memdisk/twosector.cpp index a0e3357bb4..1c2694f9c2 100644 --- a/test/memdisk/twosector.cpp +++ b/test/memdisk/twosector.cpp @@ -38,9 +38,9 @@ void Service::start() // verify nothing bad happened CHECK(!!(buf), "Buffer for sector 0 is valid"); if (!buf) - { - panic("Failed to read sector 0 on memdisk device\n"); - } + { + panic("Failed to read sector 0 on memdisk device\n"); + } // convert to text std::string text((const char*) buf.get(), disk->dev().block_size()); // verify that the sector contents matches the test string @@ -53,7 +53,7 @@ void Service::start() // verify that reading outside of disk returns a 0x0 pointer buf = disk->dev().read_sync(disk->dev().size()); CHECK(!buf, "Buffer outside of disk range (sector=%llu) is 0x0", - disk->dev().size()); + disk->dev().size()); assert(!buf); INFO("MemDisk", "SUCCESS"); diff --git a/test/tcp/service.cpp b/test/tcp/service.cpp index 4ac4564be8..d15d78232c 100644 --- a/test/tcp/service.cpp +++ b/test/tcp/service.cpp @@ -29,23 +29,23 @@ std::unique_ptr> inet; std::shared_ptr client; /* - TEST VARIABLES + TEST VARIABLES */ TCP::Port - TEST1{8081}, TEST2{8082}, TEST3{8083}, TEST4{8084}, TEST5{8085}; +TEST1{8081}, TEST2{8082}, TEST3{8083}, TEST4{8084}, TEST5{8085}; using HostAddress = std::pair; HostAddress - TEST_ADDR_TIME{"india.colorado.edu", 13}; +TEST_ADDR_TIME{"india.colorado.edu", 13}; std::string - small, big, huge; +small, big, huge; int - S{150}, B{1500}, H{15000}; +S{150}, B{1500}, H{15000}; std::string - TEST_STR {"1337"}; +TEST_STR {"1337"}; size_t bufstore_capacity{0}; @@ -54,83 +54,83 @@ size_t bufstore_capacity{0}; milliseconds MSL_TEST = 5s; /* - TEST: Release of resources/clean up. + TEST: Release of resources/clean up. */ void FINISH_TEST() { - INFO("TEST", "Started 3 x MSL timeout."); - hw::PIT::instance().onTimeout(3 * MSL_TEST, [] { - INFO("TEST", "Verify release of resources"); - CHECK(inet->tcp().activeConnections() == 0, "tcp.activeConnections() == 0"); - CHECK(inet->available_capacity() == bufstore_capacity, - "inet.available_capacity() == bufstore_capacity"); - printf("# TEST DONE #\n"); - }); + INFO("TEST", "Started 3 x MSL timeout."); + hw::PIT::instance().onTimeout(3 * MSL_TEST, [] { + INFO("TEST", "Verify release of resources"); + CHECK(inet->tcp().activeConnections() == 0, "tcp.activeConnections() == 0"); + CHECK(inet->available_capacity() == bufstore_capacity, + "inet.available_capacity() == bufstore_capacity"); + printf("# TEST DONE #\n"); + }); } /* - TEST: Outgoing Internet Connection + TEST: Outgoing Internet Connection */ void OUTGOING_TEST_INTERNET(const HostAddress& address) { - auto port = address.second; - INFO("TEST", "Outgoing Internet Connection (%s:%u)", address.first.c_str(), address.second); - inet->resolve(address.first, [port](auto&, auto&, auto ip_address) { - CHECK(ip_address != 0, "Resolved host"); + auto port = address.second; + INFO("TEST", "Outgoing Internet Connection (%s:%u)", address.first.c_str(), address.second); + inet->resolve(address.first, [port](auto&, auto&, auto ip_address) { + CHECK(ip_address != 0, "Resolved host"); - if(ip_address != 0) { - inet->tcp().connect(ip_address, port) - ->onConnect([](Connection_ptr) { - CHECK(true, "Connected"); - }) - .onReceive([](Connection_ptr conn, bool) { - CHECK(true, "Received data: %s", conn->read().c_str()); - }) - .onError([](Connection_ptr, TCP::TCPException err) { - CHECK(false, "Error occured: %s", err.what()); - }); - } - }); + if(ip_address != 0) { + inet->tcp().connect(ip_address, port) + ->onConnect([](Connection_ptr) { + CHECK(true, "Connected"); + }) + .onReceive([](Connection_ptr conn, bool) { + CHECK(true, "Received data: %s", conn->read().c_str()); + }) + .onError([](Connection_ptr, TCP::TCPException err) { + CHECK(false, "Error occured: %s", err.what()); + }); + } + }); } /* - TEST: Outgoing Connection to Host + TEST: Outgoing Connection to Host */ void OUTGOING_TEST(TCP::Socket outgoing) { - INFO("TEST", "Outgoing Connection (%s)", outgoing.to_string().c_str()); - inet->tcp().connect(outgoing) - ->onConnect([](Connection_ptr conn) { - conn->write(small); - }) - .onReceive([](Connection_ptr conn, bool) { - CHECK(conn->read() == small, "conn->read() == small"); - }) - .onDisconnect([](Connection_ptr, TCP::Connection::Disconnect) { - CHECK(true, "Connection closed by server"); + INFO("TEST", "Outgoing Connection (%s)", outgoing.to_string().c_str()); + inet->tcp().connect(outgoing) + ->onConnect([](Connection_ptr conn) { + conn->write(small); + }) + .onReceive([](Connection_ptr conn, bool) { + CHECK(conn->read() == small, "conn->read() == small"); + }) + .onDisconnect([](Connection_ptr, TCP::Connection::Disconnect) { + CHECK(true, "Connection closed by server"); - OUTGOING_TEST_INTERNET(TEST_ADDR_TIME); - }); + OUTGOING_TEST_INTERNET(TEST_ADDR_TIME); + }); } // Used to send big data struct Buffer { - size_t written, read; - char* data; - const size_t size; + size_t written, read; + char* data; + const size_t size; - Buffer(size_t length) : - written(0), read(0), data(new char[length]), size(length) {} + Buffer(size_t length) : + written(0), read(0), data(new char[length]), size(length) {} - ~Buffer() { delete[] data; } + ~Buffer() { delete[] data; } - std::string str() { return {data, size};} + std::string str() { return {data, size};} }; void Service::start() { - for(int i = 0; i < S; i++) small += TEST_STR; - for(int i = 0; i < B; i++) big += TEST_STR; - for(int i = 0; i < H; i++) huge += TEST_STR; + for(int i = 0; i < S; i++) small += TEST_STR; + for(int i = 0; i < B; i++) big += TEST_STR; + for(int i = 0; i < H; i++) huge += TEST_STR; - hw::Nic& eth0 = hw::Dev::eth<0,VirtioNet>(); + hw::Nic& eth0 = hw::Dev::eth<0,VirtioNet>(); inet = std::make_unique>(eth0); inet->network_config( {{ 10,0,0,42 }}, // IP @@ -138,113 +138,113 @@ void Service::start() {{ 10,0,0,1 }}, // Gateway {{ 8,8,8,8 }} ); // DNS - bufstore_capacity = inet->available_capacity(); - auto& tcp = inet->tcp(); - // this is default - tcp.set_buffer_limit(10); - // reduce test duration - tcp.set_MSL(MSL_TEST); + bufstore_capacity = inet->available_capacity(); + auto& tcp = inet->tcp(); + // this is default + tcp.set_buffer_limit(10); + // reduce test duration + tcp.set_MSL(MSL_TEST); - /* - TEST: Send and receive small string. - */ - INFO("TEST", "Listeners and connections allocation."); - - /* - TEST: Nothing should be allocated. - */ - CHECK(tcp.openPorts() == 0, "tcp.openPorts() == 0"); - CHECK(tcp.activeConnections() == 0, "tcp.activeConnections() == 0"); + /* + TEST: Send and receive small string. + */ + INFO("TEST", "Listeners and connections allocation."); + + /* + TEST: Nothing should be allocated. + */ + CHECK(tcp.openPorts() == 0, "tcp.openPorts() == 0"); + CHECK(tcp.activeConnections() == 0, "tcp.activeConnections() == 0"); - tcp.bind(TEST1).onConnect([](Connection_ptr conn) { - INFO("TEST", "SMALL string (%u)", small.size()); - conn->onReceive([](Connection_ptr conn, bool) { - CHECK(conn->read() == small, "conn.read() == small"); - conn->close(); - }); - conn->write(small); + tcp.bind(TEST1).onConnect([](Connection_ptr conn) { + INFO("TEST", "SMALL string (%u)", small.size()); + conn->onReceive([](Connection_ptr conn, bool) { + CHECK(conn->read() == small, "conn.read() == small"); + conn->close(); }); + conn->write(small); + }); - /* - TEST: Server should be bound. - */ - CHECK(tcp.openPorts() == 1, "tcp.openPorts() == 1"); + /* + TEST: Server should be bound. + */ + CHECK(tcp.openPorts() == 1, "tcp.openPorts() == 1"); - /* - TEST: Send and receive big string. - */ - tcp.bind(TEST2).onConnect([](Connection_ptr conn) { - INFO("TEST", "BIG string (%u)", big.size()); - auto response = std::make_shared(); - conn->onReceive([response](Connection_ptr conn, bool) { - *response += conn->read(); - if(response->size() == big.size()) { - bool OK = (*response == big); - CHECK(OK, "conn.read() == big"); - conn->close(); - } - }); - conn->write(big); + /* + TEST: Send and receive big string. + */ + tcp.bind(TEST2).onConnect([](Connection_ptr conn) { + INFO("TEST", "BIG string (%u)", big.size()); + auto response = std::make_shared(); + conn->onReceive([response](Connection_ptr conn, bool) { + *response += conn->read(); + if(response->size() == big.size()) { + bool OK = (*response == big); + CHECK(OK, "conn.read() == big"); + conn->close(); + } }); - - /* - TEST: Send and receive huge string. - */ - tcp.bind(TEST3).onConnect([](Connection_ptr conn) { - INFO("TEST", "HUGE string (%u)", huge.size()); - auto buffer = std::make_shared(huge.size()); - conn->onReceive([buffer](Connection_ptr conn, bool) { - // if not all expected data is read - if(buffer->read < huge.size()) - buffer->read += conn->read(buffer->data+buffer->read, conn->receive_buffer().data_size()); - // if not all expected data is written - if(buffer->written < huge.size()) { - buffer->written += conn->write(huge.data()+buffer->written, huge.size() - buffer->written); - } - // when all expected data is read - if(buffer->read == huge.size()) { - bool OK = (buffer->str() == huge); - CHECK(OK, "conn.read() == huge"); - conn->close(); - } - }); - buffer->written += conn->write(huge.data(), huge.size()); + conn->write(big); + }); + + /* + TEST: Send and receive huge string. + */ + tcp.bind(TEST3).onConnect([](Connection_ptr conn) { + INFO("TEST", "HUGE string (%u)", huge.size()); + auto buffer = std::make_shared(huge.size()); + conn->onReceive([buffer](Connection_ptr conn, bool) { + // if not all expected data is read + if(buffer->read < huge.size()) + buffer->read += conn->read(buffer->data+buffer->read, conn->receive_buffer().data_size()); + // if not all expected data is written + if(buffer->written < huge.size()) { + buffer->written += conn->write(huge.data()+buffer->written, huge.size() - buffer->written); + } + // when all expected data is read + if(buffer->read == huge.size()) { + bool OK = (buffer->str() == huge); + CHECK(OK, "conn.read() == huge"); + conn->close(); + } }); - - /* - TEST: More servers should be bound. - */ - CHECK(tcp.openPorts() == 3, "tcp.openPorts() == 3"); - - /* - TEST: Connection (Status etc.) and Active Close - */ - tcp.bind(TEST4).onConnect([](Connection_ptr conn) { - INFO("TEST","Connection"); - // There should be at least one connection. - CHECK(inet->tcp().activeConnections() > 0, "tcp.activeConnections() > 0"); - // Test if connected. - CHECK(conn->is_connected(), "conn.is_connected()"); - // Test if writable. - CHECK(conn->is_writable(), "conn.is_writable()"); - // Test if state is ESTABLISHED. - CHECK(conn->is_state({"ESTABLISHED"}), "conn.is_state(ESTABLISHED)"); - - INFO("TEST", "Active close"); - // Test for active close. - conn->close(); - CHECK(!conn->is_writable(), "!conn->is_writable()"); - CHECK(conn->is_state({"FIN-WAIT-1"}), "conn.is_state(FIN-WAIT-1)"); - }) - .onDisconnect([](Connection_ptr conn, TCP::Connection::Disconnect) { - CHECK(conn->is_state({"FIN-WAIT-2"}), "conn.is_state(FIN-WAIT-2)"); - hw::PIT::instance().onTimeout(1s,[conn]{ - CHECK(conn->is_state({"TIME-WAIT"}), "conn.is_state(TIME-WAIT)"); + buffer->written += conn->write(huge.data(), huge.size()); + }); + + /* + TEST: More servers should be bound. + */ + CHECK(tcp.openPorts() == 3, "tcp.openPorts() == 3"); + + /* + TEST: Connection (Status etc.) and Active Close + */ + tcp.bind(TEST4).onConnect([](Connection_ptr conn) { + INFO("TEST","Connection"); + // There should be at least one connection. + CHECK(inet->tcp().activeConnections() > 0, "tcp.activeConnections() > 0"); + // Test if connected. + CHECK(conn->is_connected(), "conn.is_connected()"); + // Test if writable. + CHECK(conn->is_writable(), "conn.is_writable()"); + // Test if state is ESTABLISHED. + CHECK(conn->is_state({"ESTABLISHED"}), "conn.is_state(ESTABLISHED)"); + + INFO("TEST", "Active close"); + // Test for active close. + conn->close(); + CHECK(!conn->is_writable(), "!conn->is_writable()"); + CHECK(conn->is_state({"FIN-WAIT-1"}), "conn.is_state(FIN-WAIT-1)"); + }) + .onDisconnect([](Connection_ptr conn, TCP::Connection::Disconnect) { + CHECK(conn->is_state({"FIN-WAIT-2"}), "conn.is_state(FIN-WAIT-2)"); + hw::PIT::instance().onTimeout(1s,[conn]{ + CHECK(conn->is_state({"TIME-WAIT"}), "conn.is_state(TIME-WAIT)"); - OUTGOING_TEST({inet->router(), TEST5}); - }); + OUTGOING_TEST({inet->router(), TEST5}); + }); - hw::PIT::instance().onTimeout(5s, [] { FINISH_TEST(); }); - }); + hw::PIT::instance().onTimeout(5s, [] { FINISH_TEST(); }); + }); } diff --git a/test/term/term.cpp b/test/term/term.cpp index 58fb7db560..88380528db 100644 --- a/test/term/term.cpp +++ b/test/term/term.cpp @@ -33,10 +33,10 @@ void Service::start() hw::Nic& eth0 = hw::Dev::eth<0,VirtioNet>(); inet = std::make_unique >(eth0); inet->network_config( - {{ 10,0,0,42 }}, // IP - {{ 255,255,255,0 }}, // Netmask - {{ 10,0,0,1 }}, // Gateway - {{ 8,8,8,8 }} ); // DNS + {{ 10,0,0,42 }}, // IP + {{ 255,255,255,0 }}, // Netmask + {{ 10,0,0,1 }}, // Gateway + {{ 8,8,8,8 }} ); // DNS INFO("TERM", "Running tests for Terminal"); auto disk = fs::new_shared_memdisk(); @@ -44,24 +44,24 @@ void Service::start() // auto-mount filesystem disk->mount( - [disk] (fs::error_t err) - { - assert(!err); + [disk] (fs::error_t err) + { + assert(!err); - /// terminal /// - #define SERVICE_TELNET 23 - auto& tcp = inet->tcp(); - auto& server = tcp.bind(SERVICE_TELNET); - server.onConnect( - [disk] (auto client) - { - // create terminal with open TCP connection - term = std::make_unique (client); - term->add_disk_commands(disk); - }); + /// terminal /// +#define SERVICE_TELNET 23 + auto& tcp = inet->tcp(); + auto& server = tcp.bind(SERVICE_TELNET); + server.onConnect( + [disk] (auto client) + { + // create terminal with open TCP connection + term = std::make_unique (client); + term->add_disk_commands(disk); + }); - INFO("TERM", "Connect to terminal with $ telnet %s ", - inet->ip_addr().str().c_str()); - /// terminal /// - }); + INFO("TERM", "Connect to terminal with $ telnet %s ", + inet->ip_addr().str().c_str()); + /// terminal /// + }); } diff --git a/test/transmit/service.cpp b/test/transmit/service.cpp index 9992ab4442..66c8dca086 100644 --- a/test/transmit/service.cpp +++ b/test/transmit/service.cpp @@ -48,7 +48,7 @@ void Service::start() auto& sock = inet->udp().bind(port); sock.onRead([&] (UDP::Socket& conn, UDP::addr_t addr, UDP::port_t port, - const char* data, int len) -> int { + const char* data, int len) -> int { string received = std::string(data,len-1); INFO("Test 2","Starting UDP-test (got UDP data from %s: %i: '%s')", addr.str().c_str(), port, received.c_str()); diff --git a/test/vga/vga.cpp b/test/vga/vga.cpp index 5de0de44a7..6e61dffdac 100644 --- a/test/vga/vga.cpp +++ b/test/vga/vga.cpp @@ -67,22 +67,22 @@ void Service::start() auto test1_1 = [] () -> bool - { - if ( c >= '4') { - hw::PIT::instance().onRepeatedTimeout(100ms, [] { - vga.newline(); - iterations++; - if (iterations == 24) - write_goodbye(); + { + if ( c >= '4') { + hw::PIT::instance().onRepeatedTimeout(100ms, [] { + vga.newline(); + iterations++; + if (iterations == 24) + write_goodbye(); - }, + }, - [] { - return iterations < 36; - }); - } - return c < '4'; - }; + [] { + return iterations < 36; + }); + } + return c < '4'; + }; auto test2 = [](){ diff --git a/vmbuild/vmbuild.cpp b/vmbuild/vmbuild.cpp index 564c77549a..9e5fd7cb82 100644 --- a/vmbuild/vmbuild.cpp +++ b/vmbuild/vmbuild.cpp @@ -107,13 +107,13 @@ int main(int argc, char** argv) { // Bochs requires old-school disk specifications. // sectors=cyls*heads*spt (sectors per track) /* - const int spt = 63; - auto disk_tracks = - (img_size_sect % spt) == 0 ? - (img_size_sect / spt) : // Sector count is a multiple of 63 - (img_size_sect / spt) + 1; // There's a remainder, so we add one track + const int spt = 63; + auto disk_tracks = + (img_size_sect % spt) == 0 ? + (img_size_sect / spt) : // Sector count is a multiple of 63 + (img_size_sect / spt) + 1; // There's a remainder, so we add one track - const decltype(img_size_sect) disksize {disk_tracks * spt * SECT_SIZE}; + const decltype(img_size_sect) disksize {disk_tracks * spt * SECT_SIZE}; */ const auto disksize = (img_size_sect + extra_sectors) * SECT_SIZE; @@ -127,9 +127,9 @@ int main(int argc, char** argv) { } cout << "Creating disk of size: " - //<< "Cyls: " << cylinders << "\n" - //<< "Heads: " << heads << "\n" - //<< "Sec/Tr: " << spt << "\n" + //<< "Cyls: " << cylinders << "\n" + //<< "Heads: " << heads << "\n" + //<< "Sec/Tr: " << spt << "\n" << "=> " << (disksize / SECT_SIZE) << " sectors\n" << "=> " << disksize << " bytes\n"; @@ -154,7 +154,7 @@ int main(int argc, char** argv) { cout << "Signature: "; for(int i {0}; i < EI_NIDENT; ++i) { - cout << elf_header->e_ident[i]; + cout << elf_header->e_ident[i]; } cout << "\nType: " << ((elf_header->e_type == ET_EXEC) ? " ELF Executable\n" : "Non-executable\n"); From f277c9bcd17e37a844d59e3c017264014d470ffd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Fri, 1 Apr 2016 11:55:55 +0200 Subject: [PATCH 086/311] tcp: cleaned up read/write + old stuff --- api/net/tcp.hpp | 241 +++++++++++------------------- src/net/tcp_connection.cpp | 77 +++++----- src/net/tcp_connection_states.cpp | 15 +- 3 files changed, 132 insertions(+), 201 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index 137b71a2a8..00973a4bdb 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -465,71 +465,6 @@ class TCP { Option::Kind kind_; }; - /* - Buffer for TCP::Packet_ptr - */ - template> - class PacketBuffer { - public: - - PacketBuffer(typename Buffer::size_type limit) : - buffer_(), data_length_(0), - data_offset_(0), limit_(limit) - { - - } - /* Number of packets */ - inline auto size() const { return buffer_.size(); } - - /* Amount of data */ - inline size_t data_size() const { return data_length_; } - - inline void push(const T& packet) { - buffer_.push(packet); - data_length_ += (size_t)packet->data_length(); - } - - inline bool add(T packet) { - if(full()) return false; - push(packet); - return true; - } - - inline void pop() { - data_length_ -= (size_t)buffer_.front()->data_length(); - buffer_.pop(); - } - - inline const T& front() const { return buffer_.front(); } - - inline const T& back() const { return buffer_.back(); } - - inline bool empty() const { return buffer_.empty(); } - - inline auto limit() const { return limit_; } - - inline bool full() const { return size() >= limit(); } - - inline auto data_offset() const { return data_offset_; } - - inline void set_data_offset(uint32_t offset) { data_offset_ = offset; } - - inline void clear() { - while(!buffer_.empty()) - buffer_.pop(); - data_length_ = {0}; - data_offset_ = {0}; - } - - private: - Buffer buffer_; - size_t data_length_; - uint32_t data_offset_; - typename Buffer::size_type limit_; - - }; // << TCP::PacketBuffer - - /* A connection between two Sockets (local and remote). Receives and handle TCP::Packet. @@ -618,27 +553,28 @@ class TCP { }; // < Connection::WriteBuffer /* - Callback when a receive buffer receives either push or is full - Supplied on asynchronous read + Callback when a receive buffer receives either push or is full + - Supplied on asynchronous read */ - using OnRead = delegate; + using ReadCallback = delegate; struct ReadRequest { ReadBuffer buffer; - OnRead callback; + ReadCallback callback; - ReadRequest(ReadBuffer buf, OnRead cb) : buffer(buf), callback(cb) {} + ReadRequest(ReadBuffer buf, ReadCallback cb) : buffer(buf), callback(cb) {} ReadRequest(size_t n = 0) : buffer(buffer_t(new uint8_t[n], std::default_delete()), n), - callback([](auto, auto&, bool){}) {} + callback([](auto, auto){}) {} }; - //using ReadRequest = std::pair; /* - Callback when a write is done - Supplied on asynchronous write, gives the user a callback when the "write job" is complete. + Callback when a write is sent by the TCP + - Supplied on asynchronous write */ - using OnWritten = delegate; + using WriteCallback = delegate; - using WriteRequest = std::pair; + using WriteRequest = std::pair; /* Connection identifier @@ -658,12 +594,6 @@ class TCP { */ using ConnectCallback = delegate)>; - /* - On receiving data - When there is data to read in the receive buffer. - Either when remote PUSH, or buffer is full. - */ - using ReceiveCallback = delegate, bool)>; - /* On disconnect - When a remote told it wanna close the connection. Connection has received a FIN, currently last thing that will happen before a connection is remoed. @@ -690,10 +620,6 @@ class TCP { */ using PacketDroppedCallback = delegate; - /* - Buffer - */ - using Buffer = PacketBuffer<>; /* Reason for disconnect event. @@ -903,29 +829,67 @@ class TCP { */ inline void set_remote(Socket remote) { remote_ = remote; } + /* - Read content from remote. + Read asynchronous from a remote. + + Create n sized internal read buffer and callback for when data is received. + Callback will be called until overwritten with a new read() or connection closes. + Buffer is cleared for data after every reset. */ - void read(ReadBuffer buffer, OnRead callback); + inline void read(size_t n, ReadCallback callback) { + ReadBuffer buffer = {buffer_t(new uint8_t[n], std::default_delete()), n}; + read(buffer, callback); + } - inline void read(buffer_t buffer, size_t n, OnRead callback) { + /* + Assign the connections receive buffer and callback for when data is received. + Works as read(size_t, ReadCallback); + */ + inline void read(buffer_t buffer, size_t n, ReadCallback callback) { read({buffer, n}, callback); } - inline void read(size_t n, OnRead callback) { - ReadBuffer buffer = {buffer_t(new uint8_t[n], std::default_delete()), n}; - read(buffer, callback); - } + void read(ReadBuffer buffer, ReadCallback callback); + /* - Write content to remote. + Write asynchronous to a remote. + + Copies the data from the buffer into an internal buffer. Callback is called when a a write is either done or aborted. + Immediately tries to write the data to the connection. If not possible, queues the write for processing when possible (FIFO). */ - void write(WriteBuffer request, OnWritten callback); + inline void write(const void* buf, size_t n, WriteCallback callback, bool PUSH = true) { + auto buffer = buffer_t(new uint8_t[n], std::default_delete()); + memcpy(buffer.get(), buf, n); + write(buffer, n, callback, PUSH); + } - inline void write(buffer_t buffer, size_t n, OnWritten callback, bool PUSH = true) { + /* + Works as write(const void*, size_t, WriteCallback, bool), + but with the exception of avoiding copying the data to an internal buffer. + */ + inline void write(buffer_t buffer, size_t n, WriteCallback callback, bool PUSH = true) { write({buffer, n, PUSH}, callback); } + /* + Works the same as it's counterpart, without subscribing to a WriteCallback. + */ + inline void write(const void* buf, size_t n, bool PUSH = true) { + write(buf, n, [](auto){}, PUSH); + } + + /* + Works the same as it's counterpart, without subscribing to a WriteCallback. + */ + inline void write(buffer_t buffer, size_t n, bool PUSH = true) { + write({buffer, n, PUSH}, [](auto){}); + } + + void write(WriteBuffer request, WriteCallback callback); + + /* Open connection. */ @@ -960,14 +924,6 @@ class TCP { return *this; } - /* - Set callback for ON RECEIVE event. - */ - inline Connection& onReceive(ReceiveCallback callback) { - on_receive_ = callback; - return *this; - } - /* Set callback for DISCONNECT event. */ @@ -1031,6 +987,19 @@ class TCP { return control_block.RCV.NXT - control_block.IRS; } + /* + Bytes queued for transmission. + TODO: Implement when retransmission is up and running. + */ + //inline size_t send_queue_bytes() const {} + + /* + Bytes currently in receive buffer. + */ + inline size_t read_queue_bytes() const { + return read_request.buffer.size(); + } + /* Return the id (TUPLE) of the connection. */ @@ -1107,7 +1076,10 @@ class TCP { */ std::queue write_queue; - + /* + Bytes queued for transmission. + */ + //size_t write_queue_total; /* When time-wait timer was started. @@ -1129,11 +1101,6 @@ class TCP { debug2(" Connected.\n"); }; - /* When data is received */ - ReceiveCallback on_receive_ = [](std::shared_ptr, bool) { - debug2(" Connection received data. \n"); - }; - /* When Connection is CLOSING. */ DisconnectCallback on_disconnect_ = [](std::shared_ptr, Disconnect) { //debug2(" Connection disconnect. Reason: %s \n", msg.c_str()); @@ -1181,14 +1148,14 @@ class TCP { } /* - + Remote is closing, no more data will be received. + Returns receive buffer to user. */ inline void receive_disconnect() { - //assert(read_request); assert(!read_request.buffer.empty()); auto& buf = read_request.buffer; buf.push = true; - read_request.callback(shared_from_this(), buf, true); + read_request.callback(buf.buffer, buf.size()); } @@ -1218,7 +1185,7 @@ class TCP { bool offer(size_t& packets); /* - Try to write (some of) queue when connected. + Try to write (some of) queue on connected. */ void write_queue_on_connect(); @@ -1234,8 +1201,6 @@ class TCP { inline void signal_connect() { on_connect_(shared_from_this()); } - inline void signal_receive(bool PUSH) { on_receive_(shared_from_this(), PUSH); } - inline void signal_disconnect(Disconnect::Reason&& reason) { on_disconnect_(shared_from_this(), Disconnect{reason}); } inline void signal_error(TCPException error) { on_error_(shared_from_this(), error); } @@ -1273,16 +1238,6 @@ class TCP { /// BUFFER HANDLING /// - /* - Read from receive buffer. - */ - size_t read_from_receive_buffer(char* buffer, size_t n); - - /* - Add(queue) a packet to the receive buffer. - */ - bool add_to_receive_buffer(TCP::Packet_ptr packet); - /* Transmit the send buffer. */ @@ -1294,15 +1249,15 @@ class TCP { void transmit(TCP::Packet_ptr); /* - Creates a new outgoing packet and put it in the back of the send buffer. + Creates a new outgoing packet with the current TCB values and options. */ TCP::Packet_ptr create_outgoing_packet(); /* - Returns the packet in the back of the send buffer. - If the send buffer is empty, it creates a new packet and adds it. */ - TCP::Packet_ptr outgoing_packet(); + inline TCP::Packet_ptr outgoing_packet() { + return create_outgoing_packet(); + } /// RETRANSMISSION /// @@ -1324,9 +1279,9 @@ class TCP { //std::chrono::milliseconds RTT() const; std::chrono::milliseconds RTO() const; - /* + /* Start the time wait timeout for 2*MSL - */ + */ void start_time_wait_timeout(); /* @@ -1396,11 +1351,6 @@ class TCP { */ void bottom(net::Packet_ptr); - /* - Write data to a connection. - */ - void write(Connection_ptr, std::shared_ptr, size_t, Connection::OnWritten, bool = true); - /* Delegate output to network layer */ @@ -1437,18 +1387,6 @@ class TCP { MAX_SEG_LIFETIME = msl; } - /* - Maximum Buffer Size - */ - inline auto buffer_limit() const { return MAX_BUFFER_SIZE; } - - /* - Set Buffer limit - */ - inline void set_buffer_limit(size_t buffer_limit) { - MAX_BUFFER_SIZE = buffer_limit; - } - /* Maximum Segment Size [RFC 793] [RFC 879] [RFC 6691] @@ -1488,12 +1426,6 @@ class TCP { std::chrono::milliseconds MAX_SEG_LIFETIME; - /* - Current: limit by packet COUNT. - Connection buffer size in bytes = buffers * BUFFER_LIMIT * MTU. - */ - size_t MAX_BUFFER_SIZE = 10; - /* Transmit packet to network layer (IP). */ @@ -1530,7 +1462,8 @@ class TCP { void process_write_queue(size_t packets); /* - + Ask to send a Connection's WriteBuffer. + If there is no free packets, the job will be queued. */ size_t send(Connection_ptr, Connection::WriteBuffer&); diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index 44380281f7..562a425165 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -57,13 +57,13 @@ Connection::Connection(TCP& host, Port local_port) : } -void Connection::read(ReadBuffer buffer, OnRead callback) { +void Connection::read(ReadBuffer buffer, ReadCallback callback) { try { state_->receive(*this, buffer); read_request.callback = callback; } catch (TCPException err) { - callback(shared_from_this(), buffer, false); + callback(buffer.buffer, buffer.size()); } } @@ -80,7 +80,7 @@ size_t Connection::receive(const uint8_t* data, size_t n, bool PUSH) { // buffer should be full assert(buf.full()); // signal the user - read_request.callback(shared_from_this(), buf, true); + read_request.callback(buf.buffer, buf.size()); // reset the buffer buf.clear(); } @@ -93,7 +93,7 @@ size_t Connection::receive(const uint8_t* data, size_t n, bool PUSH) { // end of data, signal the user if(PUSH) { buf.push = PUSH; - read_request.callback(shared_from_this(), buf, true); + read_request.callback(buf.buffer, buf.size()); // reset the buffer buf.clear(); } @@ -102,32 +102,37 @@ size_t Connection::receive(const uint8_t* data, size_t n, bool PUSH) { } -void Connection::write(WriteBuffer request, OnWritten callback) { +void Connection::write(WriteBuffer buffer, WriteCallback callback) { try { - auto written = state_->send(*this, request); - request.advance(written); + auto written = state_->send(*this, buffer); + buffer.advance(written); - if(!request.remaining) { - callback(shared_from_this(), request, true); + if(!buffer.remaining) { + callback(buffer.offset); } else { - write_queue.emplace(request, callback); + write_queue.emplace(buffer, callback); } } catch(TCPException err) { - callback(shared_from_this(), request, false); + callback(0); } } bool Connection::offer(size_t& packets) { assert(packets); + debug2(" (%s) got offered [%u] packets.\n", tuple().to_string().c_str(), packets); while(!write_queue.empty() and packets) { - auto& req = write_queue.front().first; - auto written = send(req, packets); - req.advance(written); - if(!req.remaining) { - write_queue.front().second(shared_from_this(), req, true); + auto& buf = write_queue.front().first; + // segmentize the buffer into packets + auto written = send(buf, packets); + // advance the buffer + buf.advance(written); + // if finished + if(!buf.remaining) { + // callback and remove object + write_queue.front().second(buf.offset); write_queue.pop(); } } @@ -137,7 +142,9 @@ bool Connection::offer(size_t& packets) { size_t Connection::send(const char* buffer, size_t remaining, size_t& packet_count, bool PUSH) { + assert(packet_count && remaining); size_t bytes_written{0}; + while(remaining and packet_count) { // retreive a new packet auto packet = create_outgoing_packet(); @@ -153,8 +160,8 @@ size_t Connection::send(const char* buffer, size_t remaining, size_t& packet_cou bytes_written += written; remaining -= written; - debug2(" Packet Limit: %u - Written: %u - Remaining: %u\n", - packet_limit, written, remaining); + debug2(" Packet Limit: %u - Written: %u - Remaining: %u - Packet count: %u\n", + packet_limit, written, remaining, packet_count); // If last packet, add PUSH. if(!remaining and PUSH) @@ -162,36 +169,33 @@ size_t Connection::send(const char* buffer, size_t remaining, size_t& packet_cou // Advance outgoing sequence number (SND.NXT) with the length of the data. control_block.SND.NXT += packet->data_length(); + // TODO: Replace with chaining transmit(packet); } return bytes_written; } + void Connection::write_queue_on_connect() { while(!write_queue.empty()) { - auto& req = write_queue.front().first; - auto written = send(req); - req.advance(written); - if(req.remaining) + auto& buf = write_queue.front().first; + auto written = send(buf); + buf.advance(written); + if(buf.remaining) return; - write_queue.front().second(shared_from_this(), req, true); + write_queue.front().second(buf.offset); write_queue.pop(); } } void Connection::write_queue_reset() { while(!write_queue.empty()) { - auto job = write_queue.front(); - job.second(shared_from_this(), job.first, false); + auto& job = write_queue.front(); + job.second(job.first.offset); write_queue.pop(); } } - -/* - If ACTIVE: - Need a remote Socket. -*/ void Connection::open(bool active) { try { debug(" Trying to open Connection...\n"); @@ -215,16 +219,15 @@ void Connection::close() { } } - +/* + Local:Port Remote:Port (STATE) +*/ string Connection::to_string() const { ostringstream os; - os << local().to_string() << "\t" << remote_.to_string() << "\t" << state_->to_string(); + os << local().to_string() << " " << remote_.to_string() << " (" << state_->to_string() << ")"; return os.str(); } -/* - Where the magic happens. -*/ void Connection::segment_arrived(TCP::Packet_ptr incoming) { signal_packet_received(incoming); @@ -297,10 +300,6 @@ void Connection::transmit(TCP::Packet_ptr packet) { // add_retransmission(packet); } -inline TCP::Packet_ptr Connection::outgoing_packet() { - return create_outgoing_packet(); -} - TCP::Seq Connection::generate_iss() { return host_.generate_iss(); } diff --git a/src/net/tcp_connection_states.cpp b/src/net/tcp_connection_states.cpp index 7f2511bff1..bf50259cdb 100644 --- a/src/net/tcp_connection_states.cpp +++ b/src/net/tcp_connection_states.cpp @@ -343,7 +343,8 @@ void Connection::State::process_fin(Connection& tcp, TCP::Packet_ptr in) { packet->set_ack(tcb.RCV.NXT).set_flag(ACK); tcp.transmit(packet); // signal the user - tcp.receive_disconnect(); + if(!tcp.read_request.buffer.empty()) + tcp.receive_disconnect(); } ///////////////////////////////////////////////////////////////////// @@ -606,10 +607,6 @@ void Connection::SynReceived::close(Connection& tcp) { tcp.set_state(Connection::FinWait1::instance()); } -void Connection::SynReceived::abort(Connection& tcp) { - send_reset(tcp); -} - void Connection::Established::close(Connection& tcp) { auto& tcb = tcp.tcb(); auto packet = tcp.outgoing_packet(); @@ -661,6 +658,10 @@ void Connection::State::abort(Connection&) { // Do nothing. } +void Connection::SynReceived::abort(Connection& tcp) { + send_reset(tcp); +} + void Connection::Established::abort(Connection& tcp) { send_reset(tcp); } @@ -858,9 +859,7 @@ State::Result Connection::SynSent::handle(Connection& tcp, TCP::Packet_ptr in) { tcp.transmit(packet); tcp.set_state(Connection::SynReceived::instance()); if(in->has_data()) { - tcp.add_to_receive_buffer(in); - // Advance RCV.NXT ?? - tcb.RCV.NXT += in->data_length(); + process_segment(tcp, in); } return OK; /* From 2ad480aa09b6ad3291abbcd6ae1d5daa8fc8a041 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Fri, 1 Apr 2016 11:56:58 +0200 Subject: [PATCH 087/311] tcp: updated to reflect new read/write --- src/kernel/terminal.cpp | 4 +- test/tcp/service.cpp | 100 ++++++++++++++++++++-------------------- 2 files changed, 53 insertions(+), 51 deletions(-) diff --git a/src/kernel/terminal.cpp b/src/kernel/terminal.cpp index 1e726e90f5..8211006cbe 100644 --- a/src/kernel/terminal.cpp +++ b/src/kernel/terminal.cpp @@ -31,8 +31,8 @@ Terminal::Terminal() Terminal::Terminal(Connection_ptr csock) : Terminal() { - csock->read(1024, [this](auto, auto& buffer, bool){ - this->read((char*)buffer.begin(), buffer.size()); + csock->read(1024, [this](auto buffer, size_t n){ + this->read((char*)buffer.get(), n); }); /*csock->onReceive( [this] (auto conn, bool) diff --git a/test/tcp/service.cpp b/test/tcp/service.cpp index 4ac4564be8..b8018874b7 100644 --- a/test/tcp/service.cpp +++ b/test/tcp/service.cpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -25,29 +25,30 @@ using namespace net; using namespace std::chrono; // For timers and MSL using Connection_ptr = std::shared_ptr; +using buffer_t = TCP::buffer_t; std::unique_ptr> inet; std::shared_ptr client; /* TEST VARIABLES */ -TCP::Port +TCP::Port TEST1{8081}, TEST2{8082}, TEST3{8083}, TEST4{8084}, TEST5{8085}; using HostAddress = std::pair; HostAddress TEST_ADDR_TIME{"india.colorado.edu", 13}; -std::string +std::string small, big, huge; -int +int S{150}, B{1500}, H{15000}; -std::string +std::string TEST_STR {"1337"}; -size_t bufstore_capacity{0}; +size_t buffers_available{0}; // Default MSL is 30s. Timeout 2*MSL. // To reduce test duration, lower MSL to 5s. @@ -61,8 +62,9 @@ void FINISH_TEST() { hw::PIT::instance().onTimeout(3 * MSL_TEST, [] { INFO("TEST", "Verify release of resources"); CHECK(inet->tcp().activeConnections() == 0, "tcp.activeConnections() == 0"); - CHECK(inet->available_capacity() == bufstore_capacity, - "inet.available_capacity() == bufstore_capacity"); + CHECK(inet->buffers_available() == buffers_available, + "inet->buffers_available() == buffers_available"); + INFO("Buffers available", "%u", inet->buffers_available()); printf("# TEST DONE #\n"); }); } @@ -75,14 +77,14 @@ void OUTGOING_TEST_INTERNET(const HostAddress& address) { INFO("TEST", "Outgoing Internet Connection (%s:%u)", address.first.c_str(), address.second); inet->resolve(address.first, [port](auto&, auto&, auto ip_address) { CHECK(ip_address != 0, "Resolved host"); - + if(ip_address != 0) { inet->tcp().connect(ip_address, port) - ->onConnect([](Connection_ptr) { + ->onConnect([](Connection_ptr conn) { CHECK(true, "Connected"); - }) - .onReceive([](Connection_ptr conn, bool) { - CHECK(true, "Received data: %s", conn->read().c_str()); + conn->read(1024, [](buffer_t, size_t n) { + CHECK(n > 0, "Received data"); + }); }) .onError([](Connection_ptr, TCP::TCPException err) { CHECK(false, "Error occured: %s", err.what()); @@ -98,14 +100,14 @@ void OUTGOING_TEST(TCP::Socket outgoing) { INFO("TEST", "Outgoing Connection (%s)", outgoing.to_string().c_str()); inet->tcp().connect(outgoing) ->onConnect([](Connection_ptr conn) { - conn->write(small); - }) - .onReceive([](Connection_ptr conn, bool) { - CHECK(conn->read() == small, "conn->read() == small"); + conn->write(small.data(), small.size()); + conn->read(small.size(), [](buffer_t buffer, size_t n) { + CHECK(std::string((char*)buffer.get(), n) == small, "conn->read() == small"); + }); }) .onDisconnect([](Connection_ptr, TCP::Connection::Disconnect) { CHECK(true, "Connection closed by server"); - + OUTGOING_TEST_INTERNET(TEST_ADDR_TIME); }); } @@ -115,7 +117,7 @@ struct Buffer { size_t written, read; char* data; const size_t size; - + Buffer(size_t length) : written(0), read(0), data(new char[length]), size(length) {} @@ -127,24 +129,23 @@ struct Buffer { void Service::start() { for(int i = 0; i < S; i++) small += TEST_STR; - for(int i = 0; i < B; i++) big += TEST_STR; + for(int i = 0; i < B; i++) big += TEST_STR; for(int i = 0; i < H; i++) huge += TEST_STR; hw::Nic& eth0 = hw::Dev::eth<0,VirtioNet>(); inet = std::make_unique>(eth0); - + inet->network_config( {{ 10,0,0,42 }}, // IP {{ 255,255,255,0 }}, // Netmask {{ 10,0,0,1 }}, // Gateway {{ 8,8,8,8 }} ); // DNS - - bufstore_capacity = inet->available_capacity(); + + buffers_available = inet->buffers_available(); + INFO("Buffers available", "%u", inet->buffers_available()); auto& tcp = inet->tcp(); - // this is default - tcp.set_buffer_limit(10); // reduce test duration tcp.set_MSL(MSL_TEST); - + /* TEST: Send and receive small string. */ @@ -155,36 +156,40 @@ void Service::start() */ CHECK(tcp.openPorts() == 0, "tcp.openPorts() == 0"); CHECK(tcp.activeConnections() == 0, "tcp.activeConnections() == 0"); - + tcp.bind(TEST1).onConnect([](Connection_ptr conn) { INFO("TEST", "SMALL string (%u)", small.size()); - conn->onReceive([](Connection_ptr conn, bool) { - CHECK(conn->read() == small, "conn.read() == small"); + conn->read(small.size(), [conn](buffer_t buffer, size_t n) { + CHECK(inet->buffers_available() < buffers_available, + "inet->buffers_available() < buffers_available"); + CHECK(std::string((char*)buffer.get(), n) == small, "conn.read() == small"); conn->close(); }); - conn->write(small); + conn->write(small.data(), small.size()); + INFO("Buffers available", "%u", inet->buffers_available()); }); /* TEST: Server should be bound. */ CHECK(tcp.openPorts() == 1, "tcp.openPorts() == 1"); - + /* TEST: Send and receive big string. */ tcp.bind(TEST2).onConnect([](Connection_ptr conn) { INFO("TEST", "BIG string (%u)", big.size()); auto response = std::make_shared(); - conn->onReceive([response](Connection_ptr conn, bool) { - *response += conn->read(); + conn->read(big.size(), [response, conn](buffer_t buffer, size_t n) { + *response += std::string((char*)buffer.get(), n); if(response->size() == big.size()) { bool OK = (*response == big); CHECK(OK, "conn.read() == big"); conn->close(); } }); - conn->write(big); + conn->write(big.data(), big.size()); + INFO("Buffers available", "%u", inet->buffers_available()); }); /* @@ -192,23 +197,20 @@ void Service::start() */ tcp.bind(TEST3).onConnect([](Connection_ptr conn) { INFO("TEST", "HUGE string (%u)", huge.size()); - auto buffer = std::make_shared(huge.size()); - conn->onReceive([buffer](Connection_ptr conn, bool) { - // if not all expected data is read - if(buffer->read < huge.size()) - buffer->read += conn->read(buffer->data+buffer->read, conn->receive_buffer().data_size()); - // if not all expected data is written - if(buffer->written < huge.size()) { - buffer->written += conn->write(huge.data()+buffer->written, huge.size() - buffer->written); - } + auto temp = std::make_shared(huge.size()); + conn->read(huge.size(), [temp, conn](buffer_t buffer, size_t n) { + memcpy(temp->data + temp->written, buffer.get(), n); + temp->written += n; + // when all expected data is read - if(buffer->read == huge.size()) { - bool OK = (buffer->str() == huge); + if(temp->written == huge.size()) { + bool OK = (temp->str() == huge); CHECK(OK, "conn.read() == huge"); conn->close(); } }); - buffer->written += conn->write(huge.data(), huge.size()); + conn->write(huge.data(), huge.size()); + INFO("Buffers available", "%u", inet->buffers_available()); }); /* @@ -240,10 +242,10 @@ void Service::start() CHECK(conn->is_state({"FIN-WAIT-2"}), "conn.is_state(FIN-WAIT-2)"); hw::PIT::instance().onTimeout(1s,[conn]{ CHECK(conn->is_state({"TIME-WAIT"}), "conn.is_state(TIME-WAIT)"); - + OUTGOING_TEST({inet->router(), TEST5}); }); - + hw::PIT::instance().onTimeout(5s, [] { FINISH_TEST(); }); }); From fdd5ab163693576a950acb46d8ea888cbaace53b Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Fri, 1 Apr 2016 12:30:26 +0200 Subject: [PATCH 088/311] disk: Update test_disk and memdisk section in makefile --- src/Makefile | 3 ++- src/debug/test_disk.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Makefile b/src/Makefile index 5ba7a5e191..833744f3f1 100644 --- a/src/Makefile +++ b/src/Makefile @@ -83,6 +83,7 @@ CRTN_OBJ = crt/crtn.o ################################################### OS_DEPS = $(OS_OBJECTS:.o=.d) +.PHONY: memdisk all debug stripped clean # Complete OS build ################################################### @@ -203,7 +204,7 @@ bootloader: boot/bootloader.asm boot/disk_read_lba.asm # Disk image as a section ################################################### -memdisk: +memdisk: memdisk.asm @echo "\n>> Assembling memdisk" nasm -f elf -o memdisk.o $< diff --git a/src/debug/test_disk.cpp b/src/debug/test_disk.cpp index 9ef2416bb7..71f0f0630c 100644 --- a/src/debug/test_disk.cpp +++ b/src/debug/test_disk.cpp @@ -79,7 +79,7 @@ void Service::start() if (e.is_file()) { printf("*** Attempting to read: %s\n", e.name().c_str()); - disk->fs().readFile(e, + disk->fs().read(e, 0, e.size, [e] (fs::error_t err, fs::buffer_t buffer, size_t len) { if (err) From b3ee4f5795688acb236d5e6df9710c40feccec30 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sat, 2 Apr 2016 12:20:54 +0200 Subject: [PATCH 089/311] Revert "Editorconfig / indentation Nuke" This reverts commit de3ca91b8df08a74454c7d4c386e5e04f082ddcc. --- api/fs/common.hpp | 10 +- api/fs/disk.hpp | 124 +- api/fs/ext4.hpp | 20 +- api/fs/fat.hpp | 20 +- api/fs/filesystem.hpp | 168 +- api/fs/mbr.hpp | 84 +- api/fs/memdisk.hpp | 42 +- api/fs/path.hpp | 108 +- api/fs/vbr.hpp | 4 +- api/hw/dev.hpp | 94 +- api/hw/disk.hpp | 82 +- api/hw/disk_device.hpp | 52 +- api/hw/ide.hpp | 84 +- api/hw/pci.hpp | 88 +- api/hw/pci_device.hpp | 396 ++--- api/hw/pic.hpp | 22 +- api/hw/pit.hpp | 274 +-- api/kernel/irq_manager.hpp | 20 +- api/kernel/os.hpp | 4 +- api/kernel/service.hpp | 2 +- api/kernel/terminal.hpp | 20 +- api/net/arp.hpp | 210 +-- api/net/buffer_store.hpp | 148 +- api/net/dns/client.hpp | 4 +- api/net/dns/dns.hpp | 42 +- api/net/inet.hpp | 68 +- api/net/inet4.hpp | 2 +- api/net/inet64.hpp | 14 +- api/net/ip4.hpp | 226 +-- api/net/ip4/icmpv4.hpp | 60 +- api/net/ip4/packet_ip4.hpp | 100 +- api/net/ip4/udp.hpp | 108 +- api/net/ip6/icmp6.hpp | 2 +- api/net/ip6/ip6.hpp | 86 +- api/net/ip6/udp6.hpp | 4 +- api/net/tcp.hpp | 2310 +++++++++++++------------- api/net/tcp_connection_states.hpp | 360 ++-- api/net/util.hpp | 48 +- api/utility/async_loop.hpp | 26 +- api/utility/delegate.hpp | 74 +- api/utility/membitmap.hpp | 20 +- api/utility/ringbuffer.hpp | 174 +- api/utility/signal.hpp | 52 +- api/virtio/console.hpp | 4 +- api/virtio/virtio.hpp | 56 +- etc/batch_apply_editorconfig.sh | 9 - examples/demo_service/service.cpp | 80 +- examples/tcp/service.cpp | 90 +- src/crt/cxx_abi.cpp | 2 +- src/crt/mman.cpp | 28 +- src/debug/ircd.cpp | 188 +-- src/debug/ircsplit.hpp | 60 +- src/debug/test_disk.cpp | 200 +-- src/debug/test_ipv6.cpp | 56 +- src/debug/test_service.cpp | 48 +- src/debug/test_tcp.cpp | 20 +- src/fs/disk.cpp | 204 +-- src/fs/ext4.cpp | 22 +- src/fs/fat.cpp | 280 ++-- src/fs/fat_async.cpp | 308 ++-- src/fs/fat_sync.cpp | 158 +- src/fs/mbr.cpp | 136 +- src/fs/memdisk.cpp | 74 +- src/fs/path.cpp | 174 +- src/hw/cpu_freq_sampling.cpp | 108 +- src/hw/ide.cpp | 248 +-- src/hw/nic.cpp | 24 +- src/hw/pci_device.cpp | 264 +-- src/hw/pit.cpp | 344 ++-- src/include/hw/cpu_freq_sampling.hpp | 18 +- src/kernel/cpuid.cpp | 24 +- src/kernel/irq_manager.cpp | 116 +- src/kernel/os.cpp | 16 +- src/kernel/pci_manager.cpp | 10 +- src/kernel/rdrand.cpp | 12 +- src/kernel/syscalls.cpp | 2 +- src/kernel/terminal.cpp | 310 ++-- src/kernel/terminal_disk.cpp | 198 +-- src/kernel/vga.cpp | 4 +- src/net/arp.cpp | 316 ++-- src/net/buffer_store.cpp | 118 +- src/net/dhcp/dh4client.cpp | 148 +- src/net/dns/client.cpp | 16 +- src/net/dns/dns.cpp | 214 +-- src/net/ethernet.cpp | 134 +- src/net/inet.cpp | 8 +- src/net/inet_common.cpp | 34 +- src/net/ip4.cpp | 124 +- src/net/ip4/icmpv4.cpp | 92 +- src/net/ip4/udp.cpp | 102 +- src/net/ip4/udp_socket.cpp | 58 +- src/net/ip6/icmp6.cpp | 242 +-- src/net/ip6/ip6.cpp | 78 +- src/net/ip6/udp6.cpp | 12 +- src/net/tcp.cpp | 306 ++-- src/net/tcp_connection.cpp | 576 +++---- src/net/tcp_connection_states.cpp | 1742 +++++++++---------- src/virtio/block.cpp | 86 +- src/virtio/console.cpp | 96 +- src/virtio/virtio.cpp | 20 +- src/virtio/virtionet.cpp | 6 +- test/IDE/service.cpp | 16 +- test/IRQ_PIC/service.cpp | 20 +- test/STL/service.cpp | 102 +- test/bufstore/service.cpp | 6 +- test/fat/fat16.cpp | 70 +- test/fat/fat32.cpp | 8 +- test/memdisk/bigdisk.cpp | 6 +- test/memdisk/twosector.cpp | 8 +- test/tcp/service.cpp | 312 ++-- test/term/term.cpp | 44 +- test/transmit/service.cpp | 2 +- test/vga/vga.cpp | 28 +- vmbuild/vmbuild.cpp | 20 +- 114 files changed, 7456 insertions(+), 7465 deletions(-) delete mode 100644 etc/batch_apply_editorconfig.sh diff --git a/api/fs/common.hpp b/api/fs/common.hpp index 6ef7dc11c3..c09fb25c96 100644 --- a/api/fs/common.hpp +++ b/api/fs/common.hpp @@ -23,13 +23,13 @@ namespace fs { - typedef std::shared_ptr buffer_t; +typedef std::shared_ptr buffer_t; - // TODO: transform this into a class with a bool operator - using error_t = bool; +// TODO: transform this into a class with a bool operator +using error_t = bool; - /** @var no_error: Always returns boolean false when used in expressions */ - extern error_t no_error; +/** @var no_error: Always returns boolean false when used in expressions */ +extern error_t no_error; } //< namespace fs diff --git a/api/fs/disk.hpp b/api/fs/disk.hpp index 72ad7f7757..d49137cde8 100644 --- a/api/fs/disk.hpp +++ b/api/fs/disk.hpp @@ -29,87 +29,87 @@ namespace fs { - class Disk { - public: - struct Partition; //< Representation of a disk partition +class Disk { +public: + struct Partition; //< Representation of a disk partition - /** Callbacks */ - using on_parts_func = std::function&)>; - using on_mount_func = std::function; + /** Callbacks */ + using on_parts_func = std::function&)>; + using on_mount_func = std::function; - /** Constructor */ - explicit Disk(hw::IDiskDevice&); + /** Constructor */ + explicit Disk(hw::IDiskDevice&); - enum partition_t { - MBR = 0, //< Master Boot Record (0) - /** extended partitions (1-4) */ - VBR1, - VBR2, - VBR3, - VBR4, + enum partition_t { + MBR = 0, //< Master Boot Record (0) + /** extended partitions (1-4) */ + VBR1, + VBR2, + VBR3, + VBR4, - INVALID - }; //< enum partition_t + INVALID + }; //< enum partition_t - struct Partition { - explicit Partition(const uint8_t fl, const uint8_t Id, - const uint32_t LBA, const uint32_t sz) noexcept : - flags {fl}, - id {Id}, - lba_begin {LBA}, - sectors {sz} - {} + struct Partition { + explicit Partition(const uint8_t fl, const uint8_t Id, + const uint32_t LBA, const uint32_t sz) noexcept : + flags {fl}, + id {Id}, + lba_begin {LBA}, + sectors {sz} + {} - uint8_t flags; - uint8_t id; - uint32_t lba_begin; - uint32_t sectors; + uint8_t flags; + uint8_t id; + uint32_t lba_begin; + uint32_t sectors; - // true if the partition has boot code / is bootable - bool is_boot() const noexcept - { return flags & 0x1; } + // true if the partition has boot code / is bootable + bool is_boot() const noexcept + { return flags & 0x1; } - // human-readable name of partition id - std::string name() const; + // human-readable name of partition id + std::string name() const; - // logical block address of beginning of partition - uint32_t lba() const - { return lba_begin; } + // logical block address of beginning of partition + uint32_t lba() const + { return lba_begin; } - }; //< struct Partition + }; //< struct Partition - /** Return a reference to the specified filesystem */ - FileSystem& fs() noexcept - { return *filesys; } + /** Return a reference to the specified filesystem */ + FileSystem& fs() noexcept + { return *filesys; } - //************** disk functions **************// + //************** disk functions **************// - hw::IDiskDevice& dev() noexcept - { return device; } + hw::IDiskDevice& dev() noexcept + { return device; } - // Returns true if the disk has no sectors - bool empty() const noexcept - { return device.size() == 0; } + // Returns true if the disk has no sectors + bool empty() const noexcept + { return device.size() == 0; } - // Mounts the first partition detected (MBR -> VBR1-4 -> ext) - void mount(on_mount_func func); + // Mounts the first partition detected (MBR -> VBR1-4 -> ext) + void mount(on_mount_func func); - // Mount partition @part as the filesystem FS - void mount(partition_t part, on_mount_func func); + // Mount partition @part as the filesystem FS + void mount(partition_t part, on_mount_func func); - /** - * Returns a vector of the partitions on a disk - * - * The disk does not need to be mounted beforehand - */ - void partitions(on_parts_func func); + /** + * Returns a vector of the partitions on a disk + * + * The disk does not need to be mounted beforehand + */ + void partitions(on_parts_func func); - private: - hw::IDiskDevice& device; - std::unique_ptr filesys; - }; //< class Disk +private: + hw::IDiskDevice& device; + std::unique_ptr filesys; +}; //< class Disk - using Disk_ptr = std::shared_ptr; +using Disk_ptr = std::shared_ptr; } //< namespace fs diff --git a/api/fs/ext4.hpp b/api/fs/ext4.hpp index ca289b95d0..d6f73782e5 100644 --- a/api/fs/ext4.hpp +++ b/api/fs/ext4.hpp @@ -32,16 +32,16 @@ namespace fs struct EXT4 : public FileSystem { /** - Blocks 2^32 2^32 2^32 2^32 - Inodes 2^32 2^32 2^32 2^32 - File System Size 4TiB 8TiB 16TiB 256PiB - Blocks Per Block Group 8,192 16,384 32,768 524,288 - Inodes Per Block Group 8,192 16,384 32,768 524,288 - Block Group Size 8MiB 32MiB 128MiB 32GiB - Blocks Per File, Extents 2^32 2^32 2^32 2^32 - Blocks Per File, Block Maps 16,843,020 134,480,396 1,074,791,436 4,398,314,962,956 - File Size, Extents 4TiB 8TiB 16TiB 256TiB - File Size, Block Maps 16GiB 256GiB 4TiB 256PiB + Blocks 2^32 2^32 2^32 2^32 + Inodes 2^32 2^32 2^32 2^32 + File System Size 4TiB 8TiB 16TiB 256PiB + Blocks Per Block Group 8,192 16,384 32,768 524,288 + Inodes Per Block Group 8,192 16,384 32,768 524,288 + Block Group Size 8MiB 32MiB 128MiB 32GiB + Blocks Per File, Extents 2^32 2^32 2^32 2^32 + Blocks Per File, Block Maps 16,843,020 134,480,396 1,074,791,436 4,398,314,962,956 + File Size, Extents 4TiB 8TiB 16TiB 256TiB + File Size, Block Maps 16GiB 256GiB 4TiB 256PiB **/ // 0 = Mount MBR diff --git a/api/fs/fat.hpp b/api/fs/fat.hpp index 18a1e4e0e2..424ce4e19e 100644 --- a/api/fs/fat.hpp +++ b/api/fs/fat.hpp @@ -54,14 +54,14 @@ namespace fs virtual std::string name() const override { switch (this->fat_type) - { - case T_FAT12: + { + case T_FAT12: return "FAT12"; - case T_FAT16: + case T_FAT16: return "FAT16"; - case T_FAT32: + case T_FAT32: return "FAT32"; - } + } return "Invalid fat type"; } /// ----------------------------------------------------- /// @@ -121,7 +121,7 @@ namespace fs uint32_t size() const { - return filesize; + return filesize; } } __attribute__((packed)); @@ -162,16 +162,16 @@ namespace fs uint16_t cl_to_entry_offset(uint32_t cl) { if (fat_type == T_FAT16) - return (cl * 2) % sector_size; + return (cl * 2) % sector_size; else // T_FAT32 - return (cl * 4) % sector_size; + return (cl * 4) % sector_size; } uint16_t cl_to_entry_sector(uint32_t cl) { if (fat_type == T_FAT16) - return reserved + (cl * 2 / sector_size); + return reserved + (cl * 2 / sector_size); else // T_FAT32 - return reserved + (cl * 4 / sector_size); + return reserved + (cl * 4 / sector_size); } // initialize filesystem by providing base sector diff --git a/api/fs/filesystem.hpp b/api/fs/filesystem.hpp index 498f642f74..215e0cb9b2 100644 --- a/api/fs/filesystem.hpp +++ b/api/fs/filesystem.hpp @@ -28,99 +28,99 @@ namespace fs { - class FileSystem { - public: - struct Dirent; //< Generic structure for directory entries +class FileSystem { +public: + struct Dirent; //< Generic structure for directory entries - using dirvector = std::vector; - using dirvec_t = std::shared_ptr; - using buffer_t = std::shared_ptr; + using dirvector = std::vector; + using dirvec_t = std::shared_ptr; + using buffer_t = std::shared_ptr; - using on_mount_func = std::function; - using on_ls_func = std::function; - using on_read_func = std::function; - using on_stat_func = std::function; + using on_mount_func = std::function; + using on_ls_func = std::function; + using on_read_func = std::function; + using on_stat_func = std::function; - struct Buffer - { - error_t err; - buffer_t buffer; - uint64_t len; + struct Buffer + { + error_t err; + buffer_t buffer; + uint64_t len; - Buffer(error_t e, buffer_t b, size_t l) - : err(e), buffer(b), len(l) {} - }; + Buffer(error_t e, buffer_t b, size_t l) + : err(e), buffer(b), len(l) {} + }; - enum Enttype { - FILE, - DIR, - /** FAT puts disk labels in the root directory, hence: */ - VOLUME_ID, - SYM_LINK, + enum Enttype { + FILE, + DIR, + /** FAT puts disk labels in the root directory, hence: */ + VOLUME_ID, + SYM_LINK, - INVALID_ENTITY - }; //< enum Enttype + INVALID_ENTITY + }; //< enum Enttype - /** Generic structure for directory entries */ - struct Dirent { - /** Default constructor */ - explicit Dirent(const Enttype t = INVALID_ENTITY, const std::string& n = "", - const uint64_t blk = 0U, const uint64_t pr = 0U, - const uint64_t sz = 0U, const uint32_t attr = 0U) : - ftype {t}, - fname {n}, - block {blk}, - parent {pr}, - size {sz}, - attrib {attr}, - timestamp {0} - {} + /** Generic structure for directory entries */ + struct Dirent { + /** Default constructor */ + explicit Dirent(const Enttype t = INVALID_ENTITY, const std::string& n = "", + const uint64_t blk = 0U, const uint64_t pr = 0U, + const uint64_t sz = 0U, const uint32_t attr = 0U) : + ftype {t}, + fname {n}, + block {blk}, + parent {pr}, + size {sz}, + attrib {attr}, + timestamp {0} + {} - Enttype ftype; - std::string fname; - uint64_t block; - uint64_t parent; //< Parent's block# - uint64_t size; - uint32_t attrib; - int64_t timestamp; + Enttype ftype; + std::string fname; + uint64_t block; + uint64_t parent; //< Parent's block# + uint64_t size; + uint32_t attrib; + int64_t timestamp; - Enttype type() const noexcept - { return ftype; } + Enttype type() const noexcept + { return ftype; } - // true if this dirent is valid - // if not, it means don't read any values from the Dirent as they are not - bool is_valid() const - { return ftype != INVALID_ENTITY; } + // true if this dirent is valid + // if not, it means don't read any values from the Dirent as they are not + bool is_valid() const + { return ftype != INVALID_ENTITY; } - // most common types - bool is_file() const noexcept - { return ftype == FILE; } - bool is_dir() const noexcept - { return ftype == DIR; } + // most common types + bool is_file() const noexcept + { return ftype == FILE; } + bool is_dir() const noexcept + { return ftype == DIR; } - // the entrys name - const std::string& name() const noexcept - { return fname; } + // the entrys name + const std::string& name() const noexcept + { return fname; } - // type converted to human-readable string - std::string type_string() const { - switch (ftype) { - case FILE: - return "File"; - case DIR: - return "Directory"; - case VOLUME_ID: - return "Volume ID"; + // type converted to human-readable string + std::string type_string() const { + switch (ftype) { + case FILE: + return "File"; + case DIR: + return "Directory"; + case VOLUME_ID: + return "Volume ID"; - case INVALID_ENTITY: - return "Invalid entity"; - default: - return "Unknown type"; - } //< switch (type) - } - }; //< struct Dirent + case INVALID_ENTITY: + return "Invalid entity"; + default: + return "Unknown type"; + } //< switch (type) + } + }; //< struct Dirent - /** Mount this filesystem with LBA at @base_sector */ + /** Mount this filesystem with LBA at @base_sector */ virtual void mount(uint64_t lba, uint64_t size, on_mount_func on_mount) = 0; /** @param path: Path in the mounted filesystem */ @@ -144,13 +144,13 @@ namespace fs { /** Default destructor */ virtual ~FileSystem() noexcept = default; - }; //< class FileSystem +}; //< class FileSystem - // simplify initializing shared vector - inline FileSystem::dirvec_t new_shared_vector() - { - return std::make_shared (); - } +// simplify initializing shared vector +inline FileSystem::dirvec_t new_shared_vector() +{ + return std::make_shared (); +} } //< namespace fs diff --git a/api/fs/mbr.hpp b/api/fs/mbr.hpp index f888162e0d..d36d539544 100644 --- a/api/fs/mbr.hpp +++ b/api/fs/mbr.hpp @@ -24,53 +24,53 @@ namespace fs { - struct MBR { - static constexpr int PARTITIONS {4}; +struct MBR { + static constexpr int PARTITIONS {4}; - struct partition { - uint8_t flags; - uint8_t CHS_BEG[3]; - uint8_t type; - uint8_t CHS_END[3]; - uint32_t lba_begin; - uint32_t sectors; - } __attribute__((packed)); + struct partition { + uint8_t flags; + uint8_t CHS_BEG[3]; + uint8_t type; + uint8_t CHS_END[3]; + uint32_t lba_begin; + uint32_t sectors; + } __attribute__((packed)); - /** Legacy BIOS Parameter Block */ - struct BPB { - uint16_t bytes_per_sector; - uint8_t sectors_per_cluster; - uint16_t reserved_sectors; - uint8_t fa_tables; - uint16_t root_entries; - uint16_t small_sectors; - uint8_t media_type; // 0xF8 == hard drive - uint16_t sectors_per_fat; - uint16_t sectors_per_track; - uint16_t num_heads; - uint32_t hidden_sectors; - uint32_t large_sectors; // Used if small_sectors == 0 - uint8_t disk_number; // Starts at 0x80 - uint8_t current_head; - uint8_t signature; // Must be 0x28 or 0x29 - uint32_t serial_number; // Unique ID created by mkfs - char volume_label[11]; // Deprecated - char system_id[8]; // FAT12 or FAT16 - } __attribute__((packed)); + /** Legacy BIOS Parameter Block */ + struct BPB { + uint16_t bytes_per_sector; + uint8_t sectors_per_cluster; + uint16_t reserved_sectors; + uint8_t fa_tables; + uint16_t root_entries; + uint16_t small_sectors; + uint8_t media_type; // 0xF8 == hard drive + uint16_t sectors_per_fat; + uint16_t sectors_per_track; + uint16_t num_heads; + uint32_t hidden_sectors; + uint32_t large_sectors; // Used if small_sectors == 0 + uint8_t disk_number; // Starts at 0x80 + uint8_t current_head; + uint8_t signature; // Must be 0x28 or 0x29 + uint32_t serial_number; // Unique ID created by mkfs + char volume_label[11]; // Deprecated + char system_id[8]; // FAT12 or FAT16 + } __attribute__((packed)); - struct mbr { - uint8_t jump[3]; - char oem_name[8]; - uint8_t boot[435]; // Boot-code - partition part[PARTITIONS]; - uint16_t magic; // 0xAA55 + struct mbr { + uint8_t jump[3]; + char oem_name[8]; + uint8_t boot[435]; // Boot-code + partition part[PARTITIONS]; + uint16_t magic; // 0xAA55 - inline BPB* bpb() noexcept - { return reinterpret_cast(boot); } - } __attribute__((packed)); + inline BPB* bpb() noexcept + { return reinterpret_cast(boot); } + } __attribute__((packed)); - static std::string id_to_name(uint8_t); - }; //< struct MBR + static std::string id_to_name(uint8_t); +}; //< struct MBR } //< namespace fs diff --git a/api/fs/memdisk.hpp b/api/fs/memdisk.hpp index cab44d12f2..d5397a74d4 100644 --- a/api/fs/memdisk.hpp +++ b/api/fs/memdisk.hpp @@ -25,35 +25,35 @@ namespace fs { - class MemDisk : public hw::IDiskDevice { - public: - static constexpr size_t SECTOR_SIZE = 512; +class MemDisk : public hw::IDiskDevice { +public: + static constexpr size_t SECTOR_SIZE = 512; - MemDisk() noexcept; + MemDisk() noexcept; - /** Returns the optimal block size for this device. */ - virtual block_t block_size() const noexcept override - { return SECTOR_SIZE; } + /** Returns the optimal block size for this device. */ + virtual block_t block_size() const noexcept override + { return SECTOR_SIZE; } - virtual const char* name() const noexcept override - { - return "MemDisk"; - } + virtual const char* name() const noexcept override + { + return "MemDisk"; + } - virtual void - read(block_t blk, on_read_func reader) override; + virtual void + read(block_t blk, on_read_func reader) override; - virtual void - read(block_t start, block_t cnt, on_read_func reader) override; + virtual void + read(block_t start, block_t cnt, on_read_func reader) override; - virtual buffer_t read_sync(block_t blk) override; + virtual buffer_t read_sync(block_t blk) override; - virtual block_t size() const noexcept override; + virtual block_t size() const noexcept override; - private: - void* image_start; - void* image_end; - }; //< class MemDisk +private: + void* image_start; + void* image_end; +}; //< class MemDisk } //< namespace fs diff --git a/api/fs/path.hpp b/api/fs/path.hpp index 2abd3e7449..55bcf088db 100644 --- a/api/fs/path.hpp +++ b/api/fs/path.hpp @@ -24,79 +24,79 @@ namespace fs { - class Path { - public: - //! constructs Path to the current directory - Path(); +class Path { +public: + //! constructs Path to the current directory + Path(); - //! constructs Path to @path - Path(const std::string& path); + //! constructs Path to @path + Path(const std::string& path); - size_t size() const noexcept - { return stk.size(); } + size_t size() const noexcept + { return stk.size(); } - const std::string& operator [] (const int i) const noexcept - { return stk[i]; } + const std::string& operator [] (const int i) const noexcept + { return stk[i]; } - int getState() const noexcept - { return state; } + int getState() const noexcept + { return state; } - Path& operator = (const std::string& p) { - stk.clear(); - this->state = parse(p); - return *this; - } + Path& operator = (const std::string& p) { + stk.clear(); + this->state = parse(p); + return *this; + } - Path& operator += (const std::string& p) { - this->state = parse(p); - return *this; - } + Path& operator += (const std::string& p) { + this->state = parse(p); + return *this; + } - Path operator + (const std::string& p) const { - Path np = Path(*this); - np.state = np.parse(p); - return np; - } + Path operator + (const std::string& p) const { + Path np = Path(*this); + np.state = np.parse(p); + return np; + } - bool operator == (const Path& p) const { - if (stk.size() not_eq p.stk.size()) return false; - return this->to_string() == p.to_string(); - } + bool operator == (const Path& p) const { + if (stk.size() not_eq p.stk.size()) return false; + return this->to_string() == p.to_string(); + } - bool operator != (const Path& p) const - { return not this->operator == (p); } + bool operator != (const Path& p) const + { return not this->operator == (p); } - bool operator == (const std::string& p) const - { return *this == Path(p); } + bool operator == (const std::string& p) const + { return *this == Path(p); } - bool empty() const noexcept - { return stk.empty(); } + bool empty() const noexcept + { return stk.empty(); } - std::string front() const - { return stk.front(); } + std::string front() const + { return stk.front(); } - std::string back() const - { return stk.back(); } + std::string back() const + { return stk.back(); } - Path& pop_front() noexcept - { stk.pop_front(); return *this; } + Path& pop_front() noexcept + { stk.pop_front(); return *this; } - Path& pop_back() noexcept - { stk.pop_back(); return *this; } + Path& pop_back() noexcept + { stk.pop_back(); return *this; } - Path& up() - { if (not stk.empty()) stk.pop_back(); return *this; } + Path& up() + { if (not stk.empty()) stk.pop_back(); return *this; } - std::string to_string() const; + std::string to_string() const; - private: - int parse(const std::string& path); - void name_added(const std::string& name); - std::string real_path() const; +private: + int parse(const std::string& path); + void name_added(const std::string& name); + std::string real_path() const; - int state; - std::deque stk; - }; //< class Path + int state; + std::deque stk; +}; //< class Path } //< namespace fs diff --git a/api/fs/vbr.hpp b/api/fs/vbr.hpp index dbb145b7bf..bef8b24129 100644 --- a/api/fs/vbr.hpp +++ b/api/fs/vbr.hpp @@ -21,9 +21,9 @@ namespace fs { - class VBR { +class VBR { - }; //< class VBR +}; //< class VBR } //< namespace fs diff --git a/api/hw/dev.hpp b/api/hw/dev.hpp index 559d72982f..5571982d1d 100644 --- a/api/hw/dev.hpp +++ b/api/hw/dev.hpp @@ -30,58 +30,58 @@ namespace hw { - /** @Todo: Implement */ - class Serial; - class APIC; - class HPET; +/** @Todo: Implement */ +class Serial; +class APIC; +class HPET; - /** - * Access point for devices - * - * Get a nic by calling `Dev::eth<0, Virtio_Net>(n)`, a disk by calling `Dev::disk<0, VirtioBlk>(n)` etc. - */ - class Dev { - public: - /** Get ethernet device n */ - template - static Nic& eth() { - static Nic eth_ {PCI_manager::device(N)}; - return eth_; - } +/** + * Access point for devices + * + * Get a nic by calling `Dev::eth<0, Virtio_Net>(n)`, a disk by calling `Dev::disk<0, VirtioBlk>(n)` etc. + */ +class Dev { +public: + /** Get ethernet device n */ + template + static Nic& eth() { + static Nic eth_ {PCI_manager::device(N)}; + return eth_; + } - /** Get disk N using driver DRIVER */ - template - static Disk& disk(Args&&... args) { - static Disk - disk_ { - PCI_manager::device(N), - std::forward(args)... - }; - return disk_; - } + /** Get disk N using driver DRIVER */ + template + static Disk& disk(Args&&... args) { + static Disk + disk_ { + PCI_manager::device(N), + std::forward(args)... + }; + return disk_; + } - /** Get console N using driver DRIVER */ - template - static DRIVER& console() { - static DRIVER con_ {PCI_manager::device(N)}; - return con_; - } + /** Get console N using driver DRIVER */ + template + static DRIVER& console() { + static DRIVER con_ {PCI_manager::device(N)}; + return con_; + } - /** - * Get serial port n - * - * @Todo: Make a serial port class, and move rsprint / rswrite etc. from OS out to it. - * - * @Note: The DRIVER parameter is there to support virtio serial ports. - */ - template - static PCI_Device& serial(int n); + /** + * Get serial port n + * + * @Todo: Make a serial port class, and move rsprint / rswrite etc. from OS out to it. + * + * @Note: The DRIVER parameter is there to support virtio serial ports. + */ + template + static PCI_Device& serial(int n); - /** Programmable Interval Timer device, with ~ms-precision asynchronous timers. */ - static PIT& basic_timer() { - return PIT::instance(); - } - }; //< class Dev + /** Programmable Interval Timer device, with ~ms-precision asynchronous timers. */ + static PIT& basic_timer() { + return PIT::instance(); + } +}; //< class Dev } //< namespace hw diff --git a/api/hw/disk.hpp b/api/hw/disk.hpp index 548fc8ca94..b616613fef 100644 --- a/api/hw/disk.hpp +++ b/api/hw/disk.hpp @@ -23,55 +23,55 @@ namespace hw { - template - class Disk : public IDiskDevice { - public: - /** optimal block size for this device */ - virtual block_t block_size() const noexcept override - { return driver.block_size(); } +template +class Disk : public IDiskDevice { +public: + /** optimal block size for this device */ + virtual block_t block_size() const noexcept override + { return driver.block_size(); } - /** Human readable name */ - const char* name() const noexcept override - { - return driver.name(); - } + /** Human readable name */ + const char* name() const noexcept override + { + return driver.name(); + } - virtual void - read(block_t blk, on_read_func del) override - { - driver.read(blk, del); - } - virtual void - read(block_t blk, block_t count, on_read_func del) override - { - driver.read(blk, count, del); - } + virtual void + read(block_t blk, on_read_func del) override + { + driver.read(blk, del); + } + virtual void + read(block_t blk, block_t count, on_read_func del) override + { + driver.read(blk, count, del); + } - virtual buffer_t read_sync(block_t blk) override - { - return driver.read_sync(blk); - } + virtual buffer_t read_sync(block_t blk) override + { + return driver.read_sync(blk); + } - virtual block_t size() const noexcept override - { - return driver.size(); - } + virtual block_t size() const noexcept override + { + return driver.size(); + } - virtual ~Disk() = default; + virtual ~Disk() = default; - private: - DRIVER driver; +private: + DRIVER driver; - /** - * Just a wrapper around the driver constructor - * @note The Dev-class is a friend and will call this - */ - template - explicit Disk(PCI_Device& d, Args&&... args): - driver{d, std::forward(args)... } {} + /** + * Just a wrapper around the driver constructor + * @note The Dev-class is a friend and will call this + */ + template + explicit Disk(PCI_Device& d, Args&&... args): + driver{d, std::forward(args)... } {} - friend class Dev; - }; //< class Disk + friend class Dev; +}; //< class Disk } //< namespace hw diff --git a/api/hw/disk_device.hpp b/api/hw/disk_device.hpp index 909165f41a..0612356c3c 100644 --- a/api/hw/disk_device.hpp +++ b/api/hw/disk_device.hpp @@ -26,39 +26,39 @@ namespace hw { - class IDiskDevice { - public: - using block_t = uint64_t; //< Disk device block size - using buffer_t = std::shared_ptr; +class IDiskDevice { +public: + using block_t = uint64_t; //< Disk device block size + using buffer_t = std::shared_ptr; - // Delegate for result of reading a disk sector - using on_read_func = std::function; + // Delegate for result of reading a disk sector + using on_read_func = std::function; - /** Human-readable name of this disk controller */ - virtual const char* name() const noexcept = 0; + /** Human-readable name of this disk controller */ + virtual const char* name() const noexcept = 0; - /** The size of the disk in whole sectors */ - virtual block_t size() const noexcept = 0; + /** The size of the disk in whole sectors */ + virtual block_t size() const noexcept = 0; - /** Returns the optimal block size for this device */ - virtual block_t block_size() const noexcept = 0; + /** Returns the optimal block size for this device */ + virtual block_t block_size() const noexcept = 0; - /** - * Read block(s) from blk and call func with result - * A null-pointer is passed to result if something bad happened - * Validate using !buffer_t: - * if (!buffer) - * error("Device failed to read sector"); - **/ - virtual void read(block_t blk, on_read_func func) = 0; - virtual void read(block_t blk, block_t count, on_read_func) = 0; + /** + * Read block(s) from blk and call func with result + * A null-pointer is passed to result if something bad happened + * Validate using !buffer_t: + * if (!buffer) + * error("Device failed to read sector"); + **/ + virtual void read(block_t blk, on_read_func func) = 0; + virtual void read(block_t blk, block_t count, on_read_func) = 0; - /** read synchronously the block @blk */ - virtual buffer_t read_sync(block_t blk) = 0; + /** read synchronously the block @blk */ + virtual buffer_t read_sync(block_t blk) = 0; - /** Default destructor */ - virtual ~IDiskDevice() noexcept = default; - }; //< class IDiskDevice + /** Default destructor */ + virtual ~IDiskDevice() noexcept = default; +}; //< class IDiskDevice } //< namespace hw diff --git a/api/hw/ide.hpp b/api/hw/ide.hpp index 76bb08b0c6..0d6ac60c4f 100644 --- a/api/hw/ide.hpp +++ b/api/hw/ide.hpp @@ -25,58 +25,58 @@ namespace hw { - /** IDE device driver */ - class IDE : public IDiskDevice { - public: - enum selector_t - { - MASTER, - SLAVE - }; +/** IDE device driver */ +class IDE : public IDiskDevice { +public: + enum selector_t + { + MASTER, + SLAVE + }; - /** - * Constructor - * - * @param pcidev: An initialized PCI device - */ - explicit IDE(hw::PCI_Device& pcidev, selector_t); + /** + * Constructor + * + * @param pcidev: An initialized PCI device + */ + explicit IDE(hw::PCI_Device& pcidev, selector_t); - /** Human-readable name of this disk controller */ - virtual const char* name() const noexcept override - { return "IDE Controller"; } + /** Human-readable name of this disk controller */ + virtual const char* name() const noexcept override + { return "IDE Controller"; } - /** Returns the optimal block size for this device. */ - virtual block_t block_size() const noexcept override - { return 512; } + /** Returns the optimal block size for this device. */ + virtual block_t block_size() const noexcept override + { return 512; } - virtual void read(block_t blk, on_read_func reader) override; - virtual void read(block_t blk, block_t count, on_read_func reader) override; + virtual void read(block_t blk, on_read_func reader) override; + virtual void read(block_t blk, block_t count, on_read_func reader) override; - /** read synchronously from IDE disk */ - virtual buffer_t read_sync(block_t blk) override; + /** read synchronously from IDE disk */ + virtual buffer_t read_sync(block_t blk) override; - virtual block_t size() const noexcept override - { return _nb_blk; } + virtual block_t size() const noexcept override + { return _nb_blk; } - private: - void set_drive(const uint8_t drive) const noexcept; - void set_nbsectors(const uint8_t cnt) const noexcept; - void set_blocknum(block_t blk) const noexcept; - void set_command(const uint16_t command) const noexcept; - void set_irq_mode(const bool on) const noexcept; +private: + void set_drive(const uint8_t drive) const noexcept; + void set_nbsectors(const uint8_t cnt) const noexcept; + void set_blocknum(block_t blk) const noexcept; + void set_command(const uint16_t command) const noexcept; + void set_irq_mode(const bool on) const noexcept; - void wait_status_busy() const noexcept; - void wait_status_flags(const int flags, const bool set) const noexcept; + void wait_status_busy() const noexcept; + void wait_status_flags(const int flags, const bool set) const noexcept; - void irq_handler(); - void enable_irq_handler(); + void irq_handler(); + void enable_irq_handler(); - private: - hw::PCI_Device& _pcidev; // PCI device - uint8_t _drive; // Drive id (IDE_MASTER or IDE_SLAVE) - uint32_t _iobase; // PCI device io base address - block_t _nb_blk; // Max nb blocks of the device - }; //< class IDE +private: + hw::PCI_Device& _pcidev; // PCI device + uint8_t _drive; // Drive id (IDE_MASTER or IDE_SLAVE) + uint32_t _iobase; // PCI device io base address + block_t _nb_blk; // Max nb blocks of the device +}; //< class IDE } //< namespace hw diff --git a/api/hw/pci.hpp b/api/hw/pci.hpp index fbd0b5a975..f839eae85d 100644 --- a/api/hw/pci.hpp +++ b/api/hw/pci.hpp @@ -5,53 +5,53 @@ namespace hw { - typedef uint16_t port_t; +typedef uint16_t port_t; - static inline int inp(port_t port) - { - int ret; +static inline int inp(port_t port) +{ + int ret; - __asm__ volatile("xorl %eax,%eax"); - __asm__ volatile("inb %%dx,%%al" - :"=a"(ret) - :"d"(port)); - return ret; - } - - static inline uint16_t inpw(port_t port) - { - uint16_t ret; - __asm__ volatile("xorl %eax,%eax"); - __asm__ volatile("inw %%dx,%%ax" - :"=a"(ret) - :"d"(port)); - return ret; - } - - static inline uint32_t inpd(port_t port) - { - uint32_t ret; - __asm__ volatile("xorl %eax,%eax"); - __asm__ volatile("inl %%dx,%%eax" - :"=a"(ret) - :"d"(port)); + __asm__ volatile("xorl %eax,%eax"); + __asm__ volatile("inb %%dx,%%al" + :"=a"(ret) + :"d"(port)); + return ret; +} + +static inline uint16_t inpw(port_t port) +{ + uint16_t ret; + __asm__ volatile("xorl %eax,%eax"); + __asm__ volatile("inw %%dx,%%ax" + :"=a"(ret) + :"d"(port)); + return ret; +} + +static inline uint32_t inpd(port_t port) +{ + uint32_t ret; + __asm__ volatile("xorl %eax,%eax"); + __asm__ volatile("inl %%dx,%%eax" + :"=a"(ret) + :"d"(port)); - return ret; - } - - - static inline void outp(port_t port, uint8_t data) - { - __asm__ volatile ("outb %%al,%%dx"::"a" (data), "d"(port)); - } - static inline void outpw(port_t port, uint16_t data) - { - __asm__ volatile ("outw %%ax,%%dx"::"a" (data), "d"(port)); - } - static inline void outpd(port_t port, uint32_t data) - { - __asm__ volatile ("outl %%eax,%%dx"::"a" (data), "d"(port)); - } + return ret; +} + + +static inline void outp(port_t port, uint8_t data) +{ + __asm__ volatile ("outb %%al,%%dx"::"a" (data), "d"(port)); +} +static inline void outpw(port_t port, uint16_t data) +{ + __asm__ volatile ("outw %%ax,%%dx"::"a" (data), "d"(port)); +} +static inline void outpd(port_t port, uint32_t data) +{ + __asm__ volatile ("outl %%eax,%%dx"::"a" (data), "d"(port)); +} } //< namespace hw diff --git a/api/hw/pci_device.hpp b/api/hw/pci_device.hpp index fb55a09972..4e200fa1a3 100644 --- a/api/hw/pci_device.hpp +++ b/api/hw/pci_device.hpp @@ -23,244 +23,244 @@ namespace PCI { - static const uint16_t CONFIG_ADDR {0xCF8U}; - static const uint16_t CONFIG_DATA {0xCFCU}; - static const uint8_t CONFIG_INTR {0x3CU}; +static const uint16_t CONFIG_ADDR {0xCF8U}; +static const uint16_t CONFIG_DATA {0xCFCU}; +static const uint8_t CONFIG_INTR {0x3CU}; - static const uint8_t CONFIG_VENDOR {0x00U}; - static const uint8_t CONFIG_CLASS_REV {0x08U}; +static const uint8_t CONFIG_VENDOR {0x00U}; +static const uint8_t CONFIG_CLASS_REV {0x08U}; - static const uint8_t CONFIG_BASE_ADDR_0 {0x10U}; +static const uint8_t CONFIG_BASE_ADDR_0 {0x10U}; - static const uint32_t BASE_ADDRESS_MEM_MASK {~0x0FUL}; - static const uint32_t BASE_ADDRESS_IO_MASK {~0x03UL}; +static const uint32_t BASE_ADDRESS_MEM_MASK {~0x0FUL}; +static const uint32_t BASE_ADDRESS_IO_MASK {~0x03UL}; - static const uint32_t WTF {0xffffffffU}; +static const uint32_t WTF {0xffffffffU}; - /** - * @brief PCI device message format - * - * Used to communicate with PCI devices - */ - union msg { +/** + * @brief PCI device message format + * + * Used to communicate with PCI devices + */ +union msg { - //! The whole message - uint32_t data; + //! The whole message + uint32_t data; - /** - * Packed attribtues, ordered low to high. - * - * @note: Doxygen thinks this is a function - it's not - * - * it's a GCC-directive. - */ - struct __attribute__((packed)) { - //! The PCI register - uint8_t reg; + /** + * Packed attribtues, ordered low to high. + * + * @note: Doxygen thinks this is a function - it's not + * + * it's a GCC-directive. + */ + struct __attribute__((packed)) { + //! The PCI register + uint8_t reg; - //! The 16-bit PCI-address @see pci_addr() - uint16_t addr; - uint8_t code; - }; - }; //< union msg + //! The 16-bit PCI-address @see pci_addr() + uint16_t addr; + uint8_t code; + }; +}; //< union msg - /** Relevant class codes (many more) */ - enum classcode_t { - OLD, - STORAGE, - NIC, - DISPLAY, - MULTIMEDIA, - MEMORY, - BRIDGE, - COMMUNICATION, - BASE_SYSTEM_PER, - INPUT_DEVICE, - DOCKING_STATION, - PROCESSOR, - SERIAL_BUS, - WIRELESS, - IO_CTL, - SATELLITE, - ENCRYPTION, - SIGPRO, - OTHER=255 - }; //< enum classcode_t +/** Relevant class codes (many more) */ +enum classcode_t { + OLD, + STORAGE, + NIC, + DISPLAY, + MULTIMEDIA, + MEMORY, + BRIDGE, + COMMUNICATION, + BASE_SYSTEM_PER, + INPUT_DEVICE, + DOCKING_STATION, + PROCESSOR, + SERIAL_BUS, + WIRELESS, + IO_CTL, + SATELLITE, + ENCRYPTION, + SIGPRO, + OTHER=255 +}; //< enum classcode_t } //< namespace PCI namespace hw { - /** - * @brief Communication class for all PCI devices - * - * All low level communication with PCI devices should (ideally) go here. - * - * @todo - * - Consider if we ever need to separate the address into 'bus/dev/func' parts. - * - Do we ever need anything but PCI Devices? - */ - class PCI_Device { // public Device //Why not? A PCI device is too general to be accessible? - public: +/** + * @brief Communication class for all PCI devices + * + * All low level communication with PCI devices should (ideally) go here. + * + * @todo + * - Consider if we ever need to separate the address into 'bus/dev/func' parts. + * - Do we ever need anything but PCI Devices? +*/ +class PCI_Device { // public Device //Why not? A PCI device is too general to be accessible? +public: - enum { - VENDOR_AMD = 0x1022, - VENDOR_INTEL = 0x8086, - VENDOR_CIRRUS = 0x1013, - VENDOR_VIRTIO = 0x1AF4, - VENDOR_REALTEK = 0x10EC - }; + enum { + VENDOR_AMD = 0x1022, + VENDOR_INTEL = 0x8086, + VENDOR_CIRRUS = 0x1013, + VENDOR_VIRTIO = 0x1AF4, + VENDOR_REALTEK = 0x10EC + }; - /** - * Constructor - * - * @param pci_addr: A 16-bit PCI address. - * @param device_id: A device ID, consisting of PCI vendor and product ID's. - * - * @see pci_addr() for more about the address - */ - explicit PCI_Device(const uint16_t pci_addr, const uint32_t device_id) noexcept; + /** + * Constructor + * + * @param pci_addr: A 16-bit PCI address. + * @param device_id: A device ID, consisting of PCI vendor and product ID's. + * + * @see pci_addr() for more about the address + */ + explicit PCI_Device(const uint16_t pci_addr, const uint32_t device_id) noexcept; - //! @brief Read from device with implicit pci_address (e.g. used by Nic) - uint32_t read_dword(const uint8_t reg) noexcept; + //! @brief Read from device with implicit pci_address (e.g. used by Nic) + uint32_t read_dword(const uint8_t reg) noexcept; - //! @brief Read from device with explicit pci_addr - static uint32_t read_dword(const uint16_t pci_addr, const uint8_t reg) noexcept; + //! @brief Read from device with explicit pci_addr + static uint32_t read_dword(const uint16_t pci_addr, const uint8_t reg) noexcept; - /** - * Probe for a device on the given address - * - * @param pci_addr: the address to probe - * - * @deprecated We got a 20% performance degradation using this for probing - * - * @see PCI_Device() - */ - static PCI_Device* Create(uint16_t pci_addr); + /** + * Probe for a device on the given address + * + * @param pci_addr: the address to probe + * + * @deprecated We got a 20% performance degradation using this for probing + * + * @see PCI_Device() + */ + static PCI_Device* Create(uint16_t pci_addr); - // @brief Get a device by address. @see pci_addr(). - static PCI_Device* get(uint16_t pci_addr); + // @brief Get a device by address. @see pci_addr(). + static PCI_Device* get(uint16_t pci_addr); - // @brief Get a device by individual address parts. - // @todo Will we ever need this? - static PCI_Device* get(int busno, int devno, int funcno); + // @brief Get a device by individual address parts. + // @todo Will we ever need this? + static PCI_Device* get(int busno, int devno, int funcno); - /** A descriptive name */ - inline const char* name(); + /** A descriptive name */ + inline const char* name(); - /** - * Get the PCI address of device. - * - * The address is a composite of 'bus', 'device' and 'function', usually used - * (i.e. by Linux) to designate a PCI device. - * - * @return: The address of the device - */ - inline uint16_t pci_addr() const noexcept - { return pci_addr_; }; + /** + * Get the PCI address of device. + * + * The address is a composite of 'bus', 'device' and 'function', usually used + * (i.e. by Linux) to designate a PCI device. + * + * @return: The address of the device + */ + inline uint16_t pci_addr() const noexcept + { return pci_addr_; }; - /** Get the pci class code. */ - inline PCI::classcode_t classcode() const noexcept - { return static_cast(devtype_.classcode); } + /** Get the pci class code. */ + inline PCI::classcode_t classcode() const noexcept + { return static_cast(devtype_.classcode); } - inline uint16_t rev_id() const noexcept - { return devtype_.rev_id; } + inline uint16_t rev_id() const noexcept + { return devtype_.rev_id; } - /** Get the pci vendor and product id */ - inline uint16_t vendor_id() const noexcept - { return device_id_.vendor; } + /** Get the pci vendor and product id */ + inline uint16_t vendor_id() const noexcept + { return device_id_.vendor; } - inline uint16_t product_id() const noexcept - { return device_id_.product; } + inline uint16_t product_id() const noexcept + { return device_id_.product; } - /** - * Parse all Base Address Registers (BAR's) - * - * Used to determine how to communicate with the device. - * - * This function adds resources to the PCI_Device. - */ - void probe_resources() noexcept; + /** + * Parse all Base Address Registers (BAR's) + * + * Used to determine how to communicate with the device. + * + * This function adds resources to the PCI_Device. + */ + void probe_resources() noexcept; - /** The base address of the (first) I/O resource */ - uint32_t iobase() const noexcept; + /** The base address of the (first) I/O resource */ + uint32_t iobase() const noexcept; - private: - // @brief The 3-part PCI address - uint16_t pci_addr_; +private: + // @brief The 3-part PCI address + uint16_t pci_addr_; - //@brief The three address parts derived (if needed) - uint8_t busno_ {0}; - uint8_t devno_ {0}; - uint8_t funcno_ {0}; + //@brief The three address parts derived (if needed) + uint8_t busno_ {0}; + uint8_t devno_ {0}; + uint8_t funcno_ {0}; - // @brief The 2-part ID retrieved from the device - union vendor_product { - uint32_t __value; - struct __attribute__((packed)) { - uint16_t vendor; - uint16_t product; - }; - } device_id_; + // @brief The 2-part ID retrieved from the device + union vendor_product { + uint32_t __value; + struct __attribute__((packed)) { + uint16_t vendor; + uint16_t product; + }; + } device_id_; - // @brief The class code (device type) - union class_revision { - uint32_t reg; - struct __attribute__((packed)) { - uint8_t rev_id; - uint8_t prog_if; - uint8_t subclass; - uint8_t classcode; - }; - struct __attribute__((packed)) { - uint16_t class_subclass; - uint8_t __prog_if; //Overlaps the above - uint8_t revision; - }; - } devtype_; + // @brief The class code (device type) + union class_revision { + uint32_t reg; + struct __attribute__((packed)) { + uint8_t rev_id; + uint8_t prog_if; + uint8_t subclass; + uint8_t classcode; + }; + struct __attribute__((packed)) { + uint16_t class_subclass; + uint8_t __prog_if; //Overlaps the above + uint8_t revision; + }; + } devtype_; - // @brief Printable names - const char* classname_; - const char* vendorname_; - const char* productname_; + // @brief Printable names + const char* classname_; + const char* vendorname_; + const char* productname_; - // Device Resources + // Device Resources - //! @brief Resource types, "Memory" or "I/O" - enum resource_t { RES_MEM, RES_IO }; + //! @brief Resource types, "Memory" or "I/O" + enum resource_t { RES_MEM, RES_IO }; - /** A device resource - possibly a list */ - template - struct Resource { - const resource_t type {RT}; - uint32_t start_; - uint32_t len_; - Resource* next {nullptr}; - Resource(const uint32_t start, const uint32_t len) : start_{start}, len_{len} {}; - }; + /** A device resource - possibly a list */ + template + struct Resource { + const resource_t type {RT}; + uint32_t start_; + uint32_t len_; + Resource* next {nullptr}; + Resource(const uint32_t start, const uint32_t len) : start_{start}, len_{len} {}; + }; - //! @brief Resource lists. Members added by add_resource(); - Resource* res_mem_ {nullptr}; - Resource* res_io_ {nullptr}; + //! @brief Resource lists. Members added by add_resource(); + Resource* res_mem_ {nullptr}; + Resource* res_io_ {nullptr}; - //! @brief Write to device with implicit pci_address (e.g. used by Nic) - void write_dword(const uint8_t reg, const uint32_t value) noexcept; + //! @brief Write to device with implicit pci_address (e.g. used by Nic) + void write_dword(const uint8_t reg, const uint32_t value) noexcept; - /** - * Add a resource to a resource queue. - * - * (This seems pretty dirty; private class, reference to pointer etc.) */ - template - void add_resource(Resource* res, Resource*& Q) noexcept { - Resource* q; - if (Q) { - q = Q; - while (q->next) q = q->next; - q->next = res; - } else { - Q = res; - } + /** + * Add a resource to a resource queue. + * + * (This seems pretty dirty; private class, reference to pointer etc.) */ + template + void add_resource(Resource* res, Resource*& Q) noexcept { + Resource* q; + if (Q) { + q = Q; + while (q->next) q = q->next; + q->next = res; + } else { + Q = res; } - }; //< class PCI_Device + } +}; //< class PCI_Device } //< namespace hw diff --git a/api/hw/pic.hpp b/api/hw/pic.hpp index c08b346f77..392e7f6600 100644 --- a/api/hw/pic.hpp +++ b/api/hw/pic.hpp @@ -27,7 +27,7 @@ namespace hw { /** Programmable Interrupt Controller implementation according to Intel 8259A / 8259A-2 1988 whitepaper - */ + */ class PIC { public: static void init() noexcept; @@ -49,19 +49,19 @@ namespace hw { } /** - @brief End of Interrupt. Master IRQ-lines (0-7) currently use Auto EOI, - but the user should assume that IRQ-specific EOI's are necessary. + @brief End of Interrupt. Master IRQ-lines (0-7) currently use Auto EOI, + but the user should assume that IRQ-specific EOI's are necessary. - @note: - According to Intel 8259A / 8259A-2 whitepaper p. 15 - "The AEOI mode can only be used in a master 8259A and not a slave. - 8259As with a copyright date of 1985 or later will operate in the AEOI - mode as a master or a slave" + @note: + According to Intel 8259A / 8259A-2 whitepaper p. 15 + "The AEOI mode can only be used in a master 8259A and not a slave. + 8259As with a copyright date of 1985 or later will operate in the AEOI + mode as a master or a slave" - If I enable auto-eoi for slave, everything seems to freeze in Qemu, - the moment I get the first network interrupt (IRQ 11). + If I enable auto-eoi for slave, everything seems to freeze in Qemu, + the moment I get the first network interrupt (IRQ 11). - I'm assuming this means that I have an old chip :-) + I'm assuming this means that I have an old chip :-) */ inline static void eoi(const uint8_t irq) noexcept { diff --git a/api/hw/pit.hpp b/api/hw/pit.hpp index 5d21588c9d..7e29aff3a6 100644 --- a/api/hw/pit.hpp +++ b/api/hw/pit.hpp @@ -23,165 +23,165 @@ namespace hw { - /** - Programmable Interval Timer class. A singleton. +/** + Programmable Interval Timer class. A singleton. - @TODO - ...It has timer-functionality, which should probably be super-classed, - so that i.e. the HPET could be used with the same interface. - */ - class PIT{ - public: - - typedef delegate timeout_handler; - typedef std::function repeat_condition; - - /** Create a one-shot timer. - @param ms: Expiration time. Compatible with all std::chrono durations. - @param handler: A delegate or function to be called on timeout. */ - void onTimeout(std::chrono::milliseconds ms, timeout_handler handler); + @TODO + ...It has timer-functionality, which should probably be super-classed, + so that i.e. the HPET could be used with the same interface. +*/ +class PIT{ +public: + + typedef delegate timeout_handler; + typedef std::function repeat_condition; + + /** Create a one-shot timer. + @param ms: Expiration time. Compatible with all std::chrono durations. + @param handler: A delegate or function to be called on timeout. */ + void onTimeout(std::chrono::milliseconds ms, timeout_handler handler); - /** Create a repeating timer. - @param ms: Expiration time. Compatible with all std::chrono durations. - @param handler: A delegate or function to be called every ms interval. - @param cond: The timer ends when cond() returns false. Default to true. */ - void onRepeatedTimeout(std::chrono::milliseconds ms, - timeout_handler handler, - repeat_condition cond = forever); - - /** No copy or move. The OS owns one instance forever. */ - PIT(PIT&) = delete; - PIT(PIT&&) = delete; + /** Create a repeating timer. + @param ms: Expiration time. Compatible with all std::chrono durations. + @param handler: A delegate or function to be called every ms interval. + @param cond: The timer ends when cond() returns false. Default to true. */ + void onRepeatedTimeout(std::chrono::milliseconds ms, + timeout_handler handler, + repeat_condition cond = forever); + + /** No copy or move. The OS owns one instance forever. */ + PIT(PIT&) = delete; + PIT(PIT&&) = delete; - /** Get the (single) instance. */ - static PIT& instance() { - static PIT instance_; - return instance_; - }; - - /** Initialize the hardware. */ - static void init(); - - /** The constant frequency of the PIT-hardware, before frequency dividers */ - static constexpr MHz frequency() { return frequency_; } - - static inline MHz current_frequency(){ return frequency() / current_freq_divider_; } - - /** Estimate cpu frequency based on the fixed PIT frequency and rdtsc. - @Note This is an asynchronous function. Once finished the result can be - fetched by CPUFrequency() (below) */ - static void estimateCPUFrequency(); - - /** Get the last estimated CPU frequency. May trigger frequency sampling */ - static MHz CPUFrequency(); - - private: - // Default repeat-condition - static std::function forever; - - enum Mode { ONE_SHOT = 0, - HW_ONESHOT = 1 << 1, - RATE_GEN = 2 << 1, - SQ_WAVE = 3 << 1, - SW_STROBE = 4 << 1, - HW_STROBE = 5 << 1, - NONE = 256}; - - // The PIT-chip runs at this fixed frequency (in MHz) , according to OSDev.org */ - static constexpr MHz frequency_ = MHz(14.31818 / 12); + /** Get the (single) instance. */ + static PIT& instance() { + static PIT instance_; + return instance_; + }; + + /** Initialize the hardware. */ + static void init(); + + /** The constant frequency of the PIT-hardware, before frequency dividers */ + static constexpr MHz frequency() { return frequency_; } + + static inline MHz current_frequency(){ return frequency() / current_freq_divider_; } + + /** Estimate cpu frequency based on the fixed PIT frequency and rdtsc. + @Note This is an asynchronous function. Once finished the result can be + fetched by CPUFrequency() (below) */ + static void estimateCPUFrequency(); + + /** Get the last estimated CPU frequency. May trigger frequency sampling */ + static MHz CPUFrequency(); + +private: + // Default repeat-condition + static std::function forever; + + enum Mode { ONE_SHOT = 0, + HW_ONESHOT = 1 << 1, + RATE_GEN = 2 << 1, + SQ_WAVE = 3 << 1, + SW_STROBE = 4 << 1, + HW_STROBE = 5 << 1, + NONE = 256}; + + // The PIT-chip runs at this fixed frequency (in MHz) , according to OSDev.org */ + static constexpr MHz frequency_ = MHz(14.31818 / 12); - /** Disable regular timer interrupts- which are turned on at boot-time. */ - static void disable_regular_interrupts(); + /** Disable regular timer interrupts- which are turned on at boot-time. */ + static void disable_regular_interrupts(); - /** The default (soft)handler for timer interrupts */ - void irq_handler(); + /** The default (soft)handler for timer interrupts */ + void irq_handler(); - // Private constructor / destructor. It's a singleton. - PIT(); - ~PIT(); + // Private constructor / destructor. It's a singleton. + PIT(); + ~PIT(); - // State-keeping - static Mode temp_mode_; - static uint16_t temp_freq_divider_; - static uint8_t status_byte_; - static uint16_t current_freq_divider_; - static Mode current_mode_; - static uint64_t IRQ_counter_; + // State-keeping + static Mode temp_mode_; + static uint16_t temp_freq_divider_; + static uint8_t status_byte_; + static uint16_t current_freq_divider_; + static Mode current_mode_; + static uint64_t IRQ_counter_; - // The closest we can get to a millisecond interval, with the PIT-frequency - static constexpr uint16_t millisec_interval = KHz(frequency_).count(); + // The closest we can get to a millisecond interval, with the PIT-frequency + static constexpr uint16_t millisec_interval = KHz(frequency_).count(); - // Count the "milliseconds" - static uint64_t millisec_counter; + // Count the "milliseconds" + static uint64_t millisec_counter; - // Access mode bits are bits 4- and 5 in the Mode register - enum AccessMode { LATCH_COUNT = 0x0, LO_ONLY=0x10, HI_ONLY=0x20, LO_HI=0x30 }; + // Access mode bits are bits 4- and 5 in the Mode register + enum AccessMode { LATCH_COUNT = 0x0, LO_ONLY=0x10, HI_ONLY=0x20, LO_HI=0x30 }; - /** Physically set the PIT-mode */ - static void set_mode(Mode); + /** Physically set the PIT-mode */ + static void set_mode(Mode); - /** Physiclally set the PIT frequency divider */ - static void set_freq_divider(uint16_t); + /** Physiclally set the PIT frequency divider */ + static void set_freq_divider(uint16_t); - /** Set mode to one-shot, and frequency-divider to t */ - static void oneshot(uint16_t t); + /** Set mode to one-shot, and frequency-divider to t */ + static void oneshot(uint16_t t); - /** Read back the PIT status from hardware */ - static uint8_t read_back(uint8_t channel); + /** Read back the PIT status from hardware */ + static uint8_t read_back(uint8_t channel); - /** A timer is a handler and an expiration time (interval). - @todo The timer also keeps a pre-computed rdtsc-value, which is currently unused.*/ - class Timer { - public: - enum Type { ONE_SHOT, REPEAT, REPEAT_WHILE} type_; + /** A timer is a handler and an expiration time (interval). + @todo The timer also keeps a pre-computed rdtsc-value, which is currently unused.*/ + class Timer { + public: + enum Type { ONE_SHOT, REPEAT, REPEAT_WHILE} type_; - Timer() = delete; - Timer(Type, timeout_handler, std::chrono::milliseconds, repeat_condition = forever); - Timer(const Timer&) = default; - Timer(Timer&&) = default; - Timer& operator=(Timer&) = default; - Timer& operator=(Timer&&) = default; - virtual ~Timer() = default; + Timer() = delete; + Timer(Type, timeout_handler, std::chrono::milliseconds, repeat_condition = forever); + Timer(const Timer&) = default; + Timer(Timer&&) = default; + Timer& operator=(Timer&) = default; + Timer& operator=(Timer&&) = default; + virtual ~Timer() = default; - inline Type type(){ return type_; } - inline std::chrono::milliseconds interval(){ return interval_; } - inline uint64_t start() { return timestamp_start_; } - inline uint64_t end() { return timestamp_end_; } - inline void setStart(uint64_t s) { timestamp_start_ = s; } - inline void setEnd(uint64_t e) { timestamp_end_ = e; } - inline timeout_handler handler(){ return handler_; } - inline const repeat_condition cond() { return cond_; } - inline uint32_t id(){ return id_; } - - private: - static uint32_t timers_count_; - uint32_t id_ = 0; - timeout_handler handler_; - uint64_t timestamp_start_; - uint64_t timestamp_end_; - std::chrono::milliseconds interval_; + inline Type type(){ return type_; } + inline std::chrono::milliseconds interval(){ return interval_; } + inline uint64_t start() { return timestamp_start_; } + inline uint64_t end() { return timestamp_end_; } + inline void setStart(uint64_t s) { timestamp_start_ = s; } + inline void setEnd(uint64_t e) { timestamp_end_ = e; } + inline timeout_handler handler(){ return handler_; } + inline const repeat_condition cond() { return cond_; } + inline uint32_t id(){ return id_; } + + private: + static uint32_t timers_count_; + uint32_t id_ = 0; + timeout_handler handler_; + uint64_t timestamp_start_; + uint64_t timestamp_end_; + std::chrono::milliseconds interval_; - /* This Could be a reference in the default case of "forever", but then the - case of a normal lambda being passed in, the user would have to be in charge - of storage. */ - const repeat_condition cond_; - }; - - /** A map of timers. - @note {Performance: We take advantage of the fact that std::map have sorted keys. - * Timers soonest to expire are in the front, so we only iterate over those - * Deletion of finished timers in amortized constant time, via iterators - * Timer insertion is log(n) } - @note This is why we want to instantiate PIT, and why it's a singleton: - If you don't use PIT-timers, you won't pay for them. */ - std::multimap timers_; + /* This Could be a reference in the default case of "forever", but then the + case of a normal lambda being passed in, the user would have to be in charge + of storage. */ + const repeat_condition cond_; + }; + + /** A map of timers. + @note {Performance: We take advantage of the fact that std::map have sorted keys. + * Timers soonest to expire are in the front, so we only iterate over those + * Deletion of finished timers in amortized constant time, via iterators + * Timer insertion is log(n) } + @note This is why we want to instantiate PIT, and why it's a singleton: + If you don't use PIT-timers, you won't pay for them. */ + std::multimap timers_; - /** Queue the timer. This will update timestamps in the timer */ - void start_timer(Timer t, std::chrono::milliseconds); + /** Queue the timer. This will update timestamps in the timer */ + void start_timer(Timer t, std::chrono::milliseconds); - }; +}; } //< namespace hw diff --git a/api/kernel/irq_manager.hpp b/api/kernel/irq_manager.hpp index 74dfc5d1ff..77b4911b6d 100644 --- a/api/kernel/irq_manager.hpp +++ b/api/kernel/irq_manager.hpp @@ -54,14 +54,14 @@ extern "C" { NOTES: * All IRQ-callbacks are in charge of calling End-Of-Interrupt - eoi. - Why? Because this makes it possible to prevent further interrupts until - a condition of your choice is met. And, interrupts are costly as they - always cause vm-exit. + Why? Because this makes it possible to prevent further interrupts until + a condition of your choice is met. And, interrupts are costly as they + always cause vm-exit. * IRQ-numbering: 0 or 32? @TODO: Remove all dependencies on old SanOS code. In particular, eoi is now in global scope -*/ + */ class IRQ_manager { public: using irq_delegate = delegate; @@ -90,7 +90,7 @@ class IRQ_manager { * Failure to do so will keep the interrupt from firing and cause a * stack overflow or similar badness. * } - */ + */ static void set_handler(uint8_t irq, void(*function_addr)()); /** Get handler from inside the IDT. */ @@ -100,7 +100,7 @@ class IRQ_manager { * Subscribe to an IRQ * @param irq: The IRQ to subscribe to - * @param del: A delegate to attach to the IRQ DPC-system + * @param del: A delegate to attach to the IRQ DPC-system * The delegate will be called a.s.a.p. after @param irq gets triggered * @@ -116,7 +116,7 @@ class IRQ_manager { * Get the current subscriber of an IRQ-line * * @param irq: The IRQ to get subscriber for - */ + */ static irq_delegate get_subscriber(uint8_t irq); /** @@ -169,9 +169,9 @@ class IRQ_manager { * Use "set_handler" for a simpler version using defaults */ static void create_gate(IDTDescr* idt_entry, - void (*function_addr)(), - uint16_t segment_sel, - char attributes); + void (*function_addr)(), + uint16_t segment_sel, + char attributes); /** The OS will call the following : */ friend class OS; diff --git a/api/kernel/os.hpp b/api/kernel/os.hpp index 58f4e3fdf0..7f64e49f4b 100644 --- a/api/kernel/os.hpp +++ b/api/kernel/os.hpp @@ -56,7 +56,7 @@ class OS { * Write a cstring to serial port. @todo Should be moved to Dev::serial(n). * * @param ptr: The string to write to serial port - */ + */ static size_t rsprint(const char* ptr); static size_t rsprint(const char* ptr, const size_t len); @@ -69,7 +69,7 @@ class OS { /** * Write to serial port with rswrite. - */ + */ static void default_rsprint(const char*, size_t); /** Start the OS. @todo Should be `init()` - and not accessible from ABI */ diff --git a/api/kernel/service.hpp b/api/kernel/service.hpp index e4c1c2e1fe..84f57f0e2f 100644 --- a/api/kernel/service.hpp +++ b/api/kernel/service.hpp @@ -26,7 +26,7 @@ extern "C" const char* service_name__; * This is where you take over * * The service gets started whenever the OS is done initializing - */ +*/ class Service { public: /** diff --git a/api/kernel/terminal.hpp b/api/kernel/terminal.hpp index 79257a620b..21180b13ce 100644 --- a/api/kernel/terminal.hpp +++ b/api/kernel/terminal.hpp @@ -50,16 +50,16 @@ class Terminal using Connection_ptr = std::shared_ptr; using Disk_ptr = std::shared_ptr; enum - { - NUL = 0, - BELL = 7, - BS = 8, - HTAB = 9, - LF = 10, - VTAB = 11, - FF = 12, - CR = 13 - }; + { + NUL = 0, + BELL = 7, + BS = 8, + HTAB = 9, + LF = 10, + VTAB = 11, + FF = 12, + CR = 13 + }; using on_write_func = std::function; diff --git a/api/net/arp.hpp b/api/net/arp.hpp index 76317161b6..b0c81c1c2b 100644 --- a/api/net/arp.hpp +++ b/api/net/arp.hpp @@ -27,127 +27,127 @@ namespace net { - class PacketArp; +class PacketArp; - /** ARP manager, including an ARP-Cache. */ - class Arp { - private: - /** ARP cache expires after cache_exp_t_ seconds */ - static constexpr uint16_t cache_exp_t_ {60 * 60 * 12}; - - /** Cache entries are just MAC's and timestamps */ - struct cache_entry { - Ethernet::addr mac_; - uint64_t timestamp_; +/** ARP manager, including an ARP-Cache. */ +class Arp { +private: + /** ARP cache expires after cache_exp_t_ seconds */ + static constexpr uint16_t cache_exp_t_ {60 * 60 * 12}; + + /** Cache entries are just MAC's and timestamps */ + struct cache_entry { + Ethernet::addr mac_; + uint64_t timestamp_; - /** Map needs empty constructor (we have no emplace yet) */ - cache_entry() noexcept = default; + /** Map needs empty constructor (we have no emplace yet) */ + cache_entry() noexcept = default; - cache_entry(Ethernet::addr mac) noexcept - : mac_(mac), timestamp_(OS::uptime()) {} + cache_entry(Ethernet::addr mac) noexcept + : mac_(mac), timestamp_(OS::uptime()) {} - cache_entry(const cache_entry& cpy) noexcept - : mac_(cpy.mac_), timestamp_(cpy.timestamp_) {} + cache_entry(const cache_entry& cpy) noexcept + : mac_(cpy.mac_), timestamp_(cpy.timestamp_) {} - void update() noexcept { timestamp_ = OS::uptime(); } - }; //< struct cache_entry - - using Cache = std::map; - using PacketQueue = std::map; - public: - /** - * You can assign your own ARP-resolution delegate - * - * We're doing this to keep the Hårek Haugerud mapping (HH_MAP) - */ - using Arp_resolver = delegate; - - enum Opcode { H_request = 0x100, H_reply = 0x200 }; - - /** Arp opcodes (Big-endian) */ - static constexpr uint16_t H_htype_eth {0x0100}; - static constexpr uint16_t H_ptype_ip4 {0x0008}; - static constexpr uint16_t H_hlen_plen {0x0406}; - - /** Constructor */ - explicit Arp(Inet&) noexcept; - - struct __attribute__((packed)) header { - Ethernet::header ethhdr; // Ethernet header - uint16_t htype; // Hardware type - uint16_t ptype; // Protocol type - uint16_t hlen_plen; // Protocol address length - uint16_t opcode; // Opcode - Ethernet::addr shwaddr; // Source mac - IP4::addr sipaddr; // Source ip - Ethernet::addr dhwaddr; // Target mac - IP4::addr dipaddr; // Target ip - }; - - /** Handle incoming ARP packet. */ - void bottom(Packet_ptr pckt); - - /** Roll your own arp-resolution system. */ - void set_resolver(Arp_resolver ar) - { arp_resolver_ = ar; } - - enum Resolver_name { DEFAULT, HH_MAP }; - - void set_resolver(Resolver_name nm) { - // @TODO: Add HÅREK-mapping here - switch (nm) { - case HH_MAP: - arp_resolver_ = Arp_resolver::from(*this); - break; - default: - arp_resolver_ = Arp_resolver::from(*this); - } - } - - /** Delegate link-layer output. */ - void set_linklayer_out(downstream link) - { linklayer_out_ = link; } - - /** Downstream transmission. */ - void transmit(Packet_ptr); - - private: - Inet& inet_; - - /** Needs to know which mac address to put in header->swhaddr */ - Ethernet::addr mac_; + void update() noexcept { timestamp_ = OS::uptime(); } + }; //< struct cache_entry + + using Cache = std::map; + using PacketQueue = std::map; +public: + /** + * You can assign your own ARP-resolution delegate + * + * We're doing this to keep the Hårek Haugerud mapping (HH_MAP) + */ + using Arp_resolver = delegate; + + enum Opcode { H_request = 0x100, H_reply = 0x200 }; + + /** Arp opcodes (Big-endian) */ + static constexpr uint16_t H_htype_eth {0x0100}; + static constexpr uint16_t H_ptype_ip4 {0x0008}; + static constexpr uint16_t H_hlen_plen {0x0406}; + + /** Constructor */ + explicit Arp(Inet&) noexcept; + + struct __attribute__((packed)) header { + Ethernet::header ethhdr; // Ethernet header + uint16_t htype; // Hardware type + uint16_t ptype; // Protocol type + uint16_t hlen_plen; // Protocol address length + uint16_t opcode; // Opcode + Ethernet::addr shwaddr; // Source mac + IP4::addr sipaddr; // Source ip + Ethernet::addr dhwaddr; // Target mac + IP4::addr dipaddr; // Target ip + }; + + /** Handle incoming ARP packet. */ + void bottom(Packet_ptr pckt); + + /** Roll your own arp-resolution system. */ + void set_resolver(Arp_resolver ar) + { arp_resolver_ = ar; } + + enum Resolver_name { DEFAULT, HH_MAP }; + + void set_resolver(Resolver_name nm) { + // @TODO: Add HÅREK-mapping here + switch (nm) { + case HH_MAP: + arp_resolver_ = Arp_resolver::from(*this); + break; + default: + arp_resolver_ = Arp_resolver::from(*this); + } + } + + /** Delegate link-layer output. */ + void set_linklayer_out(downstream link) + { linklayer_out_ = link; } + + /** Downstream transmission. */ + void transmit(Packet_ptr); + +private: + Inet& inet_; + + /** Needs to know which mac address to put in header->swhaddr */ + Ethernet::addr mac_; - /** Outbound data goes through here */ - downstream linklayer_out_; + /** Outbound data goes through here */ + downstream linklayer_out_; - /** The ARP cache */ - Cache cache_; + /** The ARP cache */ + Cache cache_; - /** Cache IP resolution. */ - void cache(IP4::addr, Ethernet::addr); + /** Cache IP resolution. */ + void cache(IP4::addr, Ethernet::addr); - /** Check if an IP is cached and not expired */ - bool is_valid_cached(IP4::addr); + /** Check if an IP is cached and not expired */ + bool is_valid_cached(IP4::addr); - /** ARP resolution. */ - Ethernet::addr resolve(IP4::addr); + /** ARP resolution. */ + Ethernet::addr resolve(IP4::addr); - void arp_respond(header* hdr_in); + void arp_respond(header* hdr_in); - // two different ARP resolvers - void arp_resolve(Packet_ptr); - void hh_map(Packet_ptr); + // two different ARP resolvers + void arp_resolve(Packet_ptr); + void hh_map(Packet_ptr); - Arp_resolver arp_resolver_ = Arp_resolver::from(*this); + Arp_resolver arp_resolver_ = Arp_resolver::from(*this); - PacketQueue waiting_packets_; + PacketQueue waiting_packets_; - /** Add a packet to waiting queue, to be sent when IP is resolved */ - void await_resolution(Packet_ptr, IP4::addr); + /** Add a packet to waiting queue, to be sent when IP is resolved */ + void await_resolution(Packet_ptr, IP4::addr); - /** Create a default initialized ARP-packet */ - Packet_ptr createPacket(); - }; //< class Arp + /** Create a default initialized ARP-packet */ + Packet_ptr createPacket(); +}; //< class Arp } //< namespace net diff --git a/api/net/buffer_store.hpp b/api/net/buffer_store.hpp index c215e5dcd6..f552f4b31b 100644 --- a/api/net/buffer_store.hpp +++ b/api/net/buffer_store.hpp @@ -25,80 +25,80 @@ namespace net{ - /** - * Network buffer storage for uniformly sized buffers. - * - * @note : The buffer store is intended to be used by Packet, which is - * a semi-intelligent buffer wrapper, used throughout the IP-stack. - * - * There shouldn't be any need for raw buffers in services. - **/ - class BufferStore { - public: - using buffer_t = uint8_t*; - using release_del = delegate; - - BufferStore(size_t num, size_t bufsize, size_t device_offset); - - /** Free all the buffers **/ - ~BufferStore(); - - /** Get a free buffer */ - buffer_t get_raw_buffer(); - - /** Get a free buffer, offset by device-offset */ - buffer_t get_offset_buffer(); - - /** Return a buffer. */ - void release_raw_buffer(buffer_t b, size_t); - - /** Return a buffer, offset by offset_ bytes from actual buffer. */ - void release_offset_buffer(buffer_t b, size_t); - - /** Get size of a raw buffer **/ - inline size_t raw_bufsize() - { return bufsize_; } - - inline size_t offset_bufsize() - { return bufsize_ - device_offset_; } - - /** @return the total buffer capacity in bytes */ - inline size_t capacity() - { return available_buffers_.size() * bufsize_; } - - /** Check if a buffer belongs here */ - inline bool address_is_from_pool(buffer_t addr) - { return addr >= pool_ and addr < pool_ + (bufcount_ * bufsize_); } - - /** Check if an address is the start of a buffer */ - inline bool address_is_bufstart(buffer_t addr) - { return (addr - pool_) % bufsize_ == 0; } - - /** Check if an address is the start of a buffer */ - inline bool address_is_offset_bufstart(buffer_t addr) - { return (addr - pool_ - device_offset_) % bufsize_ == 0; } - - inline size_t buffers_available() - { return available_buffers_.size(); } - - private: - size_t bufcount_; - const size_t bufsize_; - size_t device_offset_; - buffer_t pool_; - std::deque available_buffers_; - - /** Delete move and copy operations **/ - BufferStore(BufferStore&) = delete; - BufferStore(BufferStore&&) = delete; - BufferStore& operator=(BufferStore&) = delete; - BufferStore operator=(BufferStore&&) = delete; - - /** Prohibit default construction **/ - BufferStore() = delete; - - void increaseStorage(); - }; //< class BufferStore +/** + * Network buffer storage for uniformly sized buffers. + * + * @note : The buffer store is intended to be used by Packet, which is + * a semi-intelligent buffer wrapper, used throughout the IP-stack. + * + * There shouldn't be any need for raw buffers in services. + **/ +class BufferStore { +public: + using buffer_t = uint8_t*; + using release_del = delegate; + + BufferStore(size_t num, size_t bufsize, size_t device_offset); + + /** Free all the buffers **/ + ~BufferStore(); + + /** Get a free buffer */ + buffer_t get_raw_buffer(); + + /** Get a free buffer, offset by device-offset */ + buffer_t get_offset_buffer(); + + /** Return a buffer. */ + void release_raw_buffer(buffer_t b, size_t); + + /** Return a buffer, offset by offset_ bytes from actual buffer. */ + void release_offset_buffer(buffer_t b, size_t); + + /** Get size of a raw buffer **/ + inline size_t raw_bufsize() + { return bufsize_; } + + inline size_t offset_bufsize() + { return bufsize_ - device_offset_; } + + /** @return the total buffer capacity in bytes */ + inline size_t capacity() + { return available_buffers_.size() * bufsize_; } + + /** Check if a buffer belongs here */ + inline bool address_is_from_pool(buffer_t addr) + { return addr >= pool_ and addr < pool_ + (bufcount_ * bufsize_); } + + /** Check if an address is the start of a buffer */ + inline bool address_is_bufstart(buffer_t addr) + { return (addr - pool_) % bufsize_ == 0; } + + /** Check if an address is the start of a buffer */ + inline bool address_is_offset_bufstart(buffer_t addr) + { return (addr - pool_ - device_offset_) % bufsize_ == 0; } + + inline size_t buffers_available() + { return available_buffers_.size(); } + +private: + size_t bufcount_; + const size_t bufsize_; + size_t device_offset_; + buffer_t pool_; + std::deque available_buffers_; + + /** Delete move and copy operations **/ + BufferStore(BufferStore&) = delete; + BufferStore(BufferStore&&) = delete; + BufferStore& operator=(BufferStore&) = delete; + BufferStore operator=(BufferStore&&) = delete; + + /** Prohibit default construction **/ + BufferStore() = delete; + + void increaseStorage(); +}; //< class BufferStore } //< namespace net #endif //< NET_BUFFER_STORE_HPP diff --git a/api/net/dns/client.hpp b/api/net/dns/client.hpp index f8b76bdeb6..93b61d59c8 100644 --- a/api/net/dns/client.hpp +++ b/api/net/dns/client.hpp @@ -30,12 +30,12 @@ namespace net using Stack = Inet; DNSClient(Stack& stk) - : stack(stk) {} + : stack(stk) {} /** * @func a delegate that provides a hostname and its address, which is 0 if the * name @hostname was not found. Note: Test with INADDR_ANY for a 0-address. - **/ + **/ void resolve(IP4::addr dns_server, const std::string& hostname, Stack::resolve_func func); diff --git a/api/net/dns/dns.hpp b/api/net/dns/dns.hpp index f15bf3ea22..d54a11c02a 100644 --- a/api/net/dns/dns.hpp +++ b/api/net/dns/dns.hpp @@ -116,14 +116,14 @@ namespace net #pragma pack(pop) enum resp_code - { - NO_ERROR = 0, - FORMAT_ERROR = 1, - SERVER_FAIL = 2, - NAME_ERROR = 3, - NOT_IMPL = 4, // unimplemented feature - OP_REFUSED = 5, // for political reasons - }; + { + NO_ERROR = 0, + FORMAT_ERROR = 1, + SERVER_FAIL = 2, + NAME_ERROR = 3, + NOT_IMPL = 4, // unimplemented feature + OP_REFUSED = 5, // for political reasons + }; typedef std::function* (const std::string&)> lookup_func; @@ -132,18 +132,18 @@ namespace net static std::string question_string(unsigned short type) { switch (type) - { - case DNS_TYPE_A: - return "IPv4 address"; - case DNS_TYPE_ALIAS: - return "Alias"; - case DNS_TYPE_MX: - return "Mail exchange"; - case DNS_TYPE_NS: - return "Name server"; - default: - return "FIXME DNS::question_string(type = " + std::to_string(type) + ")"; - } + { + case DNS_TYPE_A: + return "IPv4 address"; + case DNS_TYPE_ALIAS: + return "Alias"; + case DNS_TYPE_MX: + return "Mail exchange"; + case DNS_TYPE_NS: + return "Name server"; + default: + return "FIXME DNS::question_string(type = " + std::to_string(type) + ")"; + } } class Request @@ -161,7 +161,7 @@ namespace net { IP4::addr result{{0}}; if (answers.size()) - result = answers[0].getIP4(); + result = answers[0].getIP4(); return result; } diff --git a/api/net/inet.hpp b/api/net/inet.hpp index 761d64614f..198b153d4d 100644 --- a/api/net/inet.hpp +++ b/api/net/inet.hpp @@ -22,54 +22,54 @@ namespace net { - class TCP; - class UDP; - class DHClient; +class TCP; +class UDP; +class DHClient; - /** An abstract IP-stack interface */ - template - class Inet { - public: - using Stack = Inet; +/** An abstract IP-stack interface */ +template +class Inet { +public: + using Stack = Inet; - template - using resolve_func = delegate; + template + using resolve_func = delegate; - virtual typename IPV::addr ip_addr() = 0; - virtual typename IPV::addr netmask() = 0; - virtual typename IPV::addr router() = 0; - virtual typename LINKLAYER::addr link_addr() = 0; + virtual typename IPV::addr ip_addr() = 0; + virtual typename IPV::addr netmask() = 0; + virtual typename IPV::addr router() = 0; + virtual typename LINKLAYER::addr link_addr() = 0; - virtual LINKLAYER& link() = 0; - virtual IPV& ip_obj() = 0; - virtual TCP& tcp() = 0; - virtual UDP& udp() = 0; + virtual LINKLAYER& link() = 0; + virtual IPV& ip_obj() = 0; + virtual TCP& tcp() = 0; + virtual UDP& udp() = 0; - virtual std::shared_ptr dhclient() = 0; + virtual std::shared_ptr dhclient() = 0; - virtual uint16_t MTU() const = 0; + virtual uint16_t MTU() const = 0; - virtual Packet_ptr createPacket(size_t size) = 0; + virtual Packet_ptr createPacket(size_t size) = 0; - virtual void resolve(const std::string& hostname, resolve_func func) = 0; + virtual void resolve(const std::string& hostname, resolve_func func) = 0; - virtual void set_dns_server(typename IPV::addr server) = 0; + virtual void set_dns_server(typename IPV::addr server) = 0; - virtual void network_config(typename IPV::addr ip, - typename IPV::addr nmask, - typename IPV::addr router, - typename IPV::addr dnssrv) = 0; + virtual void network_config(typename IPV::addr ip, + typename IPV::addr nmask, + typename IPV::addr router, + typename IPV::addr dnssrv) = 0; - /** Event triggered when there are available buffers in the transmit queue */ - virtual void on_transmit_queue_available(transmit_avail_delg del) = 0; + /** Event triggered when there are available buffers in the transmit queue */ + virtual void on_transmit_queue_available(transmit_avail_delg del) = 0; - /** Number of packets the transmit queue has room for */ - virtual size_t transmit_queue_available() = 0; + /** Number of packets the transmit queue has room for */ + virtual size_t transmit_queue_available() = 0; - /** Number of buffers available in the bufstore */ - virtual size_t buffers_available() = 0; + /** Number of buffers available in the bufstore */ + virtual size_t buffers_available() = 0; - }; //< class Inet +}; //< class Inet } //< namespace net #endif diff --git a/api/net/inet4.hpp b/api/net/inet4.hpp index 83ec392339..36f0a3db10 100644 --- a/api/net/inet4.hpp +++ b/api/net/inet4.hpp @@ -93,7 +93,7 @@ namespace net { /** * @func a delegate that provides a hostname and its address, which is 0 if the * name @hostname was not found. Note: Test with INADDR_ANY for a 0-address. - **/ + **/ inline virtual void resolve(const std::string& hostname, resolve_func func) override diff --git a/api/net/inet64.hpp b/api/net/inet64.hpp index dc323cc365..471f603762 100644 --- a/api/net/inet64.hpp +++ b/api/net/inet64.hpp @@ -62,7 +62,7 @@ namespace net { } /// send an UDPv6 packet, hopefully (please dont lie!) std::shared_ptr udp6_create( - Ethernet::addr ether_dest, const IP6::addr& ip_dest, UDPv6::port_t port) + Ethernet::addr ether_dest, const IP6::addr& ip_dest, UDPv6::port_t port) { return _udp6.create(ether_dest, ip_dest, port); } @@ -79,13 +79,13 @@ namespace net { } /** Bind an IP and a netmask to a given device. - The function expects the given device to exist.*/ + The function expects the given device to exist.*/ static void ifconfig( - netdev nic, - IP4::addr ip, - IP4::addr netmask, - IP6::addr ip6); + netdev nic, + IP4::addr ip, + IP4::addr netmask, + IP6::addr ip6); inline static IP4::addr ip4(netdev nic) { return _ip4_list[nic]; } @@ -125,7 +125,7 @@ namespace net { /** Don't think we *want* copy construction. @todo: Fix this with a singleton or something. - */ + */ Inet(Inet& UNUSED(cpy)) = delete; Inet(std::vector ips); diff --git a/api/net/ip4.hpp b/api/net/ip4.hpp index 4414c88836..85905ddadd 100644 --- a/api/net/ip4.hpp +++ b/api/net/ip4.hpp @@ -26,147 +26,147 @@ namespace net { - // Default delegate assignments - void ignore_ip4_up(Packet_ptr); - void ignore_ip4_down(Packet_ptr); +// Default delegate assignments +void ignore_ip4_up(Packet_ptr); +void ignore_ip4_down(Packet_ptr); - /** IP4 layer */ - class IP4 { - public: - /** Initialize. Sets a dummy linklayer out. */ - explicit IP4(Inet&) noexcept; +/** IP4 layer */ +class IP4 { +public: + /** Initialize. Sets a dummy linklayer out. */ + explicit IP4(Inet&) noexcept; - /** Known transport layer protocols. */ - enum proto { IP4_ICMP=1, IP4_UDP=17, IP4_TCP=6 }; + /** Known transport layer protocols. */ + enum proto { IP4_ICMP=1, IP4_UDP=17, IP4_TCP=6 }; - /** IP4 address representation */ - union __attribute__((packed)) addr { - uint8_t part[4]; - uint32_t whole; + /** IP4 address representation */ + union __attribute__((packed)) addr { + uint8_t part[4]; + uint32_t whole; - /** - * NOTE: Constructors - * Can't have them - removes the packed-attribute - */ + /** + * NOTE: Constructors + * Can't have them - removes the packed-attribute + */ - inline addr& operator=(addr cpy) noexcept { - whole = cpy.whole; - return *this; - } + inline addr& operator=(addr cpy) noexcept { + whole = cpy.whole; + return *this; + } - /** Standard comparison operators */ - inline bool operator==(addr rhs) const noexcept - { return whole == rhs.whole; } + /** Standard comparison operators */ + inline bool operator==(addr rhs) const noexcept + { return whole == rhs.whole; } - inline bool operator==(const uint32_t rhs) const noexcept - { return whole == rhs; } + inline bool operator==(const uint32_t rhs) const noexcept + { return whole == rhs; } - inline bool operator<(const addr rhs) const noexcept - { return whole < rhs.whole; } + inline bool operator<(const addr rhs) const noexcept + { return whole < rhs.whole; } - inline bool operator<(const uint32_t rhs) const noexcept - { return whole < rhs; } + inline bool operator<(const uint32_t rhs) const noexcept + { return whole < rhs; } - inline bool operator>(const addr rhs) const noexcept - { return whole > rhs.whole; } + inline bool operator>(const addr rhs) const noexcept + { return whole > rhs.whole; } - inline bool operator>(const uint32_t rhs) const noexcept - { return whole > rhs; } + inline bool operator>(const uint32_t rhs) const noexcept + { return whole > rhs; } - inline bool operator!=(const addr rhs) const noexcept - { return whole != rhs.whole; } + inline bool operator!=(const addr rhs) const noexcept + { return whole != rhs.whole; } - inline bool operator!=(const uint32_t rhs) const noexcept - { return whole != rhs; } + inline bool operator!=(const uint32_t rhs) const noexcept + { return whole != rhs; } - /** x.x.x.x string representation */ - std::string str() const { - char ip_addr[16]; - sprintf(ip_addr, "%1i.%1i.%1i.%1i", - part[0], part[1], part[2], part[3]); - return ip_addr; - } - }; //< union addr + /** x.x.x.x string representation */ + std::string str() const { + char ip_addr[16]; + sprintf(ip_addr, "%1i.%1i.%1i.%1i", + part[0], part[1], part[2], part[3]); + return ip_addr; + } + }; //< union addr - static const addr INADDR_ANY; - static const addr INADDR_BCAST; + static const addr INADDR_ANY; + static const addr INADDR_BCAST; - /** IP4 header representation */ - struct ip_header { - uint8_t version_ihl; - uint8_t tos; - uint16_t tot_len; - uint16_t id; - uint16_t frag_off_flags; - uint8_t ttl; - uint8_t protocol; - uint16_t check; - addr saddr; - addr daddr; - }; + /** IP4 header representation */ + struct ip_header { + uint8_t version_ihl; + uint8_t tos; + uint16_t tot_len; + uint16_t id; + uint16_t frag_off_flags; + uint8_t ttl; + uint8_t protocol; + uint16_t check; + addr saddr; + addr daddr; + }; - /** - * The full header including IP - * - * @Note: This might be removed if we decide to isolate layers more - */ - struct full_header { - uint8_t link_hdr[sizeof(typename LinkLayer::header)]; - ip_header ip_hdr; - }; + /** + * The full header including IP + * + * @Note: This might be removed if we decide to isolate layers more + */ + struct full_header { + uint8_t link_hdr[sizeof(typename LinkLayer::header)]; + ip_header ip_hdr; + }; - /** Upstream: Input from link layer */ - void bottom(Packet_ptr); + /** Upstream: Input from link layer */ + void bottom(Packet_ptr); - /** Upstream: Outputs to transport layer */ - inline void set_icmp_handler(upstream s) - { icmp_handler_ = s; } + /** Upstream: Outputs to transport layer */ + inline void set_icmp_handler(upstream s) + { icmp_handler_ = s; } - inline void set_udp_handler(upstream s) - { udp_handler_ = s; } + inline void set_udp_handler(upstream s) + { udp_handler_ = s; } - inline void set_tcp_handler(upstream s) - { tcp_handler_ = s; } + inline void set_tcp_handler(upstream s) + { tcp_handler_ = s; } - /** Downstream: Delegate linklayer out */ - void set_linklayer_out(downstream s) - { linklayer_out_ = s; }; + /** Downstream: Delegate linklayer out */ + void set_linklayer_out(downstream s) + { linklayer_out_ = s; }; - /** - * Downstream: Receive data from above and transmit - * - * @note: The following *must be set* in the packet: - * - * * Destination IP - * * Protocol - * - * Source IP *can* be set - if it's not, IP4 will set it - */ - void transmit(Packet_ptr); + /** + * Downstream: Receive data from above and transmit + * + * @note: The following *must be set* in the packet: + * + * * Destination IP + * * Protocol + * + * Source IP *can* be set - if it's not, IP4 will set it + */ + void transmit(Packet_ptr); - /** Compute the IP4 header checksum */ - uint16_t checksum(ip_header*); + /** Compute the IP4 header checksum */ + uint16_t checksum(ip_header*); - /** - * \brief - * - * Returns the IPv4 address associated with this interface - **/ - const addr local_ip() const { - return stack_.ip_addr(); - } + /** + * \brief + * + * Returns the IPv4 address associated with this interface + **/ + const addr local_ip() const { + return stack_.ip_addr(); + } - private: - Inet& stack_; +private: + Inet& stack_; - /** Downstream: Linklayer output delegate */ - downstream linklayer_out_ {ignore_ip4_down}; + /** Downstream: Linklayer output delegate */ + downstream linklayer_out_ {ignore_ip4_down}; - /** Upstream delegates */ - upstream icmp_handler_ {ignore_ip4_up}; - upstream udp_handler_ {ignore_ip4_up}; - upstream tcp_handler_ {ignore_ip4_up}; - }; //< class IP4 + /** Upstream delegates */ + upstream icmp_handler_ {ignore_ip4_up}; + upstream udp_handler_ {ignore_ip4_up}; + upstream tcp_handler_ {ignore_ip4_up}; +}; //< class IP4 } //< namespace net #endif diff --git a/api/net/ip4/icmpv4.hpp b/api/net/ip4/icmpv4.hpp index 084f2b0860..d0787fd783 100644 --- a/api/net/ip4/icmpv4.hpp +++ b/api/net/ip4/icmpv4.hpp @@ -23,44 +23,44 @@ namespace net { - void icmp_default_out(Packet_ptr); +void icmp_default_out(Packet_ptr); - class ICMPv4 { - public: - // Initialize - ICMPv4(Inet&); +class ICMPv4 { +public: + // Initialize + ICMPv4(Inet&); - // Known ICMP types - enum icmp_types { ICMP_ECHO_REPLY, ICMP_ECHO = 8 }; + // Known ICMP types + enum icmp_types { ICMP_ECHO_REPLY, ICMP_ECHO = 8 }; - struct icmp_header { - uint8_t type; - uint8_t code; - uint16_t checksum; - uint16_t identifier; - uint16_t sequence; - uint8_t payload[0]; - }__attribute__((packed)); + struct icmp_header { + uint8_t type; + uint8_t code; + uint16_t checksum; + uint16_t identifier; + uint16_t sequence; + uint8_t payload[0]; + }__attribute__((packed)); - struct full_header { - LinkLayer::header link_hdr; - IP4::ip_header ip_hdr; - icmp_header icmp_hdr; - }__attribute__((packed)); + struct full_header { + LinkLayer::header link_hdr; + IP4::ip_header ip_hdr; + icmp_header icmp_hdr; + }__attribute__((packed)); - // Input from network layer - void bottom(Packet_ptr); + // Input from network layer + void bottom(Packet_ptr); - // Delegate output to network layer - inline void set_network_out(downstream s) - { network_layer_out_ = s; }; + // Delegate output to network layer + inline void set_network_out(downstream s) + { network_layer_out_ = s; }; - private: - Inet& inet_; - downstream network_layer_out_ {icmp_default_out}; +private: + Inet& inet_; + downstream network_layer_out_ {icmp_default_out}; - void ping_reply(full_header* full_hdr, uint16_t size); - }; //< class ICMPv4 + void ping_reply(full_header* full_hdr, uint16_t size); +}; //< class ICMPv4 } //< namespace net #endif //< NET_IP4_ICMPv4_HPP diff --git a/api/net/ip4/packet_ip4.hpp b/api/net/ip4/packet_ip4.hpp index 918ec77f1d..7076fce840 100644 --- a/api/net/ip4/packet_ip4.hpp +++ b/api/net/ip4/packet_ip4.hpp @@ -25,70 +25,70 @@ namespace net { - class PacketIP4 : public Packet, // might work as upcast: - public std::enable_shared_from_this - { - public: - static constexpr size_t DEFAULT_TTL {64}; +class PacketIP4 : public Packet, // might work as upcast: + public std::enable_shared_from_this +{ +public: + static constexpr size_t DEFAULT_TTL {64}; - const IP4::addr& src() const noexcept - { return ip4_header().saddr; } + const IP4::addr& src() const noexcept + { return ip4_header().saddr; } - void set_src(const IP4::addr& addr) noexcept - { ip4_header().saddr = addr; } + void set_src(const IP4::addr& addr) noexcept + { ip4_header().saddr = addr; } - const IP4::addr& dst() const noexcept - { return ip4_header().daddr; } + const IP4::addr& dst() const noexcept + { return ip4_header().daddr; } - void set_dst(const IP4::addr& addr) noexcept - { ip4_header().daddr = addr; } + void set_dst(const IP4::addr& addr) noexcept + { ip4_header().daddr = addr; } - void set_protocol(IP4::proto p) noexcept - { ip4_header().protocol = p; } + void set_protocol(IP4::proto p) noexcept + { ip4_header().protocol = p; } - uint8_t protocol() const noexcept - { return ip4_header().protocol; } + uint8_t protocol() const noexcept + { return ip4_header().protocol; } - uint16_t ip4_segment_size() const noexcept - { return ntohs(ip4_header().tot_len); } + uint16_t ip4_segment_size() const noexcept + { return ntohs(ip4_header().tot_len); } - /** Last modifications before transmission */ - void make_flight_ready() noexcept { - assert( ip4_header().protocol ); - set_segment_length(); - set_ip4_checksum(); - } + /** Last modifications before transmission */ + void make_flight_ready() noexcept { + assert( ip4_header().protocol ); + set_segment_length(); + set_ip4_checksum(); + } - void init() noexcept { - ip4_header().version_ihl = 0x45; - ip4_header().tos = 0; - ip4_header().id = 0; - ip4_header().frag_off_flags = 0; - ip4_header().ttl = DEFAULT_TTL; - } + void init() noexcept { + ip4_header().version_ihl = 0x45; + ip4_header().tos = 0; + ip4_header().id = 0; + ip4_header().frag_off_flags = 0; + ip4_header().ttl = DEFAULT_TTL; + } - private: - const IP4::ip_header& ip4_header() const noexcept - { return (reinterpret_cast(buffer()))->ip_hdr; } +private: + const IP4::ip_header& ip4_header() const noexcept + { return (reinterpret_cast(buffer()))->ip_hdr; } - IP4::ip_header& ip4_header() noexcept - { return (reinterpret_cast(buffer()))->ip_hdr; } + IP4::ip_header& ip4_header() noexcept + { return (reinterpret_cast(buffer()))->ip_hdr; } - /** - * Set IP4 header length - * - * Inferred from packet size and linklayer header size - */ - void set_segment_length() noexcept - { ip4_header().tot_len = htons(size() - sizeof(LinkLayer::header)); } + /** + * Set IP4 header length + * + * Inferred from packet size and linklayer header size + */ + void set_segment_length() noexcept + { ip4_header().tot_len = htons(size() - sizeof(LinkLayer::header)); } - void set_ip4_checksum() noexcept { - auto& hdr = ip4_header(); - hdr.check = 0; - hdr.check = net::checksum(&hdr, sizeof(IP4::ip_header)); - } + void set_ip4_checksum() noexcept { + auto& hdr = ip4_header(); + hdr.check = 0; + hdr.check = net::checksum(&hdr, sizeof(IP4::ip_header)); + } - }; //< class PacketIP4 +}; //< class PacketIP4 } //< namespace net #endif //< IP4_PACKET_IP4_HPP diff --git a/api/net/ip4/udp.hpp b/api/net/ip4/udp.hpp index 21c6245d6a..be016c3b87 100644 --- a/api/net/ip4/udp.hpp +++ b/api/net/ip4/udp.hpp @@ -25,77 +25,77 @@ namespace net { - class PacketUDP; +class PacketUDP; - template - class Socket; +template +class Socket; - void ignore_udp(Packet_ptr); +void ignore_udp(Packet_ptr); - /** Basic UDP support. @todo Implement UDP sockets. */ - class UDP { - public: - using addr_t = IP4::addr; +/** Basic UDP support. @todo Implement UDP sockets. */ +class UDP { +public: + using addr_t = IP4::addr; - /** UDP port number */ - using port_t = uint16_t; + /** UDP port number */ + using port_t = uint16_t; - using Socket = Socket; - using Stack = Inet; + using Socket = Socket; + using Stack = Inet; - /** UDP header */ - struct udp_header { - port_t sport; - port_t dport; - uint16_t length; - uint16_t checksum; - }; + /** UDP header */ + struct udp_header { + port_t sport; + port_t dport; + uint16_t length; + uint16_t checksum; + }; - /** Full UDP Header with all sub-headers */ - struct full_header { - IP4::full_header full_hdr; - udp_header udp_hdr; - }__attribute__((packed)); + /** Full UDP Header with all sub-headers */ + struct full_header { + IP4::full_header full_hdr; + udp_header udp_hdr; + }__attribute__((packed)); - //////////////////////////////////////////// + //////////////////////////////////////////// - inline addr_t local_ip() const - { return stack_.ip_addr(); } + inline addr_t local_ip() const + { return stack_.ip_addr(); } - /** Input from network layer */ - void bottom(Packet_ptr); + /** Input from network layer */ + void bottom(Packet_ptr); - /** Delegate output to network layer */ - inline void set_network_out(downstream del) - { network_layer_out_ = del; } + /** Delegate output to network layer */ + inline void set_network_out(downstream del) + { network_layer_out_ = del; } - /** Send UDP datagram from source ip/port to destination ip/port. + /** Send UDP datagram from source ip/port to destination ip/port. - @param sip Local IP-address - @param sport Local port - @param dip Remote IP-address - @param dport Remote port */ - void transmit(std::shared_ptr udp); + @param sip Local IP-address + @param sport Local port + @param dip Remote IP-address + @param dport Remote port */ + void transmit(std::shared_ptr udp); - //! @param port local port - Socket& bind(port_t port); + //! @param port local port + Socket& bind(port_t port); - //! returns a new UDP socket bound to a random port - Socket& bind(); + //! returns a new UDP socket bound to a random port + Socket& bind(); - //! construct this UDP module with @inet - UDP(Stack& inet) : - network_layer_out_ {ignore_udp}, - stack_ {inet} - { } - private: - downstream network_layer_out_; - Stack& stack_; - std::map ports_; - port_t current_port_ {1024}; + //! construct this UDP module with @inet + UDP(Stack& inet) : + network_layer_out_ {ignore_udp}, + stack_ {inet} + { } +private: + downstream network_layer_out_; + Stack& stack_; + std::map ports_; + port_t current_port_ {1024}; - friend class SocketUDP; - }; //< class UDP + friend class SocketUDP; +}; //< class UDP } //< namespace net #include "packet_udp.hpp" diff --git a/api/net/ip6/icmp6.hpp b/api/net/ip6/icmp6.hpp index b26d28e5c5..eb4d48d0e4 100644 --- a/api/net/ip6/icmp6.hpp +++ b/api/net/ip6/icmp6.hpp @@ -144,6 +144,6 @@ namespace net size_ = sizeof(IP6::full_header) + icmp_len; } - }; + }; } diff --git a/api/net/ip6/ip6.hpp b/api/net/ip6/ip6.hpp index 1378c2021d..31db6d09f0 100644 --- a/api/net/ip6/ip6.hpp +++ b/api/net/ip6/ip6.hpp @@ -43,17 +43,17 @@ namespace net public: /** Known transport layer protocols. */ enum proto - { - PROTO_HOPOPT = 0, // IPv6 hop-by-hop + { + PROTO_HOPOPT = 0, // IPv6 hop-by-hop - PROTO_ICMPv4 = 1, - PROTO_TCP = 6, - PROTO_UDP = 17, + PROTO_ICMPv4 = 1, + PROTO_TCP = 6, + PROTO_UDP = 17, - PROTO_ICMPv6 = 58, // IPv6 ICMP - PROTO_NoNext = 59, // no next-header - PROTO_OPTSv6 = 60, // dest options - }; + PROTO_ICMPv6 = 58, // IPv6 ICMP + PROTO_NoNext = 59, // no next-header + PROTO_OPTSv6 = 60, // dest options + }; struct addr { @@ -64,11 +64,11 @@ namespace net uint16_t c1, uint16_t c2, uint16_t d1, uint16_t d2) { i128 = _mm_set_epi16( - //d2, d1, c2, c1, b2, b1, a2, a1); - htons(d2), htons(d1), - htons(c2), htons(c1), - htons(b2), htons(b1), - htons(a2), htons(a1)); + //d2, d1, c2, c1, b2, b1, a2, a1); + htons(d2), htons(d1), + htons(c2), htons(c1), + htons(b2), htons(b1), + htons(a2), htons(a1)); } addr(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { @@ -121,15 +121,15 @@ namespace net bool is_multicast() const { /** - RFC 4291 2.7 Multicast Addresses + RFC 4291 2.7 Multicast Addresses - An IPv6 multicast address is an identifier for a group of interfaces - (typically on different nodes). An interface may belong to any - number of multicast groups. Multicast addresses have the following format: - | 8 | 4 | 4 | 112 bits | - +------ -+----+----+---------------------------------------------+ - |11111111|flgs|scop| group ID | - +--------+----+----+---------------------------------------------+ + An IPv6 multicast address is an identifier for a group of interfaces + (typically on different nodes). An interface may belong to any + number of multicast groups. Multicast addresses have the following format: + | 8 | 4 | 4 | 112 bits | + +------ -+----+----+---------------------------------------------+ + |11111111|flgs|scop| group ID | + +--------+----+----+---------------------------------------------+ **/ return i8[0] == 0xFF; } @@ -142,7 +142,7 @@ namespace net }; } __attribute__((aligned(alignof(__m128i)))); -#pragma pack(push, 1) + #pragma pack(push, 1) class header { public: @@ -153,7 +153,7 @@ namespace net uint8_t tclass() const { return ((scanline[0] & 0xF000) >> 12) + - (scanline[0] & 0xF); + (scanline[0] & 0xF); } // initializes the first scanline with the IPv6 version void init_scan0() @@ -164,7 +164,7 @@ namespace net uint16_t size() const { return ((scanline[1] & 0x00FF) << 8) + - ((scanline[1] & 0xFF00) >> 8); + ((scanline[1] & 0xFF00) >> 8); } void set_size(uint16_t newsize) { @@ -218,7 +218,7 @@ namespace net return hdr_ext_len; } }; -#pragma pack(pop) + #pragma pack(pop) struct full_header { @@ -243,25 +243,25 @@ namespace net static std::string protocol_name(uint8_t protocol) { switch (protocol) - { - case PROTO_HOPOPT: - return "IPv6 Hop-By-Hop (0)"; + { + case PROTO_HOPOPT: + return "IPv6 Hop-By-Hop (0)"; - case PROTO_TCP: - return "TCPv6 (6)"; - case PROTO_UDP: - return "UDPv6 (17)"; + case PROTO_TCP: + return "TCPv6 (6)"; + case PROTO_UDP: + return "UDPv6 (17)"; - case PROTO_ICMPv6: - return "ICMPv6 (58)"; - case PROTO_NoNext: - return "No next header (59)"; - case PROTO_OPTSv6: - return "IPv6 destination options (60)"; + case PROTO_ICMPv6: + return "ICMPv6 (58)"; + case PROTO_NoNext: + return "No next header (59)"; + case PROTO_OPTSv6: + return "IPv6 destination options (60)"; - default: - return "Unknown: " + std::to_string(protocol); - } + default: + return "Unknown: " + std::to_string(protocol); + } } // handler for upstream IPv6 packets @@ -283,7 +283,7 @@ namespace net // creates a new IPv6 packet to be sent over the ether static std::shared_ptr create(uint8_t proto, - Ethernet::addr ether_dest, const IP6::addr& dest); + Ethernet::addr ether_dest, const IP6::addr& dest); private: addr local; diff --git a/api/net/ip6/udp6.hpp b/api/net/ip6/udp6.hpp index 30ca33a5f8..66ac4ec510 100644 --- a/api/net/ip6/udp6.hpp +++ b/api/net/ip6/udp6.hpp @@ -72,7 +72,7 @@ namespace net // creates a new packet to be sent over the ether std::shared_ptr create( - Ethernet::addr ether_dest, const IP6::addr& dest, port_t port); + Ethernet::addr ether_dest, const IP6::addr& dest, port_t port); private: std::map listeners; @@ -125,7 +125,7 @@ namespace net header().length = htons(sizeof(UDPv6::header) + newlen); // new total IPv6 payload length ip6_header().set_size( - sizeof(IP6::header) + sizeof(UDPv6::header) + newlen); + sizeof(IP6::header) + sizeof(UDPv6::header) + newlen); // new total packet length size_ = sizeof(IP6::full_header) + sizeof(UDPv6::header) + newlen; } diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index a29dbed345..de585587be 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -29,1206 +29,1206 @@ #include // enable_shared_from_this inline unsigned round_up(unsigned n, unsigned div) { - assert(n); - return (n + div - 1) / div; + assert(n); + return (n + div - 1) / div; } namespace net { - class TCP { - public: - using Address = IP4::addr; - using Port = uint16_t; - /* - A Sequence number (SYN/ACK) (32 bits) - */ - using Seq = uint32_t; +class TCP { +public: + using Address = IP4::addr; + using Port = uint16_t; + /* + A Sequence number (SYN/ACK) (32 bits) + */ + using Seq = uint32_t; - class Packet; - using Packet_ptr = std::shared_ptr; + class Packet; + using Packet_ptr = std::shared_ptr; - class TCPException; - class TCPBadOptionException; + class TCPException; + class TCPBadOptionException; - class Connection; - using Connection_ptr = std::shared_ptr; - using IPStack = Inet; + class Connection; + using Connection_ptr = std::shared_ptr; + using IPStack = Inet; - public: - /* - An IP address and a Port. - */ - class Socket { - public: - /* - Intialize an empty socket. - */ - inline Socket() : address_(), port_(0) { address_.whole = 0; }; - - /* - Create a socket with a Address and Port. - */ - inline Socket(Address address, Port port) : address_(address), port_(port) {}; - - /* - Returns the Socket's address. - */ - inline const TCP::Address address() const { return address_; } - - /* - Returns the Socket's port. - */ - inline TCP::Port port() const { return port_; } - - /* - Returns a string in the format "Address:Port". - */ - std::string to_string() const { - std::stringstream ss; - ss << address_.str() << ":" << port_; - return ss.str(); - } - - inline bool is_empty() const { return (address_.whole == 0 and port_ == 0); } - - /* - Comparator used for vector. - */ - inline bool operator ==(const Socket &s2) const { - return address().whole == s2.address().whole - and port() == s2.port(); - } - - /* - Comparator used for map. - */ - inline bool operator <(const Socket& s2) const { - return address().whole < s2.address().whole - or (address().whole == s2.address().whole and port() < s2.port()); - } - - private: - //SocketID id_; // Maybe a hash or something. Not sure if needed (yet) - TCP::Address address_; - TCP::Port port_; - - }; // << class TCP::Socket - - - /////// TCP Stuff - Relevant to the protocol ///// +public: + /* + An IP address and a Port. + */ + class Socket { + public: + /* + Intialize an empty socket. + */ + inline Socket() : address_(), port_(0) { address_.whole = 0; }; + + /* + Create a socket with a Address and Port. + */ + inline Socket(Address address, Port port) : address_(address), port_(port) {}; + + /* + Returns the Socket's address. + */ + inline const TCP::Address address() const { return address_; } + + /* + Returns the Socket's port. + */ + inline TCP::Port port() const { return port_; } + + /* + Returns a string in the format "Address:Port". + */ + std::string to_string() const { + std::stringstream ss; + ss << address_.str() << ":" << port_; + return ss.str(); + } + + inline bool is_empty() const { return (address_.whole == 0 and port_ == 0); } + + /* + Comparator used for vector. + */ + inline bool operator ==(const Socket &s2) const { + return address().whole == s2.address().whole + and port() == s2.port(); + } + + /* + Comparator used for map. + */ + inline bool operator <(const Socket& s2) const { + return address().whole < s2.address().whole + or (address().whole == s2.address().whole and port() < s2.port()); + } + + private: + //SocketID id_; // Maybe a hash or something. Not sure if needed (yet) + TCP::Address address_; + TCP::Port port_; + + }; // << class TCP::Socket + + + /////// TCP Stuff - Relevant to the protocol ///// - static constexpr uint16_t default_window_size = 0xffff; + static constexpr uint16_t default_window_size = 0xffff; - static constexpr uint16_t default_mss = 536; + static constexpr uint16_t default_mss = 536; - /* - Flags (Control bits) in the TCP Header. - */ - enum Flag { - NS = (1 << 8), // Nounce (Experimental: see RFC 3540) - CWR = (1 << 7), // Congestion Window Reduced - ECE = (1 << 6), // ECN-Echo - URG = (1 << 5), // Urgent - ACK = (1 << 4), // Acknowledgement - PSH = (1 << 3), // Push - RST = (1 << 2), // Reset - SYN = (1 << 1), // Syn(chronize) - FIN = 1, // Fin(ish) + /* + Flags (Control bits) in the TCP Header. + */ + enum Flag { + NS = (1 << 8), // Nounce (Experimental: see RFC 3540) + CWR = (1 << 7), // Congestion Window Reduced + ECE = (1 << 6), // ECN-Echo + URG = (1 << 5), // Urgent + ACK = (1 << 4), // Acknowledgement + PSH = (1 << 3), // Push + RST = (1 << 2), // Reset + SYN = (1 << 1), // Syn(chronize) + FIN = 1, // Fin(ish) }; /* - Representation of the TCP Header. - - RFC 793, (p.15): - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Source Port | Destination Port | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Sequence Number | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Acknowledgment Number | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Data | |U|A|P|R|S|F| | - | Offset| Reserved |R|C|S|S|Y|I| Window | - | | |G|K|H|T|N|N| | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Checksum | Urgent Pointer | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Options | Padding | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | data | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - struct Header { - TCP::Port source_port; // Source port - TCP::Port destination_port; // Destination port - uint32_t seq_nr; // Sequence number - uint32_t ack_nr; // Acknowledge number - union { - uint16_t whole; // Reference to offset_reserved & flags together. - struct { - uint8_t offset_reserved; // Offset (4 bits) + Reserved (3 bits) + NS (1 bit) - uint8_t flags; // All Flags (Control bits) except NS (9 bits - 1 bit) - }; - } offset_flags; // Data offset + Reserved + Flags (16 bits) - uint16_t window_size; // Window size - uint16_t checksum; // Checksum - uint16_t urgent; // Urgent pointer offset - uint8_t options[0]; // Options - }__attribute__((packed)); // << struct TCP::Header - - - /* - TCP Pseudo header, for checksum calculation + Representation of the TCP Header. + + RFC 793, (p.15): + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Source Port | Destination Port | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Sequence Number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Acknowledgment Number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Data | |U|A|P|R|S|F| | + | Offset| Reserved |R|C|S|S|Y|I| Window | + | | |G|K|H|T|N|N| | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Checksum | Urgent Pointer | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Options | Padding | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | data | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ - struct Pseudo_header { - IP4::addr saddr; - IP4::addr daddr; - uint8_t zero; - uint8_t proto; - uint16_t tcp_length; - }__attribute__((packed)); + struct Header { + TCP::Port source_port; // Source port + TCP::Port destination_port; // Destination port + uint32_t seq_nr; // Sequence number + uint32_t ack_nr; // Acknowledge number + union { + uint16_t whole; // Reference to offset_reserved & flags together. + struct { + uint8_t offset_reserved; // Offset (4 bits) + Reserved (3 bits) + NS (1 bit) + uint8_t flags; // All Flags (Control bits) except NS (9 bits - 1 bit) + }; + } offset_flags; // Data offset + Reserved + Flags (16 bits) + uint16_t window_size; // Window size + uint16_t checksum; // Checksum + uint16_t urgent; // Urgent pointer offset + uint8_t options[0]; // Options + }__attribute__((packed)); // << struct TCP::Header + + + /* + TCP Pseudo header, for checksum calculation + */ + struct Pseudo_header { + IP4::addr saddr; + IP4::addr daddr; + uint8_t zero; + uint8_t proto; + uint16_t tcp_length; + }__attribute__((packed)); - /* - TCP Checksum-header (TCP-header + pseudo-header) - */ - struct Checksum_header { - TCP::Pseudo_header pseudo; - TCP::Header tcp; - }__attribute__((packed)); + /* + TCP Checksum-header (TCP-header + pseudo-header) + */ + struct Checksum_header { + TCP::Pseudo_header pseudo; + TCP::Header tcp; + }__attribute__((packed)); - /* - To extract the TCP part from a Packet_ptr and calculate size. (?) - */ - struct Full_header { - Ethernet::header ethernet; - IP4::ip_header ip4; - TCP::Header tcp; - }__attribute__((packed)); + /* + To extract the TCP part from a Packet_ptr and calculate size. (?) + */ + struct Full_header { + Ethernet::header ethernet; + IP4::ip_header ip4; + TCP::Header tcp; + }__attribute__((packed)); - /* - TCP Header Option - */ - struct Option { - uint8_t kind; - uint8_t length; - uint8_t data[0]; - - enum Kind { - END = 0x00, // End of option list - NOP = 0x01, // No-Opeartion - MSS = 0x02, // Maximum Segment Size [RFC 793] Rev: [879, 6691] - }; - - static std::string kind_string(Kind kind) { - switch(kind) { - case MSS: - return {"MSS"}; - - default: - return {"Unknown Option"}; - } - } - - struct opt_mss { - uint8_t kind; - uint8_t length; - uint16_t mss; - - opt_mss(uint16_t mss) - : kind(MSS), length(4), mss(htons(mss)) {} - }; - - struct opt_timestamp { - uint8_t kind; - uint8_t length; - uint32_t ts_val; - uint32_t ts_ecr; - }; - }; + /* + TCP Header Option + */ + struct Option { + uint8_t kind; + uint8_t length; + uint8_t data[0]; + + enum Kind { + END = 0x00, // End of option list + NOP = 0x01, // No-Opeartion + MSS = 0x02, // Maximum Segment Size [RFC 793] Rev: [879, 6691] + }; + + static std::string kind_string(Kind kind) { + switch(kind) { + case MSS: + return {"MSS"}; + + default: + return {"Unknown Option"}; + } + } + + struct opt_mss { + uint8_t kind; + uint8_t length; + uint16_t mss; + + opt_mss(uint16_t mss) + : kind(MSS), length(4), mss(htons(mss)) {} + }; + + struct opt_timestamp { + uint8_t kind; + uint8_t length; + uint32_t ts_val; + uint32_t ts_ecr; + }; + }; - /* - A Wrapper for a TCP Packet. Is everything as a IP4 Packet, - in addition to the TCP Header and functions to modify this and the control bits (FLAGS). - */ - class Packet : public PacketIP4 { - public: + /* + A Wrapper for a TCP Packet. Is everything as a IP4 Packet, + in addition to the TCP Header and functions to modify this and the control bits (FLAGS). + */ + class Packet : public PacketIP4 { + public: - inline TCP::Header& header() const - { - return ((TCP::Full_header*) buffer())->tcp; - } + inline TCP::Header& header() const + { + return ((TCP::Full_header*) buffer())->tcp; + } - static const size_t HEADERS_SIZE = sizeof(TCP::Full_header); + static const size_t HEADERS_SIZE = sizeof(TCP::Full_header); - //! initializes to a default, empty TCP packet, given - //! a valid MTU-sized buffer - void init() - { - // Erase all headers (smart? necessary? ...well, convenient) - memset(buffer(), 0, HEADERS_SIZE); - PacketIP4::init(); + //! initializes to a default, empty TCP packet, given + //! a valid MTU-sized buffer + void init() + { + // Erase all headers (smart? necessary? ...well, convenient) + memset(buffer(), 0, HEADERS_SIZE); + PacketIP4::init(); - set_protocol(IP4::IP4_TCP); - set_win_size(TCP::default_window_size); - set_offset(5); + set_protocol(IP4::IP4_TCP); + set_win_size(TCP::default_window_size); + set_offset(5); - // set TCP payload location (!?) - set_payload(buffer() + all_headers_len()); - } + // set TCP payload location (!?) + set_payload(buffer() + all_headers_len()); + } - // GETTERS - inline TCP::Port src_port() const { return ntohs(header().source_port); } + // GETTERS + inline TCP::Port src_port() const { return ntohs(header().source_port); } - inline TCP::Port dst_port() const { return ntohs(header().destination_port); } + inline TCP::Port dst_port() const { return ntohs(header().destination_port); } - inline TCP::Seq seq() const { return ntohl(header().seq_nr); } + inline TCP::Seq seq() const { return ntohl(header().seq_nr); } - inline TCP::Seq ack() const { return ntohl(header().ack_nr); } + inline TCP::Seq ack() const { return ntohl(header().ack_nr); } - inline uint16_t win() const { return ntohs(header().window_size); } + inline uint16_t win() const { return ntohs(header().window_size); } - inline TCP::Socket source() const { return TCP::Socket{src(), src_port()}; } + inline TCP::Socket source() const { return TCP::Socket{src(), src_port()}; } - inline TCP::Socket destination() const { return TCP::Socket{dst(), dst_port()}; } + inline TCP::Socket destination() const { return TCP::Socket{dst(), dst_port()}; } - // SETTERS - inline TCP::Packet& set_src_port(TCP::Port p) { - header().source_port = htons(p); - return *this; - } + // SETTERS + inline TCP::Packet& set_src_port(TCP::Port p) { + header().source_port = htons(p); + return *this; + } - inline TCP::Packet& set_dst_port(TCP::Port p) { - header().destination_port = htons(p); - return *this; - } + inline TCP::Packet& set_dst_port(TCP::Port p) { + header().destination_port = htons(p); + return *this; + } - inline TCP::Packet& set_seq(TCP::Seq n) { - header().seq_nr = htonl(n); - return *this; - } + inline TCP::Packet& set_seq(TCP::Seq n) { + header().seq_nr = htonl(n); + return *this; + } - inline TCP::Packet& set_ack(TCP::Seq n) { - header().ack_nr = htonl(n); - return *this; - } + inline TCP::Packet& set_ack(TCP::Seq n) { + header().ack_nr = htonl(n); + return *this; + } - inline TCP::Packet& set_win_size(uint16_t size) { - header().window_size = htons(size); - return *this; - } + inline TCP::Packet& set_win_size(uint16_t size) { + header().window_size = htons(size); + return *this; + } - inline TCP::Packet& set_checksum(uint16_t checksum) { - header().checksum = checksum; - return *this; - } + inline TCP::Packet& set_checksum(uint16_t checksum) { + header().checksum = checksum; + return *this; + } - inline TCP::Packet& set_source(const TCP::Socket& src) { - set_src(src.address()); // PacketIP4::set_src - set_src_port(src.port()); - return *this; - } + inline TCP::Packet& set_source(const TCP::Socket& src) { + set_src(src.address()); // PacketIP4::set_src + set_src_port(src.port()); + return *this; + } - inline TCP::Packet& set_destination(const TCP::Socket& dest) { - set_dst(dest.address()); // PacketIP4::set_dst - set_dst_port(dest.port()); - return *this; - } + inline TCP::Packet& set_destination(const TCP::Socket& dest) { + set_dst(dest.address()); // PacketIP4::set_dst + set_dst_port(dest.port()); + return *this; + } - /// FLAGS / CONTROL BITS /// + /// FLAGS / CONTROL BITS /// - inline TCP::Packet& set_flag(TCP::Flag f) { - header().offset_flags.whole |= htons(f); - return *this; - } + inline TCP::Packet& set_flag(TCP::Flag f) { + header().offset_flags.whole |= htons(f); + return *this; + } - inline TCP::Packet& set_flags(uint16_t f) { - header().offset_flags.whole |= htons(f); - return *this; - } + inline TCP::Packet& set_flags(uint16_t f) { + header().offset_flags.whole |= htons(f); + return *this; + } - inline TCP::Packet& clear_flag(TCP::Flag f) { - header().offset_flags.whole &= ~ htons(f); - return *this; - } + inline TCP::Packet& clear_flag(TCP::Flag f) { + header().offset_flags.whole &= ~ htons(f); + return *this; + } - inline TCP::Packet& clear_flags() { - header().offset_flags.whole &= 0x00ff; - return *this; - } + inline TCP::Packet& clear_flags() { + header().offset_flags.whole &= 0x00ff; + return *this; + } - inline bool isset(TCP::Flag f) { return ntohs(header().offset_flags.whole) & f; } + inline bool isset(TCP::Flag f) { return ntohs(header().offset_flags.whole) & f; } - /// OFFSET, OPTIONS, DATA /// + /// OFFSET, OPTIONS, DATA /// - // Get the raw tcp offset, in quadruples - inline uint8_t offset() const { return (uint8_t)(header().offset_flags.offset_reserved >> 4); } + // Get the raw tcp offset, in quadruples + inline uint8_t offset() const { return (uint8_t)(header().offset_flags.offset_reserved >> 4); } - // Set raw TCP offset in quadruples - inline void set_offset(uint8_t offset) { header().offset_flags.offset_reserved = (offset << 4); } + // Set raw TCP offset in quadruples + inline void set_offset(uint8_t offset) { header().offset_flags.offset_reserved = (offset << 4); } - // The actaul TCP header size (including options). - inline uint8_t header_size() const { return offset() * 4; } + // The actaul TCP header size (including options). + inline uint8_t header_size() const { return offset() * 4; } - // Calculate the full header length, down to linklayer, in bytes - uint8_t all_headers_len() const { return (HEADERS_SIZE - sizeof(TCP::Header)) + header_size(); } + // Calculate the full header length, down to linklayer, in bytes + uint8_t all_headers_len() const { return (HEADERS_SIZE - sizeof(TCP::Header)) + header_size(); } - // Where data starts - inline char* data() { return (char*) (buffer() + all_headers_len()); } + // Where data starts + inline char* data() { return (char*) (buffer() + all_headers_len()); } - inline uint16_t data_length() const { return size() - all_headers_len(); } - - inline bool has_data() const { return data_length() > 0; } - - inline uint16_t tcp_length() const { return header_size() + data_length(); } - - template - inline void add_option(Args&&... args) { - // to avoid headache, options need to be added BEFORE any data. - assert(!has_data()); - // option address - auto* addr = options()+options_length(); - new (addr) T(args...); - // update offset - set_offset(offset() + round_up( ((T*)addr)->length, 4 )); - set_length(); // update - } - - inline void clear_options() { - // clear existing options - // move data (if any) (??) - set_offset(5); - set_length(); // update - } - - inline uint8_t* options() { return (uint8_t*) header().options; } - - inline uint8_t options_length() const { return header_size() - sizeof(TCP::Header); } - - inline bool has_options() const { return options_length() > 0; } - - // sets the correct length for all the protocols up to IP4 - void set_length(uint16_t newlen = 0) { - // new total packet length - set_size( all_headers_len() + newlen ); - } - - //! assuming the packet has been properly initialized, - //! this will fill bytes from @buffer into this packets buffer, - //! then return the number of bytes written. buffer is unmodified - size_t fill(const char* buffer, size_t length) { - size_t rem = capacity() - all_headers_len(); - size_t total = (length < rem) ? length : rem; - // copy from buffer to packet buffer - memcpy(data() + data_length(), buffer, total); - // set new packet length - set_length(data_length() + total); - return total; - } - - inline std::string to_string() { - std::ostringstream os; - os << "[ S:" << source().to_string() << " D:" << destination().to_string() - << " SEQ:" << seq() << " ACK:" << ack() - << " HEAD-LEN:" << (int)header_size() << " OPT-LEN:" << (int)options_length() << " DATA-LEN:" << data_length() - << " WIN:" << win() << " FLAGS:" << std::bitset<8>{header().offset_flags.flags} << " ]"; - return os.str(); - } - - }; // << class TCP::Packet + inline uint16_t data_length() const { return size() - all_headers_len(); } + + inline bool has_data() const { return data_length() > 0; } + + inline uint16_t tcp_length() const { return header_size() + data_length(); } + + template + inline void add_option(Args&&... args) { + // to avoid headache, options need to be added BEFORE any data. + assert(!has_data()); + // option address + auto* addr = options()+options_length(); + new (addr) T(args...); + // update offset + set_offset(offset() + round_up( ((T*)addr)->length, 4 )); + set_length(); // update + } + + inline void clear_options() { + // clear existing options + // move data (if any) (??) + set_offset(5); + set_length(); // update + } + + inline uint8_t* options() { return (uint8_t*) header().options; } + + inline uint8_t options_length() const { return header_size() - sizeof(TCP::Header); } + + inline bool has_options() const { return options_length() > 0; } + + // sets the correct length for all the protocols up to IP4 + void set_length(uint16_t newlen = 0) { + // new total packet length + set_size( all_headers_len() + newlen ); + } + + //! assuming the packet has been properly initialized, + //! this will fill bytes from @buffer into this packets buffer, + //! then return the number of bytes written. buffer is unmodified + size_t fill(const char* buffer, size_t length) { + size_t rem = capacity() - all_headers_len(); + size_t total = (length < rem) ? length : rem; + // copy from buffer to packet buffer + memcpy(data() + data_length(), buffer, total); + // set new packet length + set_length(data_length() + total); + return total; + } + + inline std::string to_string() { + std::ostringstream os; + os << "[ S:" << source().to_string() << " D:" << destination().to_string() + << " SEQ:" << seq() << " ACK:" << ack() + << " HEAD-LEN:" << (int)header_size() << " OPT-LEN:" << (int)options_length() << " DATA-LEN:" << data_length() + << " WIN:" << win() << " FLAGS:" << std::bitset<8>{header().offset_flags.flags} << " ]"; + return os.str(); + } + + }; // << class TCP::Packet - /* - TODO: Does this need to be better? (faster? stronger?) - */ - class TCPException : public std::runtime_error { - public: - TCPException(const std::string& error) : std::runtime_error(error) {}; - virtual ~TCPException() {}; - }; + /* + TODO: Does this need to be better? (faster? stronger?) + */ + class TCPException : public std::runtime_error { + public: + TCPException(const std::string& error) : std::runtime_error(error) {}; + virtual ~TCPException() {}; + }; - /* - Exception for Bad TCP Header Option (TCP::Option) - */ - class TCPBadOptionException : public TCPException { - public: - TCPBadOptionException(Option::Kind kind, const std::string& error) : - TCPException("Bad Option [" + Option::kind_string(kind) + "]: " + error), - kind_(kind) {}; - - Option::Kind kind(); - private: - Option::Kind kind_; - }; + /* + Exception for Bad TCP Header Option (TCP::Option) + */ + class TCPBadOptionException : public TCPException { + public: + TCPBadOptionException(Option::Kind kind, const std::string& error) : + TCPException("Bad Option [" + Option::kind_string(kind) + "]: " + error), + kind_(kind) {}; + + Option::Kind kind(); + private: + Option::Kind kind_; + }; - /* - Buffer for TCP::Packet_ptr - */ - template> - class PacketBuffer { - public: + /* + Buffer for TCP::Packet_ptr + */ + template> + class PacketBuffer { + public: - PacketBuffer(typename Buffer::size_type limit) : - buffer_(), data_length_(0), - data_offset_(0), limit_(limit) - { - - } - /* Number of packets */ - inline auto size() const { return buffer_.size(); } + PacketBuffer(typename Buffer::size_type limit) : + buffer_(), data_length_(0), + data_offset_(0), limit_(limit) + { + + } + /* Number of packets */ + inline auto size() const { return buffer_.size(); } - /* Amount of data */ - inline size_t data_size() const { return data_length_; } - - inline void push(const T& packet) { - buffer_.push(packet); - data_length_ += (size_t)packet->data_length(); - } - - inline bool add(T packet) { - if(full()) return false; - push(packet); - return true; - } - - inline void pop() { - data_length_ -= (size_t)buffer_.front()->data_length(); - buffer_.pop(); - } + /* Amount of data */ + inline size_t data_size() const { return data_length_; } - inline const T& front() const { return buffer_.front(); } + inline void push(const T& packet) { + buffer_.push(packet); + data_length_ += (size_t)packet->data_length(); + } - inline const T& back() const { return buffer_.back(); } + inline bool add(T packet) { + if(full()) return false; + push(packet); + return true; + } - inline bool empty() const { return buffer_.empty(); } + inline void pop() { + data_length_ -= (size_t)buffer_.front()->data_length(); + buffer_.pop(); + } - inline auto limit() const { return limit_; } + inline const T& front() const { return buffer_.front(); } - inline bool full() const { return size() >= limit(); } + inline const T& back() const { return buffer_.back(); } - inline auto data_offset() const { return data_offset_; } + inline bool empty() const { return buffer_.empty(); } - inline void set_data_offset(uint32_t offset) { data_offset_ = offset; } + inline auto limit() const { return limit_; } - inline void clear() { - while(!buffer_.empty()) - buffer_.pop(); - data_length_ = {0}; - data_offset_ = {0}; - } + inline bool full() const { return size() >= limit(); } - private: - Buffer buffer_; - size_t data_length_; - uint32_t data_offset_; - typename Buffer::size_type limit_; + inline auto data_offset() const { return data_offset_; } - }; // << TCP::PacketBuffer + inline void set_data_offset(uint32_t offset) { data_offset_ = offset; } + inline void clear() { + while(!buffer_.empty()) + buffer_.pop(); + data_length_ = {0}; + data_offset_ = {0}; + } - /* - A connection between two Sockets (local and remote). - Receives and handle TCP::Packet. - Transist between many states. - */ - class Connection : public std::enable_shared_from_this { - public: - /* - Connection identifier - */ - using Tuple = std::pair; - - /// CALLBACKS /// - /* - On connection attempt - When a remote sends SYN to connection in LISTENING state. - First thing that will happen. - */ - using AcceptCallback = delegate)>; - - /* - On connected - When both hosts exchanged sequence numbers (handshake is done). - Now in ESTABLISHED state - it's allowed to write and read to/from the remote. - */ - using ConnectCallback = delegate)>; - - /* - On receiving data - When there is data to read in the receive buffer. - Either when remote PUSH, or buffer is full. - */ - using ReceiveCallback = delegate, bool)>; - - /* - On disconnect - When a remote told it wanna close the connection. - Connection has received a FIN, currently last thing that will happen before a connection is remoed. - */ - struct Disconnect; - - using DisconnectCallback = delegate, Disconnect)>; - - /* - On error - When any of the users request fails. - */ - using ErrorCallback = delegate, TCPException)>; - - /* - When a packet is received - Everytime a connection receives an incoming packet. - Would probably be used for debugging. - (Currently not in use) - */ - using PacketReceivedCallback = delegate, TCP::Packet_ptr)>; - - /* - When a packet is dropped - Everytime an incoming packet is unallowed, it will be dropped. - Can be used for debugging. - */ - using PacketDroppedCallback = delegate; - - /* - Buffer - */ - using Buffer = PacketBuffer<>; - - /* - Reason for disconnect event. - */ - struct Disconnect { - public: - enum Reason { - CLOSING, - REFUSED, - RESET - }; - - Reason reason; + private: + Buffer buffer_; + size_t data_length_; + uint32_t data_offset_; + typename Buffer::size_type limit_; - explicit Disconnect(Reason reason) : reason(reason) {} + }; // << TCP::PacketBuffer - inline operator Reason() const noexcept { return reason; } - inline operator std::string() const noexcept { return to_string(); } - - inline bool operator ==(const Disconnect& dc) const { return reason == dc.reason; } - - std::string to_string() const { - switch(reason) { - case CLOSING: - return "Connection closing"; - case REFUSED: - return "Conneciton refused"; - case RESET: - return "Connection reset"; - default: - return "Unknown reason"; - } - } - }; // < struct TCP::Connection::Disconnect - - /* - Interface for one of the many states a Connection can have. - */ - class State { - public: - enum Result { - CLOSED = -1, - OK = 0, - CLOSE = 1 - }; /* - Open a Connection. - OPEN + A connection between two Sockets (local and remote). + Receives and handle TCP::Packet. + Transist between many states. */ - virtual void open(Connection&, bool active = false); - - /* - Write to a Connection. - SEND - */ - virtual size_t send(Connection&, const char* buffer, size_t n, bool push = false); - - /* - Read from a Connection. - RECEIVE - */ - virtual size_t receive(Connection&, char* buffer, size_t n); + class Connection : public std::enable_shared_from_this { + public: + /* + Connection identifier + */ + using Tuple = std::pair; + + /// CALLBACKS /// + /* + On connection attempt - When a remote sends SYN to connection in LISTENING state. + First thing that will happen. + */ + using AcceptCallback = delegate)>; + + /* + On connected - When both hosts exchanged sequence numbers (handshake is done). + Now in ESTABLISHED state - it's allowed to write and read to/from the remote. + */ + using ConnectCallback = delegate)>; + + /* + On receiving data - When there is data to read in the receive buffer. + Either when remote PUSH, or buffer is full. + */ + using ReceiveCallback = delegate, bool)>; + + /* + On disconnect - When a remote told it wanna close the connection. + Connection has received a FIN, currently last thing that will happen before a connection is remoed. + */ + struct Disconnect; + + using DisconnectCallback = delegate, Disconnect)>; + + /* + On error - When any of the users request fails. + */ + using ErrorCallback = delegate, TCPException)>; + + /* + When a packet is received - Everytime a connection receives an incoming packet. + Would probably be used for debugging. + (Currently not in use) + */ + using PacketReceivedCallback = delegate, TCP::Packet_ptr)>; + + /* + When a packet is dropped - Everytime an incoming packet is unallowed, it will be dropped. + Can be used for debugging. + */ + using PacketDroppedCallback = delegate; + + /* + Buffer + */ + using Buffer = PacketBuffer<>; + + /* + Reason for disconnect event. + */ + struct Disconnect { + public: + enum Reason { + CLOSING, + REFUSED, + RESET + }; + + Reason reason; + + explicit Disconnect(Reason reason) : reason(reason) {} + + inline operator Reason() const noexcept { return reason; } + + inline operator std::string() const noexcept { return to_string(); } + + inline bool operator ==(const Disconnect& dc) const { return reason == dc.reason; } + + std::string to_string() const { + switch(reason) { + case CLOSING: + return "Connection closing"; + case REFUSED: + return "Conneciton refused"; + case RESET: + return "Connection reset"; + default: + return "Unknown reason"; + } + } + }; // < struct TCP::Connection::Disconnect + + /* + Interface for one of the many states a Connection can have. + */ + class State { + public: + enum Result { + CLOSED = -1, + OK = 0, + CLOSE = 1 + }; + /* + Open a Connection. + OPEN + */ + virtual void open(Connection&, bool active = false); + + /* + Write to a Connection. + SEND + */ + virtual size_t send(Connection&, const char* buffer, size_t n, bool push = false); + + /* + Read from a Connection. + RECEIVE + */ + virtual size_t receive(Connection&, char* buffer, size_t n); - /* - Close a Connection. - CLOSE - */ - virtual void close(Connection&); + /* + Close a Connection. + CLOSE + */ + virtual void close(Connection&); - /* - Terminate a Connection. - ABORT - */ - virtual void abort(Connection&); + /* + Terminate a Connection. + ABORT + */ + virtual void abort(Connection&); - /* - Handle a Packet - SEGMENT ARRIVES - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) = 0; - - /* - The current state represented as a string. - STATUS - */ - virtual std::string to_string() const = 0; - - protected: - /* - Helper functions - TODO: Clean up names. - */ - virtual bool check_seq(Connection&, TCP::Packet_ptr); - - virtual void unallowed_syn_reset_connection(Connection&, TCP::Packet_ptr); - - virtual bool check_ack(Connection&, TCP::Packet_ptr); - - virtual void process_segment(Connection&, TCP::Packet_ptr); - - virtual void process_fin(Connection&, TCP::Packet_ptr); - - virtual void send_reset(Connection&); - - }; // < class TCP::Connection::State - - /* - Forward declaration of concrete states. - Definition in "tcp_connection_states.hpp" - */ - class Closed; - class Listen; - class SynSent; - class SynReceived; - class Established; - class FinWait1; - class FinWait2; - class CloseWait; - class LastAck; - class Closing; - class TimeWait; - - /* - Transmission Control Block. - Keep tracks of all the data for a connection. + /* + Handle a Packet + SEGMENT ARRIVES + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) = 0; + + /* + The current state represented as a string. + STATUS + */ + virtual std::string to_string() const = 0; + + protected: + /* + Helper functions + TODO: Clean up names. + */ + virtual bool check_seq(Connection&, TCP::Packet_ptr); + + virtual void unallowed_syn_reset_connection(Connection&, TCP::Packet_ptr); + + virtual bool check_ack(Connection&, TCP::Packet_ptr); + + virtual void process_segment(Connection&, TCP::Packet_ptr); + + virtual void process_fin(Connection&, TCP::Packet_ptr); + + virtual void send_reset(Connection&); + + }; // < class TCP::Connection::State + + /* + Forward declaration of concrete states. + Definition in "tcp_connection_states.hpp" + */ + class Closed; + class Listen; + class SynSent; + class SynReceived; + class Established; + class FinWait1; + class FinWait2; + class CloseWait; + class LastAck; + class Closing; + class TimeWait; + + /* + Transmission Control Block. + Keep tracks of all the data for a connection. - RFC 793: Page 19 - Among the variables stored in the - TCB are the local and remote socket numbers, the security and - precedence of the connection, pointers to the user's send and receive - buffers, pointers to the retransmit queue and to the current segment. - In addition several variables relating to the send and receive - sequence numbers are stored in the TCB. - */ - struct TCB { - /* Send Sequence Variables */ - struct { - TCP::Seq UNA; // send unacknowledged - TCP::Seq NXT; // send next - uint16_t WND; // send window - uint16_t UP; // send urgent pointer - TCP::Seq WL1; // segment sequence number used for last window update - TCP::Seq WL2; // segment acknowledgment number used for last window update - - uint16_t MSS; // Maximum segment size for outgoing segments. - } SND; // << - TCP::Seq ISS; // initial send sequence number - - /* Receive Sequence Variables */ - struct { - TCP::Seq NXT; // receive next - uint16_t WND; // receive window - uint16_t UP; // receive urgent pointer - } RCV; // << - TCP::Seq IRS; // initial receive sequence number - - TCB() { - SND = { 0, 0, TCP::default_window_size, 0, 0, 0, TCP::default_mss }; - ISS = 0; - RCV = { 0, TCP::default_window_size, 0 }; - IRS = 0; - }; - - std::string to_string() const; - }__attribute__((packed)); // < struct TCP::Connection::TCB - - /* - Creates a connection without a remote. - */ - Connection(TCP& host, Port local_port); - - /* - Creates a connection with a remote. - */ - Connection(TCP& host, Port local_port, Socket remote); - - /* - The hosting TCP instance. - */ - inline const TCP& host() const { return host_; } - - /* - The local Socket bound to this connection. - */ - inline TCP::Socket local() const { return {host_.inet_.ip_addr(), local_port_}; } - - /* - The remote Socket bound to this connection. - */ - inline TCP::Socket remote() const { return remote_; } - - /* - Set remote Socket bound to this connection. - @WARNING: Should this be public? Used by TCP. - */ - inline void set_remote(Socket remote) { remote_ = remote; } - - - /* - Read content from remote. - */ - size_t read(char* buffer, size_t n); - - /* - Read n bytes into a string. - Default 1024 bytes. - */ - std::string read(size_t n = 0); - - /* - Write content to remote. - */ - size_t write(const char* buffer, size_t n, bool PUSH = true); - - /* - Write a string to the remote. - */ - inline void write(const std::string& content) { - write(content.data(), content.size(), true); - } - - /* - Open connection. - */ - void open(bool active = false); - - /* - Close connection. - */ - void close(); - - /* - Abort connection. (Same as Terminate) - */ - inline void abort() { - state_->abort(*this); - signal_close(); - } - - /* - Set callback for ACCEPT event. - */ - inline Connection& onAccept(AcceptCallback callback) { - on_accept_ = callback; - return *this; - } - - /* - Set callback for CONNECT event. - */ - inline Connection& onConnect(ConnectCallback callback) { - on_connect_ = callback; - return *this; - } - - /* - Set callback for ON RECEIVE event. - */ - inline Connection& onReceive(ReceiveCallback callback) { - on_receive_ = callback; - return *this; - } - - /* - Set callback for DISCONNECT event. - */ - inline Connection& onDisconnect(DisconnectCallback callback) { - on_disconnect_ = callback; - return *this; - } - - /* - Set callback for ERROR event. - */ - inline Connection& onError(ErrorCallback callback) { - on_error_ = callback; - return *this; - } - - /* - Set callback for every packet received. - */ - inline Connection& onPacketReceived(PacketReceivedCallback callback) { - on_packet_received_ = callback; - return *this; - } - - /* - Set callback for when a packet is dropped. - */ - inline Connection& onPacketDropped(PacketDroppedCallback callback) { - on_packet_dropped_ = callback; - return *this; - } - - /* - Represent the Connection as a string (STATUS). - */ - std::string to_string() const; - - /* - Returns the current state of the connection. - */ - inline Connection::State& state() const { return *state_; } - - /* - Returns the previous state of the connection. - */ - inline Connection::State& prev_state() const { return *prev_state_; } - - /* - Calculates and return bytes transmitted. - TODO: Not sure if this will suffice. - */ - inline uint32_t bytes_transmitted() const { - return control_block.SND.NXT - control_block.ISS; - } - - /* - Calculates and return bytes received. - TODO: Not sure if this will suffice. - */ - inline uint32_t bytes_received() const { - return control_block.RCV.NXT - control_block.IRS; - } - - /* - Return the id (TUPLE) of the connection. - */ - inline Connection::Tuple tuple() const { - return {local_port_, remote_}; - } - - /* - Receive buffer - */ - inline const Buffer& receive_buffer() { - return receive_buffer_; - } - - /* - Send buffer - */ - inline const Buffer& send_buffer() { - return send_buffer_; - } - - /* - Receive a TCP Packet. - - @WARNING: Public, for use in TCP::bottom (friend it?) - */ - void receive(TCP::Packet_ptr); - - - /* - State checks. - */ - bool is_listening() const; - - bool is_connected() const; - - bool is_closing() const; - - bool is_writable() const; - - /* - Helper function for state checks. - */ - inline bool is_state(const State& state) const { - return state_ == &state; - } - - inline bool is_state(const std::string& state_str) const { - return state_->to_string() == state_str; - } - - /* - Destroy the Connection. - - Clean up. - */ - ~Connection(); - - private: - /* - "Parent" for Connection. - */ - TCP& host_; // 4 B - - /* - End points. - */ - TCP::Port local_port_; // 2 B - TCP::Socket remote_; // 8~ B - - /* - The current state the Connection is in. - Handles most of the logic. - */ - State* state_; // 4 B - // Previous state. Used to keep track of state transitions. - State* prev_state_; // 4 B + RFC 793: Page 19 + Among the variables stored in the + TCB are the local and remote socket numbers, the security and + precedence of the connection, pointers to the user's send and receive + buffers, pointers to the retransmit queue and to the current segment. + In addition several variables relating to the send and receive + sequence numbers are stored in the TCB. + */ + struct TCB { + /* Send Sequence Variables */ + struct { + TCP::Seq UNA; // send unacknowledged + TCP::Seq NXT; // send next + uint16_t WND; // send window + uint16_t UP; // send urgent pointer + TCP::Seq WL1; // segment sequence number used for last window update + TCP::Seq WL2; // segment acknowledgment number used for last window update + + uint16_t MSS; // Maximum segment size for outgoing segments. + } SND; // << + TCP::Seq ISS; // initial send sequence number + + /* Receive Sequence Variables */ + struct { + TCP::Seq NXT; // receive next + uint16_t WND; // receive window + uint16_t UP; // receive urgent pointer + } RCV; // << + TCP::Seq IRS; // initial receive sequence number + + TCB() { + SND = { 0, 0, TCP::default_window_size, 0, 0, 0, TCP::default_mss }; + ISS = 0; + RCV = { 0, TCP::default_window_size, 0 }; + IRS = 0; + }; + + std::string to_string() const; + }__attribute__((packed)); // < struct TCP::Connection::TCB + + /* + Creates a connection without a remote. + */ + Connection(TCP& host, Port local_port); + + /* + Creates a connection with a remote. + */ + Connection(TCP& host, Port local_port, Socket remote); + + /* + The hosting TCP instance. + */ + inline const TCP& host() const { return host_; } + + /* + The local Socket bound to this connection. + */ + inline TCP::Socket local() const { return {host_.inet_.ip_addr(), local_port_}; } + + /* + The remote Socket bound to this connection. + */ + inline TCP::Socket remote() const { return remote_; } + + /* + Set remote Socket bound to this connection. + @WARNING: Should this be public? Used by TCP. + */ + inline void set_remote(Socket remote) { remote_ = remote; } + + + /* + Read content from remote. + */ + size_t read(char* buffer, size_t n); + + /* + Read n bytes into a string. + Default 1024 bytes. + */ + std::string read(size_t n = 0); + + /* + Write content to remote. + */ + size_t write(const char* buffer, size_t n, bool PUSH = true); + + /* + Write a string to the remote. + */ + inline void write(const std::string& content) { + write(content.data(), content.size(), true); + } + + /* + Open connection. + */ + void open(bool active = false); + + /* + Close connection. + */ + void close(); + + /* + Abort connection. (Same as Terminate) + */ + inline void abort() { + state_->abort(*this); + signal_close(); + } + + /* + Set callback for ACCEPT event. + */ + inline Connection& onAccept(AcceptCallback callback) { + on_accept_ = callback; + return *this; + } + + /* + Set callback for CONNECT event. + */ + inline Connection& onConnect(ConnectCallback callback) { + on_connect_ = callback; + return *this; + } + + /* + Set callback for ON RECEIVE event. + */ + inline Connection& onReceive(ReceiveCallback callback) { + on_receive_ = callback; + return *this; + } + + /* + Set callback for DISCONNECT event. + */ + inline Connection& onDisconnect(DisconnectCallback callback) { + on_disconnect_ = callback; + return *this; + } + + /* + Set callback for ERROR event. + */ + inline Connection& onError(ErrorCallback callback) { + on_error_ = callback; + return *this; + } + + /* + Set callback for every packet received. + */ + inline Connection& onPacketReceived(PacketReceivedCallback callback) { + on_packet_received_ = callback; + return *this; + } + + /* + Set callback for when a packet is dropped. + */ + inline Connection& onPacketDropped(PacketDroppedCallback callback) { + on_packet_dropped_ = callback; + return *this; + } + + /* + Represent the Connection as a string (STATUS). + */ + std::string to_string() const; + + /* + Returns the current state of the connection. + */ + inline Connection::State& state() const { return *state_; } + + /* + Returns the previous state of the connection. + */ + inline Connection::State& prev_state() const { return *prev_state_; } + + /* + Calculates and return bytes transmitted. + TODO: Not sure if this will suffice. + */ + inline uint32_t bytes_transmitted() const { + return control_block.SND.NXT - control_block.ISS; + } + + /* + Calculates and return bytes received. + TODO: Not sure if this will suffice. + */ + inline uint32_t bytes_received() const { + return control_block.RCV.NXT - control_block.IRS; + } + + /* + Return the id (TUPLE) of the connection. + */ + inline Connection::Tuple tuple() const { + return {local_port_, remote_}; + } + + /* + Receive buffer + */ + inline const Buffer& receive_buffer() { + return receive_buffer_; + } + + /* + Send buffer + */ + inline const Buffer& send_buffer() { + return send_buffer_; + } + + /* + Receive a TCP Packet. + + @WARNING: Public, for use in TCP::bottom (friend it?) + */ + void receive(TCP::Packet_ptr); + + + /* + State checks. + */ + bool is_listening() const; + + bool is_connected() const; + + bool is_closing() const; + + bool is_writable() const; + + /* + Helper function for state checks. + */ + inline bool is_state(const State& state) const { + return state_ == &state; + } + + inline bool is_state(const std::string& state_str) const { + return state_->to_string() == state_str; + } + + /* + Destroy the Connection. + + Clean up. + */ + ~Connection(); + + private: + /* + "Parent" for Connection. + */ + TCP& host_; // 4 B + + /* + End points. + */ + TCP::Port local_port_; // 2 B + TCP::Socket remote_; // 8~ B + + /* + The current state the Connection is in. + Handles most of the logic. + */ + State* state_; // 4 B + // Previous state. Used to keep track of state transitions. + State* prev_state_; // 4 B - /* - Keep tracks of all sequence variables. - */ - TCB control_block; // 36 B - - /* - Buffers - */ - Buffer receive_buffer_; - Buffer send_buffer_; - - /* - When time-wait timer was started. - */ - uint64_t time_wait_started; + /* + Keep tracks of all sequence variables. + */ + TCB control_block; // 36 B + + /* + Buffers + */ + Buffer receive_buffer_; + Buffer send_buffer_; + + /* + When time-wait timer was started. + */ + uint64_t time_wait_started; - /// CALLBACK HANDLING /// + /// CALLBACK HANDLING /// - /* When a Connection is initiated. */ - AcceptCallback on_accept_ = AcceptCallback::from(this); - inline bool default_on_accept(std::shared_ptr) { - //debug2(" Connection attempt from: %s \n", conn->remote().to_string().c_str()); - return true; // Always accept - } - - /* When Connection is ESTABLISHED. */ - ConnectCallback on_connect_ = [](std::shared_ptr) { - debug2(" Connected.\n"); - }; + /* When a Connection is initiated. */ + AcceptCallback on_accept_ = AcceptCallback::from(this); + inline bool default_on_accept(std::shared_ptr) { + //debug2(" Connection attempt from: %s \n", conn->remote().to_string().c_str()); + return true; // Always accept + } + + /* When Connection is ESTABLISHED. */ + ConnectCallback on_connect_ = [](std::shared_ptr) { + debug2(" Connected.\n"); + }; - /* When data is received */ - ReceiveCallback on_receive_ = [](std::shared_ptr, bool) { - debug2(" Connection received data. \n"); - }; + /* When data is received */ + ReceiveCallback on_receive_ = [](std::shared_ptr, bool) { + debug2(" Connection received data. \n"); + }; - /* When Connection is CLOSING. */ - DisconnectCallback on_disconnect_ = [](std::shared_ptr, Disconnect) { - //debug2(" Connection disconnect. Reason: %s \n", msg.c_str()); - }; + /* When Connection is CLOSING. */ + DisconnectCallback on_disconnect_ = [](std::shared_ptr, Disconnect) { + //debug2(" Connection disconnect. Reason: %s \n", msg.c_str()); + }; - /* When error occcured. */ - ErrorCallback on_error_ = ErrorCallback::from(this); - inline void default_on_error(std::shared_ptr, TCPException) { - //debug2(" TCPException: %s \n", error.what()); - } + /* When error occcured. */ + ErrorCallback on_error_ = ErrorCallback::from(this); + inline void default_on_error(std::shared_ptr, TCPException) { + //debug2(" TCPException: %s \n", error.what()); + } - /* When packet is received */ - PacketReceivedCallback on_packet_received_ = [](std::shared_ptr, TCP::Packet_ptr) { - //debug2(" Packet received: %s \n", packet->to_string().c_str()); - }; + /* When packet is received */ + PacketReceivedCallback on_packet_received_ = [](std::shared_ptr, TCP::Packet_ptr) { + //debug2(" Packet received: %s \n", packet->to_string().c_str()); + }; - /* When a packet is dropped. */ - PacketDroppedCallback on_packet_dropped_ = [](TCP::Packet_ptr, std::string) { - //debug(" Packet dropped. %s | Reason: %s \n", - // packet->to_string().c_str(), reason.c_str()); - }; + /* When a packet is dropped. */ + PacketDroppedCallback on_packet_dropped_ = [](TCP::Packet_ptr, std::string) { + //debug(" Packet dropped. %s | Reason: %s \n", + // packet->to_string().c_str(), reason.c_str()); + }; - /* - Invoke/signal the diffrent TCP events. - */ - inline bool signal_accept() { return on_accept_(shared_from_this()); } + /* + Invoke/signal the diffrent TCP events. + */ + inline bool signal_accept() { return on_accept_(shared_from_this()); } - inline void signal_connect() { on_connect_(shared_from_this()); } + inline void signal_connect() { on_connect_(shared_from_this()); } - inline void signal_receive(bool PUSH) { on_receive_(shared_from_this(), PUSH); } + inline void signal_receive(bool PUSH) { on_receive_(shared_from_this(), PUSH); } - inline void signal_disconnect(Disconnect::Reason&& reason) { on_disconnect_(shared_from_this(), Disconnect{reason}); } + inline void signal_disconnect(Disconnect::Reason&& reason) { on_disconnect_(shared_from_this(), Disconnect{reason}); } - inline void signal_error(TCPException error) { on_error_(shared_from_this(), error); } + inline void signal_error(TCPException error) { on_error_(shared_from_this(), error); } - inline void signal_packet_received(TCP::Packet_ptr packet) { on_packet_received_(shared_from_this(), packet); } + inline void signal_packet_received(TCP::Packet_ptr packet) { on_packet_received_(shared_from_this(), packet); } - inline void signal_packet_dropped(TCP::Packet_ptr packet, std::string reason) { on_packet_dropped_(packet, reason); } + inline void signal_packet_dropped(TCP::Packet_ptr packet, std::string reason) { on_packet_dropped_(packet, reason); } - /* - Drop a packet. Used for debug/callback. - */ - inline void drop(TCP::Packet_ptr packet, std::string reason) { signal_packet_dropped(packet, reason); } - inline void drop(TCP::Packet_ptr packet) { drop(packet, "None given."); } + /* + Drop a packet. Used for debug/callback. + */ + inline void drop(TCP::Packet_ptr packet, std::string reason) { signal_packet_dropped(packet, reason); } + inline void drop(TCP::Packet_ptr packet) { drop(packet, "None given."); } - /// TCB HANDLING /// + /// TCB HANDLING /// - /* - Returns the TCB. - */ - inline Connection::TCB& tcb() { return control_block; } + /* + Returns the TCB. + */ + inline Connection::TCB& tcb() { return control_block; } - /* - Generate a new ISS. - */ - TCP::Seq generate_iss(); + /* + Generate a new ISS. + */ + TCP::Seq generate_iss(); - /// STATE HANDLING /// - /* - Set state. (used by substates) - */ - void set_state(State& state); + /// STATE HANDLING /// + /* + Set state. (used by substates) + */ + void set_state(State& state); - /// BUFFER HANDLING /// + /// BUFFER HANDLING /// - /* - Read from receive buffer. - */ - size_t read_from_receive_buffer(char* buffer, size_t n); + /* + Read from receive buffer. + */ + size_t read_from_receive_buffer(char* buffer, size_t n); - /* - Add(queue) a packet to the receive buffer. - */ - bool add_to_receive_buffer(TCP::Packet_ptr packet); + /* + Add(queue) a packet to the receive buffer. + */ + bool add_to_receive_buffer(TCP::Packet_ptr packet); - /* - Write to the send buffer. Segmentize into packets. - */ - size_t write_to_send_buffer(const char* buffer, size_t n, bool PUSH = true); - - /* - Transmit the send buffer. - */ - void transmit(); - - /* - Transmit the packet. - */ - void transmit(TCP::Packet_ptr); - - /* - Creates a new outgoing packet and put it in the back of the send buffer. - */ - TCP::Packet_ptr create_outgoing_packet(); - - /* - Returns the packet in the back of the send buffer. - If the send buffer is empty, it creates a new packet and adds it. - */ - TCP::Packet_ptr outgoing_packet(); + /* + Write to the send buffer. Segmentize into packets. + */ + size_t write_to_send_buffer(const char* buffer, size_t n, bool PUSH = true); + + /* + Transmit the send buffer. + */ + void transmit(); + + /* + Transmit the packet. + */ + void transmit(TCP::Packet_ptr); + + /* + Creates a new outgoing packet and put it in the back of the send buffer. + */ + TCP::Packet_ptr create_outgoing_packet(); + + /* + Returns the packet in the back of the send buffer. + If the send buffer is empty, it creates a new packet and adds it. + */ + TCP::Packet_ptr outgoing_packet(); - /// RETRANSMISSION /// + /// RETRANSMISSION /// - /* - Starts a retransmission timer that retransmits the packet when RTO has passed. + /* + Starts a retransmission timer that retransmits the packet when RTO has passed. - // TODO: Calculate RTO, currently hardcoded to 1 second (1000ms). - */ - void add_retransmission(TCP::Packet_ptr); - - /* - Measure the elapsed time between sending a data octet with a - particular sequence number and receiving an acknowledgment that - covers that sequence number (segments sent do not have to match - segments received). This measured elapsed time is the Round Trip - Time (RTT). - */ - //std::chrono::milliseconds RTT() const; - std::chrono::milliseconds RTO() const; + // TODO: Calculate RTO, currently hardcoded to 1 second (1000ms). + */ + void add_retransmission(TCP::Packet_ptr); + + /* + Measure the elapsed time between sending a data octet with a + particular sequence number and receiving an acknowledgment that + covers that sequence number (segments sent do not have to match + segments received). This measured elapsed time is the Round Trip + Time (RTT). + */ + //std::chrono::milliseconds RTT() const; + std::chrono::milliseconds RTO() const; - /* - Start the time wait timeout for 2*MSL - */ - void start_time_wait_timeout(); + /* + Start the time wait timeout for 2*MSL + */ + void start_time_wait_timeout(); - /* - Tell the host (TCP) to delete this connection. - */ - void signal_close(); + /* + Tell the host (TCP) to delete this connection. + */ + void signal_close(); - /// OPTIONS /// - /* - Maximum Segment Data Size - (Limit the size for outgoing packets) - */ - inline uint16_t MSDS() const { - return std::min(host_.MSS(), control_block.SND.MSS); - } + /// OPTIONS /// + /* + Maximum Segment Data Size + (Limit the size for outgoing packets) + */ + inline uint16_t MSDS() const { + return std::min(host_.MSS(), control_block.SND.MSS); + } - /* - Parse and apply options. - */ - void parse_options(TCP::Packet_ptr); + /* + Parse and apply options. + */ + void parse_options(TCP::Packet_ptr); - /* - Add an option. - */ - void add_option(TCP::Option::Kind, TCP::Packet_ptr); + /* + Add an option. + */ + void add_option(TCP::Option::Kind, TCP::Packet_ptr); - }; // < class TCP::Connection + }; // < class TCP::Connection - /// USER INTERFACE - TCP /// + /// USER INTERFACE - TCP /// - /* - Constructor - */ - TCP(IPStack&); + /* + Constructor + */ + TCP(IPStack&); - /* - Bind a new listener to a given Port. - */ - TCP::Connection& bind(Port port); + /* + Bind a new listener to a given Port. + */ + TCP::Connection& bind(Port port); - /* - Active open a new connection to the given remote. - */ - Connection_ptr connect(Socket remote); + /* + Active open a new connection to the given remote. + */ + Connection_ptr connect(Socket remote); - /* - Active open a new connection to the given remote. - */ - inline auto connect(TCP::Address address, Port port = 80) { - return connect({address, port}); - } + /* + Active open a new connection to the given remote. + */ + inline auto connect(TCP::Address address, Port port = 80) { + return connect({address, port}); + } - /* - Active open a new connection to the given remote. - */ - void connect(Socket remote, Connection::ConnectCallback); + /* + Active open a new connection to the given remote. + */ + void connect(Socket remote, Connection::ConnectCallback); - /* - Receive packet from network layer (IP). - */ - void bottom(net::Packet_ptr); + /* + Receive packet from network layer (IP). + */ + void bottom(net::Packet_ptr); - /* - Delegate output to network layer - */ - inline void set_network_out(downstream del) { _network_layer_out = del; } + /* + Delegate output to network layer + */ + inline void set_network_out(downstream del) { _network_layer_out = del; } - /* - Compute the TCP checksum - */ + /* + Compute the TCP checksum + */ static uint16_t checksum(const TCP::Packet_ptr); inline const auto& listeners() { return listeners_; } @@ -1236,113 +1236,113 @@ namespace net { inline const auto& connections() { return connections_; } /* - Number of open ports. + Number of open ports. */ - inline size_t openPorts() { return listeners_.size(); } + inline size_t openPorts() { return listeners_.size(); } - /* - Number of active connections. - */ - inline size_t activeConnections() { return connections_.size(); } + /* + Number of active connections. + */ + inline size_t activeConnections() { return connections_.size(); } - /* - Maximum Segment Lifetime - */ - inline auto MSL() const { return MAX_SEG_LIFETIME; } + /* + Maximum Segment Lifetime + */ + inline auto MSL() const { return MAX_SEG_LIFETIME; } - /* - Set Maximum Segment Lifetime - */ - inline void set_MSL(const std::chrono::milliseconds msl) { - MAX_SEG_LIFETIME = msl; - } + /* + Set Maximum Segment Lifetime + */ + inline void set_MSL(const std::chrono::milliseconds msl) { + MAX_SEG_LIFETIME = msl; + } - /* - Maximum Buffer Size - */ - inline auto buffer_limit() const { return MAX_BUFFER_SIZE; } + /* + Maximum Buffer Size + */ + inline auto buffer_limit() const { return MAX_BUFFER_SIZE; } - /* - Set Buffer limit - */ - inline void set_buffer_limit(size_t buffer_limit) { - MAX_BUFFER_SIZE = buffer_limit; - } + /* + Set Buffer limit + */ + inline void set_buffer_limit(size_t buffer_limit) { + MAX_BUFFER_SIZE = buffer_limit; + } - /* - Maximum Segment Size - [RFC 793] [RFC 879] [RFC 6691] + /* + Maximum Segment Size + [RFC 793] [RFC 879] [RFC 6691] - @NOTE: Currently not supporting MTU bigger than 1482 bytes. - */ - inline uint16_t MSS() const { - /* - VirtulaBox "issue": - MTU > 1498 will break TCP. - MTU > 1482 seems to cause fragmentation: https://www.virtualbox.org/ticket/13967 - */ - const uint16_t VBOX_LIMIT = 1482; - return std::min(inet_.MTU(), VBOX_LIMIT) - sizeof(Full_header::ip4) - sizeof(TCP::Header); - } + @NOTE: Currently not supporting MTU bigger than 1482 bytes. + */ + inline uint16_t MSS() const { + /* + VirtulaBox "issue": + MTU > 1498 will break TCP. + MTU > 1482 seems to cause fragmentation: https://www.virtualbox.org/ticket/13967 + */ + const uint16_t VBOX_LIMIT = 1482; + return std::min(inet_.MTU(), VBOX_LIMIT) - sizeof(Full_header::ip4) - sizeof(TCP::Header); + } - /* - Show all connections for TCP as a string. - */ - std::string status() const; + /* + Show all connections for TCP as a string. + */ + std::string status() const; - private: - IPStack& inet_; - std::map listeners_; - std::map connections_; +private: + IPStack& inet_; + std::map listeners_; + std::map connections_; - downstream _network_layer_out; + downstream _network_layer_out; - /* - Settings - */ - TCP::Port current_ephemeral_ = 1024; + /* + Settings + */ + TCP::Port current_ephemeral_ = 1024; - std::chrono::milliseconds MAX_SEG_LIFETIME; + std::chrono::milliseconds MAX_SEG_LIFETIME; - /* - Current: limit by packet COUNT. - Connection buffer size in bytes = buffers * BUFFER_LIMIT * MTU. - */ - size_t MAX_BUFFER_SIZE = 10; + /* + Current: limit by packet COUNT. + Connection buffer size in bytes = buffers * BUFFER_LIMIT * MTU. + */ + size_t MAX_BUFFER_SIZE = 10; - /* - Transmit packet to network layer (IP). - */ - void transmit(TCP::Packet_ptr); + /* + Transmit packet to network layer (IP). + */ + void transmit(TCP::Packet_ptr); - /* - Generate a unique initial sequence number (ISS). - */ - TCP::Seq generate_iss(); + /* + Generate a unique initial sequence number (ISS). + */ + TCP::Seq generate_iss(); - /* - Returns a free port for outgoing connections. - */ - TCP::Port free_port(); + /* + Returns a free port for outgoing connections. + */ + TCP::Port free_port(); - /* - Packet is dropped. - */ - void drop(TCP::Packet_ptr); + /* + Packet is dropped. + */ + void drop(TCP::Packet_ptr); - /* - Add a Connection. - */ - Connection_ptr add_connection(TCP::Port local_port, TCP::Socket remote); + /* + Add a Connection. + */ + Connection_ptr add_connection(TCP::Port local_port, TCP::Socket remote); - /* - Close and delete the connection. - */ - void close_connection(TCP::Connection&); + /* + Close and delete the connection. + */ + void close_connection(TCP::Connection&); - }; // < class TCP +}; // < class TCP }; // < namespace net diff --git a/api/net/tcp_connection_states.hpp b/api/net/tcp_connection_states.hpp index 118193835a..67e314d43d 100644 --- a/api/net/tcp_connection_states.hpp +++ b/api/net/tcp_connection_states.hpp @@ -25,320 +25,320 @@ using Connection = TCP::Connection; using State = TCP::Connection::State; /* - CLOSED + CLOSED */ class Connection::Closed : public State { public: - inline static State& instance() { - static Closed instance; - return instance; - } + inline static State& instance() { + static Closed instance; + return instance; + } - virtual void open(Connection&, bool active = false) override; + virtual void open(Connection&, bool active = false) override; - virtual size_t send(Connection&, const char* buffer, size_t n, bool push) override; + virtual size_t send(Connection&, const char* buffer, size_t n, bool push) override; - /* - PASSIVE: - <- Do nothing (Start listening). + /* + PASSIVE: + <- Do nothing (Start listening). - => Listen. + => Listen. - ACTIVE: - <- Send SYN. + ACTIVE: + <- Send SYN. - => SynSent - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + => SynSent + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "CLOSED"; - }; + inline virtual std::string to_string() const override { + return "CLOSED"; + }; private: - inline Closed() {}; + inline Closed() {}; }; /* - LISTEN + LISTEN */ class Connection::Listen : public State { public: - inline static State& instance() { - static Listen instance; - return instance; - } - virtual void open(Connection&, bool active = false) override; + inline static State& instance() { + static Listen instance; + return instance; + } + virtual void open(Connection&, bool active = false) override; - virtual size_t send(Connection&, const char* buffer, size_t n, bool push) override; + virtual size_t send(Connection&, const char* buffer, size_t n, bool push) override; - virtual void close(Connection&) override; - /* - -> Receive SYN. + virtual void close(Connection&) override; + /* + -> Receive SYN. - <- Send SYN+ACK. + <- Send SYN+ACK. - => SynReceived. - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + => SynReceived. + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "LISTENING"; - }; + inline virtual std::string to_string() const override { + return "LISTENING"; + }; private: - inline Listen() {}; + inline Listen() {}; }; /* - SYN-SENT + SYN-SENT */ class Connection::SynSent : public State { public: - inline static State& instance() { - static SynSent instance; - return instance; - } + inline static State& instance() { + static SynSent instance; + return instance; + } - virtual size_t send(Connection&, const char* buffer, size_t n, bool push) override; + virtual size_t send(Connection&, const char* buffer, size_t n, bool push) override; - virtual void close(Connection&) override; - /* - -> Receive SYN+ACK + virtual void close(Connection&) override; + /* + -> Receive SYN+ACK - <- Send ACK. + <- Send ACK. - => Established. - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + => Established. + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "SYN-SENT"; - }; + inline virtual std::string to_string() const override { + return "SYN-SENT"; + }; private: - inline SynSent() {}; + inline SynSent() {}; }; /* - SYN-RCV + SYN-RCV */ class Connection::SynReceived : public State { public: - inline static State& instance() { - static SynReceived instance; - return instance; - } + inline static State& instance() { + static SynReceived instance; + return instance; + } - virtual size_t send(Connection&, const char* buffer, size_t n, bool push) override; + virtual size_t send(Connection&, const char* buffer, size_t n, bool push) override; - virtual void close(Connection&) override; + virtual void close(Connection&) override; - virtual void abort(Connection&) override; - /* - -> Receive ACK. + virtual void abort(Connection&) override; + /* + -> Receive ACK. - <- Do nothing (Connection is Established) + <- Do nothing (Connection is Established) - => Established. - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + => Established. + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "SYN-RCV"; - }; + inline virtual std::string to_string() const override { + return "SYN-RCV"; + }; private: - inline SynReceived() {}; + inline SynReceived() {}; }; /* - ESTABLISHED + ESTABLISHED */ class Connection::Established : public State { public: - inline static State& instance() { - static Established instance; - return instance; - } + inline static State& instance() { + static Established instance; + return instance; + } - virtual size_t send(Connection&, const char* buffer, size_t n, bool push) override; + virtual size_t send(Connection&, const char* buffer, size_t n, bool push) override; - virtual size_t receive(Connection&, char* buffer, size_t n) override; + virtual size_t receive(Connection&, char* buffer, size_t n) override; - virtual void close(Connection&) override; + virtual void close(Connection&) override; - virtual void abort(Connection&) override; + virtual void abort(Connection&) override; - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "ESTABLISHED"; - }; + inline virtual std::string to_string() const override { + return "ESTABLISHED"; + }; private: - inline Established() {}; + inline Established() {}; }; /* - FIN-WAIT-1 + FIN-WAIT-1 */ class Connection::FinWait1 : public State { public: - inline static State& instance() { - static FinWait1 instance; - return instance; - } + inline static State& instance() { + static FinWait1 instance; + return instance; + } - virtual size_t receive(Connection&, char* buffer, size_t n) override; + virtual size_t receive(Connection&, char* buffer, size_t n) override; - virtual void close(Connection&) override; + virtual void close(Connection&) override; - virtual void abort(Connection&) override; + virtual void abort(Connection&) override; - /* - -> Receive ACK. + /* + -> Receive ACK. - => FinWait2. - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + => FinWait2. + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "FIN-WAIT-1"; - }; + inline virtual std::string to_string() const override { + return "FIN-WAIT-1"; + }; private: - inline FinWait1() {}; + inline FinWait1() {}; }; /* - FIN-WAIT-2 + FIN-WAIT-2 */ class Connection::FinWait2 : public State { public: - inline static State& instance() { - static FinWait2 instance; - return instance; - } + inline static State& instance() { + static FinWait2 instance; + return instance; + } - virtual size_t receive(Connection&, char* buffer, size_t n) override; + virtual size_t receive(Connection&, char* buffer, size_t n) override; - virtual void close(Connection&) override; + virtual void close(Connection&) override; - virtual void abort(Connection&) override; - /* + virtual void abort(Connection&) override; + /* - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "FIN-WAIT-2"; - }; + inline virtual std::string to_string() const override { + return "FIN-WAIT-2"; + }; private: - inline FinWait2() {}; + inline FinWait2() {}; }; /* - CLOSE-WAIT + CLOSE-WAIT */ class Connection::CloseWait : public State { public: - inline static State& instance() { - static CloseWait instance; - return instance; - } + inline static State& instance() { + static CloseWait instance; + return instance; + } - virtual size_t send(Connection&, const char* buffer, size_t n, bool push) override; + virtual size_t send(Connection&, const char* buffer, size_t n, bool push) override; - virtual size_t receive(Connection&, char* buffer, size_t n) override; + virtual size_t receive(Connection&, char* buffer, size_t n) override; - virtual void close(Connection&) override; + virtual void close(Connection&) override; - virtual void abort(Connection&) override; - /* - -> Nothing I think... + virtual void abort(Connection&) override; + /* + -> Nothing I think... - <- Send FIN. + <- Send FIN. - => LastAck - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + => LastAck + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "CLOSE-WAIT"; - }; + inline virtual std::string to_string() const override { + return "CLOSE-WAIT"; + }; private: - inline CloseWait() {}; + inline CloseWait() {}; }; /* - LAST-ACK + LAST-ACK */ class Connection::LastAck : public State { public: - inline static State& instance() { - static LastAck instance; - return instance; - } - /* - -> Receive ACK. + inline static State& instance() { + static LastAck instance; + return instance; + } + /* + -> Receive ACK. - <- conn.onClose(); + <- conn.onClose(); - => Closed (Tell TCP to remove this connection) - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + => Closed (Tell TCP to remove this connection) + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "LAST-ACK"; - }; + inline virtual std::string to_string() const override { + return "LAST-ACK"; + }; private: - inline LastAck() {}; + inline LastAck() {}; }; /* - CLOSING + CLOSING */ class Connection::Closing : public State { public: - inline static State& instance() { - static Closing instance; - return instance; - } - /* - -> Receive ACK. + inline static State& instance() { + static Closing instance; + return instance; + } + /* + -> Receive ACK. - => TimeWait (Guess this isnt needed, just start a Close-timer) - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + => TimeWait (Guess this isnt needed, just start a Close-timer) + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "CLOSING"; - }; + inline virtual std::string to_string() const override { + return "CLOSING"; + }; private: - inline Closing() {}; + inline Closing() {}; }; /* - TIME-WAIT + TIME-WAIT */ class Connection::TimeWait : public State { public: - inline static State& instance() { - static TimeWait instance; - return instance; - } - /* + inline static State& instance() { + static TimeWait instance; + return instance; + } + /* - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "TIME-WAIT"; - }; + inline virtual std::string to_string() const override { + return "TIME-WAIT"; + }; private: - inline TimeWait() {}; + inline TimeWait() {}; }; -#endif +#endif \ No newline at end of file diff --git a/api/net/util.hpp b/api/net/util.hpp index 621273bf2f..f5d3f7161a 100644 --- a/api/net/util.hpp +++ b/api/net/util.hpp @@ -22,37 +22,37 @@ namespace net { - /* - * See P.49 of C programming - * Get "n" bits from integer "x", starting from position "p" - * e.g., getbits(x, 31, 8) -- highest byte - * getbits(x, 7, 8) -- lowest byte - */ +/* + * See P.49 of C programming + * Get "n" bits from integer "x", starting from position "p" + * e.g., getbits(x, 31, 8) -- highest byte + * getbits(x, 7, 8) -- lowest byte + */ #define getbits(x, p, n) (((x) >> ((p) + 1 - (n))) & ~(~0 << (n))) - inline uint16_t ntohs(uint16_t n) noexcept { - return __builtin_bswap16(n); - } +inline uint16_t ntohs(uint16_t n) noexcept { + return __builtin_bswap16(n); +} - inline uint16_t htons(uint16_t n) noexcept { - return __builtin_bswap16(n); - } +inline uint16_t htons(uint16_t n) noexcept { + return __builtin_bswap16(n); +} - inline uint32_t ntohl(uint32_t n) noexcept { - return __builtin_bswap32(n); - } +inline uint32_t ntohl(uint32_t n) noexcept { + return __builtin_bswap32(n); +} - inline uint32_t htonl(uint32_t n) noexcept { - return __builtin_bswap32(n); - } +inline uint32_t htonl(uint32_t n) noexcept { + return __builtin_bswap32(n); +} - inline uint64_t ntohll(uint64_t n) noexcept { - return __builtin_bswap64(n); - } +inline uint64_t ntohll(uint64_t n) noexcept { + return __builtin_bswap64(n); +} - inline uint64_t htonll(uint64_t n) noexcept { - return __builtin_bswap64(n); - } +inline uint64_t htonll(uint64_t n) noexcept { + return __builtin_bswap64(n); +} } //< namespace net diff --git a/api/utility/async_loop.hpp b/api/utility/async_loop.hpp index d30230784e..c4c456a360 100644 --- a/api/utility/async_loop.hpp +++ b/api/utility/async_loop.hpp @@ -6,27 +6,27 @@ typedef std::shared_ptr next_ptr_t; inline void async_loop( - std::function func, - std::function on_done) + std::function func, + std::function on_done) { // store next function on heap auto next = std::make_shared (); // loop: *next = - [next] (bool done) + [next] (bool done) + { + // check we are done, and if so, + // execute the callback function and return + if (done) { - // check we are done, and if so, - // execute the callback function and return - if (done) - { - on_done(); - return; - } - // otherwise, - // execute one iteration of the loop - func(next); + on_done(); + return; } + // otherwise, + // execute one iteration of the loop + func(next); + } // start the process next(false); } diff --git a/api/utility/delegate.hpp b/api/utility/delegate.hpp index a942bf7da5..27c04c64cd 100644 --- a/api/utility/delegate.hpp +++ b/api/utility/delegate.hpp @@ -7,7 +7,7 @@ Licence: Assumed to be public domain. ...It's just awesome how people make great stuff and just post it -*/ + */ #ifndef OSABI_DELEGATE_HPP #define OSABI_DELEGATE_HPP @@ -25,7 +25,7 @@ class delegate using stub_ptr_type = R (*)(void*, A&&...); delegate(void* const o, stub_ptr_type const m) noexcept : - object_ptr_(o), + object_ptr_(o), stub_ptr_(m) { } @@ -42,16 +42,16 @@ class delegate delegate(::std::nullptr_t const) noexcept : delegate() { } template {}>::type> - explicit delegate(C const* const o) noexcept : - object_ptr_(const_cast(o)) + typename ::std::enable_if< ::std::is_class{}>::type> + explicit delegate(C const* const o) noexcept : + object_ptr_(const_cast(o)) { } template {}>::type> - explicit delegate(C const& o) noexcept : - object_ptr_(const_cast(&o)) + typename ::std::enable_if< ::std::is_class{}>::type> + explicit delegate(C const& o) noexcept : + object_ptr_(const_cast(&o)) { } @@ -84,11 +84,11 @@ class delegate typename = typename ::std::enable_if< !::std::is_same::type>{} >::type - > - delegate(T&& f) : + > + delegate(T&& f) : store_(operator new(sizeof(typename ::std::decay::type)), - functor_deleter::type>), - store_size_(sizeof(typename ::std::decay::type)) + functor_deleter::type>), + store_size_(sizeof(typename ::std::decay::type)) { using functor_type = typename ::std::decay::type; @@ -122,22 +122,22 @@ class delegate typename = typename ::std::enable_if< !::std::is_same::type>{} >::type - > - delegate& operator=(T&& f) + > + delegate& operator=(T&& f) { using functor_type = typename ::std::decay::type; if ((sizeof(functor_type) > store_size_) || !store_.unique()) - { - store_.reset(operator new(sizeof(functor_type)), - functor_deleter); + { + store_.reset(operator new(sizeof(functor_type)), + functor_deleter); - store_size_ = sizeof(functor_type); - } + store_size_ = sizeof(functor_type); + } else - { - deleter_(store_.get()); - } + { + deleter_(store_.get()); + } new (store_.get()) functor_type(::std::forward(f)); @@ -201,14 +201,14 @@ class delegate template static delegate from(C* const object_ptr, - R (C::* const method_ptr)(A...)) + R (C::* const method_ptr)(A...)) { return member_pair(object_ptr, method_ptr); } template static delegate from(C const* const object_ptr, - R (C::* const method_ptr)(A...) const) + R (C::* const method_ptr)(A...) const) { return const_member_pair(object_ptr, method_ptr); } @@ -221,7 +221,7 @@ class delegate template static delegate from(C const& object, - R (C::* const method_ptr)(A...) const) + R (C::* const method_ptr)(A...) const) { return const_member_pair(&object, method_ptr); } @@ -262,7 +262,7 @@ class delegate R operator()(A... args) const { - // assert(stub_ptr); +// assert(stub_ptr); return stub_ptr_(object_ptr_, ::std::forward
(args)...); } @@ -303,14 +303,14 @@ class delegate static R method_stub(void* const object_ptr, A&&... args) { return (static_cast(object_ptr)->*method_ptr)( - ::std::forward(args)...); + ::std::forward(args)...); } template static R const_method_stub(void* const object_ptr, A&&... args) { return (static_cast(object_ptr)->*method_ptr)( - ::std::forward(args)...); + ::std::forward(args)...); } template @@ -318,7 +318,7 @@ class delegate template struct is_member_pair< ::std::pair > : std::true_type + R (C::* const)(A...)> > : std::true_type { }; @@ -327,16 +327,16 @@ class delegate template struct is_const_member_pair< ::std::pair > : std::true_type + R (C::* const)(A...) const> > : std::true_type { }; template static typename ::std::enable_if< !(is_member_pair{} || - is_const_member_pair{}), + is_const_member_pair{}), R - >::type + >::type functor_stub(void* const object_ptr, A&&... args) { return (*static_cast(object_ptr))(::std::forward(args)...); @@ -345,13 +345,13 @@ class delegate template static typename ::std::enable_if< is_member_pair{} || - is_const_member_pair{}, + is_const_member_pair{}, R - >::type - functor_stub(void* const object_ptr, A&&... args) + >::type + functor_stub(void* const object_ptr, A&&... args) { return (static_cast(object_ptr)->first->* - static_cast(object_ptr)->second)(::std::forward(args)...); + static_cast(object_ptr)->second)(::std::forward(args)...); } }; @@ -365,7 +365,7 @@ namespace std auto const seed(hash()(d.object_ptr_)); return hash::stub_ptr_type>()( - d.stub_ptr_) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + d.stub_ptr_) + 0x9e3779b9 + (seed << 6) + (seed >> 2); } }; } diff --git a/api/utility/membitmap.hpp b/api/utility/membitmap.hpp index fe22eb1e67..bf8606ced3 100644 --- a/api/utility/membitmap.hpp +++ b/api/utility/membitmap.hpp @@ -23,7 +23,7 @@ * In-memory bitmap implementation * * - **/ +**/ namespace fs { @@ -56,15 +56,15 @@ namespace fs { // each word for (index_t i = 0; i < _size; i++) - if (_data[i] != WORD_MAX) - { - // each bit - for (index_t b = 0; b < CHUNK_SIZE; b++) - if (!(_data[i] & (1 << b))) - { - return i * CHUNK_SIZE + b; - } - } // chunk + if (_data[i] != WORD_MAX) + { + // each bit + for (index_t b = 0; b < CHUNK_SIZE; b++) + if (!(_data[i] & (1 << b))) + { + return i * CHUNK_SIZE + b; + } + } // chunk return -1; } // first_free() diff --git a/api/utility/ringbuffer.hpp b/api/utility/ringbuffer.hpp index 1999811a90..88bd7f9f38 100644 --- a/api/utility/ringbuffer.hpp +++ b/api/utility/ringbuffer.hpp @@ -24,110 +24,110 @@ namespace includeOS { - class RingBuffer - { - enum error_t - { - E_OK = 0, - E_NO_SPACE = -1; - E_WRITE_FAILED = -2; - }; + class RingBuffer + { + enum error_t + { + E_OK = 0, + E_NO_SPACE = -1; + E_WRITE_FAILED = -2; + }; - RingBuffer(int size) - { - this->size = size + 1; - this->start = 0; - this->end = 0; - this->buffer = new char[this->size]; - } - ~RingBuffer() - { - if (this->buffer) - delete[] this->buffer; - } + RingBuffer(int size) + { + this->size = size + 1; + this->start = 0; + this->end = 0; + this->buffer = new char[this->size]; + } + ~RingBuffer() + { + if (this->buffer) + delete[] this->buffer; + } - int write(char* data, int length) - { - if (available_data() == 0) - { - this->start = this->end = 0; - } + int write(char* data, int length) + { + if (available_data() == 0) + { + this->start = this->end = 0; + } - if (length > available_space()) - { - return E_NO_SPACE; - } + if (length > available_space()) + { + return E_NO_SPACE; + } - void* result = memcpy(ends_at(), data, length); - if (result == nullptr) - { - return E_WRITE_FAILED; - } + void* result = memcpy(ends_at(), data, length); + if (result == nullptr) + { + return E_WRITE_FAILED; + } - // commit write - this->end = (this->end + length) % this->size; - // return length written - return length; - } + // commit write + this->end = (this->end + length) % this->size; + // return length written + return length; + } - int read(char* dest, int length) - { - check_debug(amount <= RingBuffer_available_data(buffer), - "Not enough in the buffer: has %d, needs %d", - RingBuffer_available_data(buffer), amount); + int read(char* dest, int length) + { + check_debug(amount <= RingBuffer_available_data(buffer), + "Not enough in the buffer: has %d, needs %d", + RingBuffer_available_data(buffer), amount); - void *result = memcpy(target, RingBuffer_starts_at(buffer), amount); - check(result != NULL, "Failed to write buffer into data."); + void *result = memcpy(target, RingBuffer_starts_at(buffer), amount); + check(result != NULL, "Failed to write buffer into data."); - // commit read - this->start = (this->start + length) % this->size; + // commit read + this->start = (this->start + length) % this->size; - if (this->end == this->start) - { - this->start = this->end = 0; - } + if (this->end == this->start) + { + this->start = this->end = 0; + } - return length; - } + return length; + } -#define RingBuffer_available_data(B) (((B)->end + 1) % (B)->length - (B)->start - 1) -#define RingBuffer_available_space(B) ((B)->length - (B)->end - 1) + #define RingBuffer_available_data(B) (((B)->end + 1) % (B)->length - (B)->start - 1) + #define RingBuffer_available_space(B) ((B)->length - (B)->end - 1) - int available_data() const - { - return (this->end + 1) % this->size - this->start - 1; - } - int available_space() const - { - return this-> - } + int available_data() const + { + return (this->end + 1) % this->size - this->start - 1; + } + int available_space() const + { + return this-> + } - const char* starts_at() const - { - return this->buffer + this->end; - } - const char* ends_at() const - { - return this->buffer + this->end; - } + const char* starts_at() const + { + return this->buffer + this->end; + } + const char* ends_at() const + { + return this->buffer + this->end; + } - bool full() const - { - return available_data() - this->size == 0; - } - bool empty() const - { - return available_data() == 0; - } + bool full() const + { + return available_data() - this->size == 0; + } + bool empty() const + { + return available_data() == 0; + } - private: - int size; - int start; - int end; - char* buffer; - }; + private: + int size; + int start; + int end; + char* buffer; + }; } #endif diff --git a/api/utility/signal.hpp b/api/utility/signal.hpp index 35c672f8f0..c15d4cc269 100644 --- a/api/utility/signal.hpp +++ b/api/utility/signal.hpp @@ -24,42 +24,42 @@ template class signal { public: - //! \brief Callable type of the signal handlers - using handler = std::function; + //! \brief Callable type of the signal handlers + using handler = std::function; - //! \brief Default constructor - explicit signal() = default; + //! \brief Default constructor + explicit signal() = default; - //! \brief Default destructor - ~signal() noexcept = default; + //! \brief Default destructor + ~signal() noexcept = default; - //! \brief Default move constructor - explicit signal(signal&&) noexcept = default; + //! \brief Default move constructor + explicit signal(signal&&) noexcept = default; - //! \brief Default assignment operator - signal& operator=(signal&&) = default; + //! \brief Default assignment operator + signal& operator=(signal&&) = default; - //! \brief Connect a callable object to this signal - void connect(handler&& fn) { - funcs.emplace_back(std::forward(fn)); - } + //! \brief Connect a callable object to this signal + void connect(handler&& fn) { + funcs.emplace_back(std::forward(fn)); + } - //! \brief Emit this signal by executing all connected callable objects - template - void emit(Args&&... args) { - for(auto& fn : funcs) - fn(std::forward(args)...); - } + //! \brief Emit this signal by executing all connected callable objects + template + void emit(Args&&... args) { + for(auto& fn : funcs) + fn(std::forward(args)...); + } private: - // Set of callable objects registered to be called on demand - std::vector funcs; + // Set of callable objects registered to be called on demand + std::vector funcs; - // Avoid copying - signal(signal const&) = delete; + // Avoid copying + signal(signal const&) = delete; - // Avoid assignment - signal& operator=(signal const&) = delete; + // Avoid assignment + signal& operator=(signal const&) = delete; }; //< class signal #endif //< UTILITY_SIGNAL_HPP diff --git a/api/virtio/console.hpp b/api/virtio/console.hpp index 951789bd9b..89b622792d 100644 --- a/api/virtio/console.hpp +++ b/api/virtio/console.hpp @@ -41,7 +41,7 @@ * placed in the receive queue for incoming data and outgoing * characters are placed in the transmit queue. * - **/ +**/ class VirtioCon : public Virtio { @@ -98,7 +98,7 @@ class VirtioCon : public Virtio /** * Handle device IRQ. * Will look for config. changes and service RX/TX queues as necessary. - **/ + **/ void irq_handler(); Virtio::Queue rx; // 0 diff --git a/api/virtio/virtio.hpp b/api/virtio/virtio.hpp index c5affa27b4..4ec99d0cd1 100644 --- a/api/virtio/virtio.hpp +++ b/api/virtio/virtio.hpp @@ -16,17 +16,17 @@ // limitations under the License. /** - @note This virtio implementation was very much inspired by - SanOS, (C) Michael Ringgaard. All due respect. + @note This virtio implementation was very much inspired by + SanOS, (C) Michael Ringgaard. All due respect. - STANDARD: + STANDARD: - We're aiming to become standards compilant according to this one: + We're aiming to become standards compilant according to this one: - Virtio 1.0, OASIS Committee Specification Draft 03 - (http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.html) + Virtio 1.0, OASIS Committee Specification Draft 03 + (http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.html) - In the following abbreviated to Virtio 1.03 or Virtio std. + In the following abbreviated to Virtio 1.03 or Virtio std. */ #pragma once #ifndef VIRTIO_VIRTIO_HPP @@ -63,7 +63,7 @@ /** A simple scatter-gather list used for Queue::enqueue. ( From sanos, virtio.h - probably Linux originally) -*/ + */ struct scatterlist { void* data; int size; @@ -76,21 +76,21 @@ class Virtio // http://docs.oasis-open.org/virtio/virtio/v1.0/csprd01/virtio-v1.0-csprd01.html#x1-860005 // Virtio device types enum virtiotype_t - { - RESERVED = 0, - NIC, - BLOCK, - CONSOLE, - ENTROPY, - BALLOON, - IO_MEM, - RP_MSG, - SCSI_HOST, - T9P, - WLAN, - RP_SERIAL, - CAIF - }; + { + RESERVED = 0, + NIC, + BLOCK, + CONSOLE, + ENTROPY, + BALLOON, + IO_MEM, + RP_MSG, + SCSI_HOST, + T9P, + WLAN, + RP_SERIAL, + CAIF + }; /** Virtio Queue class. */ class Queue @@ -111,11 +111,11 @@ class Virtio le32 len; /* This marks a buffer as continuing via the next field. */ -#define VIRTQ_DESC_F_NEXT 1 + #define VIRTQ_DESC_F_NEXT 1 /* This marks a buffer as device write-only (otherwise device read-only). */ -#define VIRTQ_DESC_F_WRITE 2 + #define VIRTQ_DESC_F_WRITE 2 /* This means the buffer contains a list of buffer descriptors. */ -#define VIRTQ_DESC_F_INDIRECT 4 + #define VIRTQ_DESC_F_INDIRECT 4 /* The flags as indicated above. */ le16 flags; /* Next field if flags & NEXT */ @@ -148,7 +148,7 @@ class Virtio le16 flags; le16 idx; struct virtq_used_elem ring[ /* Queue Size */]; - /*le16 avail_event; Only if VIRTIO_F_EVENT_IDX */ + /*le16 avail_event; Only if VIRTIO_F_EVENT_IDX */ }; @@ -299,7 +299,7 @@ class Virtio /** Indicate which Virtio version (PCI revision ID) is supported. Currently only Legacy is supported (partially the 1.0 standard) - */ + */ static inline bool version_supported(uint16_t i) { return i <= 0; } diff --git a/etc/batch_apply_editorconfig.sh b/etc/batch_apply_editorconfig.sh deleted file mode 100644 index e0fa4ebdef..0000000000 --- a/etc/batch_apply_editorconfig.sh +++ /dev/null @@ -1,9 +0,0 @@ -#! /bin/bash - -SRC=$1 - -for file in `find $SRC \( -not -path "*/cxxabi/*" -not -path "*/STREAM/*" -not -path "*/lest/*" -not -path "*/mod/*" \) -type f \( -name *.cpp -or -name *.hpp -or -name *.inc \)` -do - echo -e "\n >> Formatting $file" - emacs $file -batch --eval '(indent-region (point-min) (point-max) nil)' -f save-buffer -done diff --git a/examples/demo_service/service.cpp b/examples/demo_service/service.cpp index 4b69193b60..7acabb6e33 100644 --- a/examples/demo_service/service.cpp +++ b/examples/demo_service/service.cpp @@ -49,58 +49,58 @@ void Service::start() { auto& server = inet->tcp().bind(80); hw::PIT::instance().onRepeatedTimeout(30s, []{ - printf(" TCP STATUS:\n%s \n", inet->tcp().status().c_str()); - }); + printf(" TCP STATUS:\n%s \n", inet->tcp().status().c_str()); + }); // Add a TCP connection handler - here a hardcoded HTTP-service server.onAccept([](auto conn) -> bool { printf(" @onAccept - Connection attempt from: %s \n", - conn->to_string().c_str()); + conn->to_string().c_str()); return true; // allow all connections - }).onConnect([](auto) { - printf(" @onConnect - Connection successfully established.\n"); + }).onConnect([](auto) { + printf(" @onConnect - Connection successfully established.\n"); - }).onReceive([](auto conn, bool push) { - std::string data = conn->read(1024); - printf(" @onData - PUSH: %d, Data read: \n%s\n", push, data.c_str()); - int color = rand(); - std::stringstream stream; + }).onReceive([](auto conn, bool push) { + std::string data = conn->read(1024); + printf(" @onData - PUSH: %d, Data read: \n%s\n", push, data.c_str()); + int color = rand(); + std::stringstream stream; - /* HTML Fonts */ - std::string ubuntu_medium = "font-family: \'Ubuntu\', sans-serif; font-weight: 500; "; - std::string ubuntu_normal = "font-family: \'Ubuntu\', sans-serif; font-weight: 400; "; - std::string ubuntu_light = "font-family: \'Ubuntu\', sans-serif; font-weight: 300; "; + /* HTML Fonts */ + std::string ubuntu_medium = "font-family: \'Ubuntu\', sans-serif; font-weight: 500; "; + std::string ubuntu_normal = "font-family: \'Ubuntu\', sans-serif; font-weight: 400; "; + std::string ubuntu_light = "font-family: \'Ubuntu\', sans-serif; font-weight: 300; "; - /* HTML */ - stream << "" - << "" - << "" - << "

> 8) << "\">" - << "IncludeOS

" - << "

Now speaks TCP!

" - // .... generate more dynamic content - << "

...and can improvise http. With limitations of course, but it's been easier than expected so far

" - << "

© 2015, Oslo and Akershus University College of Applied Sciences
" - << "\n"; + /* HTML */ + stream << "" + << "" + << "" + << "

> 8) << "\">" + << "IncludeOS

" + << "

Now speaks TCP!

" + // .... generate more dynamic content + << "

...and can improvise http. With limitations of course, but it's been easier than expected so far

" + << "

© 2015, Oslo and Akershus University College of Applied Sciences
" + << "\n"; - /* HTTP-header */ - std::string html = stream.str(); - std::string header="HTTP/1.1 200 OK \n " \ - "Date: Mon, 01 Jan 1970 00:00:01 GMT \n" \ - "Server: IncludeOS prototype 4.0 \n" \ - "Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT \n" \ - "Content-Type: text/html; charset=UTF-8 \n" \ - "Content-Length: "+std::to_string(html.size())+"\n" \ - "Accept-Ranges: bytes\n" \ - "Connection: close\n\n"; + /* HTTP-header */ + std::string html = stream.str(); + std::string header="HTTP/1.1 200 OK \n " \ + "Date: Mon, 01 Jan 1970 00:00:01 GMT \n" \ + "Server: IncludeOS prototype 4.0 \n" \ + "Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT \n" \ + "Content-Type: text/html; charset=UTF-8 \n" \ + "Content-Length: "+std::to_string(html.size())+"\n" \ + "Accept-Ranges: bytes\n" \ + "Connection: close\n\n"; - std::string output{header + html}; - conn->write(output.data(), output.size()); + std::string output{header + html}; + conn->write(output.data(), output.size()); - }).onDisconnect([](auto, auto reason) { - printf(" @onDisconnect - Reason: %s \n", reason.to_string().c_str()); - }); + }).onDisconnect([](auto, auto reason) { + printf(" @onDisconnect - Reason: %s \n", reason.to_string().c_str()); + }); printf("*** TEST SERVICE STARTED *** \n"); } diff --git a/examples/tcp/service.cpp b/examples/tcp/service.cpp index 610a7edebf..f944aa6fb2 100644 --- a/examples/tcp/service.cpp +++ b/examples/tcp/service.cpp @@ -16,16 +16,16 @@ // limitations under the License. /* - An example to show incoming and outgoing TCP Connections. - In this example, IncludeOS is listening on port 80. + An example to show incoming and outgoing TCP Connections. + In this example, IncludeOS is listening on port 80. - Data received on port 80 will be redirected to a - outgoing connection to a (in this case) python server (server.py) + Data received on port 80 will be redirected to a + outgoing connection to a (in this case) python server (server.py) - Data received from the python server connection - will be redirected back to the client. + Data received from the python server connection + will be redirected back to the client. - To try it out, use netcat to connect to this IncludeOS instance. + To try it out, use netcat to connect to this IncludeOS instance. */ #include @@ -43,19 +43,19 @@ net::TCP::Socket python_server{ {{10,0,2,2}} , 1337}; // Called when data is received on client (incoming connection) void handle_client_on_receive(Connection_ptr client, Connection_ptr python) { - // Read the request from our client - std::string request = client->read(1024); - printf("Received [Client]: %s\n", request.c_str()); - // Write the request to our python server - python->write(request); + // Read the request from our client + std::string request = client->read(1024); + printf("Received [Client]: %s\n", request.c_str()); + // Write the request to our python server + python->write(request); } // Called when data is received on python (outgoing connection) void handle_python_on_receive(Connection_ptr python, Connection_ptr client) { - // Read the response from our python server - std::string response = python->read(1024); - // Write response to our client - client->write(response); + // Read the response from our python server + std::string response = python->read(1024); + // Write response to our client + client->write(response); } void Service::start() { @@ -74,41 +74,41 @@ void Service::start() { // Set up a TCP server on port 80 auto& server = inet->tcp().bind(80); inet->dhclient()->on_config([&server](auto&) { - printf("Server IP updated: %s\n", server.local().to_string().c_str()); - }); + printf("Server IP updated: %s\n", server.local().to_string().c_str()); + }); printf("Server listening: %s \n", server.local().to_string().c_str()); // When someone connects to our server server.onConnect([](Connection_ptr client) { - printf("Connected [Client]: %s\n", client->to_string().c_str()); - // Make an outgoing connection to our python server - auto outgoing = inet->tcp().connect(python_server); - // When outgoing connection to python sever is established - outgoing->onConnect([client](Connection_ptr python) { - printf("Connected [Python]: %s\n", python->to_string().c_str()); + printf("Connected [Client]: %s\n", client->to_string().c_str()); + // Make an outgoing connection to our python server + auto outgoing = inet->tcp().connect(python_server); + // When outgoing connection to python sever is established + outgoing->onConnect([client](Connection_ptr python) { + printf("Connected [Python]: %s\n", python->to_string().c_str()); - // Setup handlers for when data is received on client and python connection - // When client has data to be read - client->onReceive([python](Connection_ptr client, bool) { - handle_client_on_receive(client, python); - }); + // Setup handlers for when data is received on client and python connection + // When client has data to be read + client->onReceive([python](Connection_ptr client, bool) { + handle_client_on_receive(client, python); + }); - // When python server has data to be read - python->onReceive([client](Connection_ptr python, bool) { - handle_python_on_receive(python, client); - }); + // When python server has data to be read + python->onReceive([client](Connection_ptr python, bool) { + handle_python_on_receive(python, client); + }); - // When client is disconnecting - client->onDisconnect([python](Connection_ptr, Disconnect reason) { - printf("Disconnected [Client]: %s\n", reason.to_string().c_str()); - python->close(); - }); + // When client is disconnecting + client->onDisconnect([python](Connection_ptr, Disconnect reason) { + printf("Disconnected [Client]: %s\n", reason.to_string().c_str()); + python->close(); + }); - // When python is disconnecting - python->onDisconnect([client](Connection_ptr, Disconnect reason) { - printf("Disconnected [Python]: %s\n", reason.to_string().c_str()); - client->close(); - }); - }); // << onConnect (outgoing (python)) - }); // << onConnect (client) + // When python is disconnecting + python->onDisconnect([client](Connection_ptr, Disconnect reason) { + printf("Disconnected [Python]: %s\n", reason.to_string().c_str()); + client->close(); + }); + }); // << onConnect (outgoing (python)) + }); // << onConnect (client) } diff --git a/src/crt/cxx_abi.cpp b/src/crt/cxx_abi.cpp index 40617afe7f..911ead7b00 100644 --- a/src/crt/cxx_abi.cpp +++ b/src/crt/cxx_abi.cpp @@ -22,7 +22,7 @@ * This header is for instantiating and implementing * missing functionality gluing libc++ to the kernel * - **/ +**/ #include extern "C" diff --git a/src/crt/mman.cpp b/src/crt/mman.cpp index 23f99aef44..d82a15511d 100644 --- a/src/crt/mman.cpp +++ b/src/crt/mman.cpp @@ -20,15 +20,15 @@ struct mmap_entry_t std::map _mmap_entries; void* mmap(void* addr, size_t length, - int prot, int flags, - int fd, off_t offset) + int prot, int flags, + int fd, off_t offset) { // invalid or misaligned length if (length == 0 || (length & 4095) != 0) - { - errno = EINVAL; - return MAP_FAILED; - } + { + errno = EINVAL; + return MAP_FAILED; + } // associate some VA space with open file @fd // for now just allocate page-aligned on heap @@ -53,15 +53,15 @@ int munmap(void* addr, size_t length) { auto it = _mmap_entries.find(addr); if (it != _mmap_entries.end()) - { - // - assert(it->second.length == length); + { + // + assert(it->second.length == length); - // free and remove the entry - free(it->second.addr); - _mmap_entries.erase(it); - return 0; - } + // free and remove the entry + free(it->second.addr); + _mmap_entries.erase(it); + return 0; + } errno = EINVAL; return -1; } diff --git a/src/debug/ircd.cpp b/src/debug/ircd.cpp index 84068f8a8c..f4ca803615 100644 --- a/src/debug/ircd.cpp +++ b/src/debug/ircd.cpp @@ -12,9 +12,9 @@ void Client::split_message(const std::string& msg) printf("[Client]: "); for (auto& str : vec) - { - printf("[%s]", str.c_str()); - } + { + printf("[%s]", str.c_str()); + } printf("\n"); // ignore empty messages if (vec.size() == 0) return; @@ -25,47 +25,47 @@ void Client::split_message(const std::string& msg) void Client::read(const char* buf, size_t len) { while (len > 0) - { - int search = -1; + { + int search = -1; - for (size_t i = 0; i < len; i++) - if (buf[i] == 13 || buf[i] == 10) - { - search = i; break; - } - // not found: - if (search == -1) - { - // append entire buffer - buffer.append(buf, len); - break; - } - else - { - // found CR LF: - if (search != 0) - { - // append to clients buffer - buffer.append(buf, search); + for (size_t i = 0; i < len; i++) + if (buf[i] == 13 || buf[i] == 10) + { + search = i; break; + } + // not found: + if (search == -1) + { + // append entire buffer + buffer.append(buf, len); + break; + } + else + { + // found CR LF: + if (search != 0) + { + // append to clients buffer + buffer.append(buf, search); - // move forward in socket buffer - buf += search; - // decrease len - len -= search; - } - else - { - buf++; len--; - } + // move forward in socket buffer + buf += search; + // decrease len + len -= search; + } + else + { + buf++; len--; + } - // parse message - if (buffer.size()) - { - split_message(buffer); - buffer.clear(); - } - } + // parse message + if (buffer.size()) + { + split_message(buffer); + buffer.clear(); + } } + } } void Client::send(uint16_t numeric, std::string text) @@ -94,59 +94,59 @@ void Client::send(std::string text) void Client::handle(const std::string&, const std::vector& msg) { -#define TK_CAP "CAP" -#define TK_PASS "PASS" -#define TK_NICK "NICK" -#define TK_USER "USER" + #define TK_CAP "CAP" + #define TK_PASS "PASS" + #define TK_NICK "NICK" + #define TK_USER "USER" const std::string& cmd = msg[0]; if (this->is_reg() == false) + { + if (cmd == TK_CAP) + { + // ignored completely + } + else if (cmd == TK_PASS) { - if (cmd == TK_CAP) - { - // ignored completely - } - else if (cmd == TK_PASS) - { - if (msg.size() > 1) - { - this->passw = msg[1]; - } - else - { - send(ERR_NEEDMOREPARAMS, cmd + " :Not enough parameters"); - } - } - else if (cmd == TK_NICK) - { - if (msg.size() > 1) - { - this->nick = msg[1]; - welcome(regis | 1); - } - else - { - send(ERR_NEEDMOREPARAMS, cmd + " :Not enough parameters"); - } - } - else if (cmd == TK_USER) - { - if (msg.size() > 1) - { - this->user = msg[1]; - welcome(regis | 2); - } - else - { - send(ERR_NEEDMOREPARAMS, cmd + " :Not enough parameters"); - } - } + if (msg.size() > 1) + { + this->passw = msg[1]; + } else - { - send(ERR_NOSUCHCMD, cmd + " :Unknown command"); - } + { + send(ERR_NEEDMOREPARAMS, cmd + " :Not enough parameters"); + } } + else if (cmd == TK_NICK) + { + if (msg.size() > 1) + { + this->nick = msg[1]; + welcome(regis | 1); + } + else + { + send(ERR_NEEDMOREPARAMS, cmd + " :Not enough parameters"); + } + } + else if (cmd == TK_USER) + { + if (msg.size() > 1) + { + this->user = msg[1]; + welcome(regis | 2); + } + else + { + send(ERR_NEEDMOREPARAMS, cmd + " :Not enough parameters"); + } + } + else + { + send(ERR_NOSUCHCMD, cmd + " :Unknown command"); + } + } } #define RPL_WELCOME 1 @@ -162,15 +162,15 @@ void Client::welcome(uint8_t newreg) regis = newreg; // not registered before, but registered now if (!regged && is_reg()) - { - printf("* Registered: %s\n", nickuserhost().c_str()); - send(RPL_WELCOME, ":Welcome to the Internet Relay Network, " + nickuserhost()); - send(RPL_YOURHOST, ":Your host is " + SERVER_NAME + ", running v1.0"); - } + { + printf("* Registered: %s\n", nickuserhost().c_str()); + send(RPL_WELCOME, ":Welcome to the Internet Relay Network, " + nickuserhost()); + send(RPL_YOURHOST, ":Your host is " + SERVER_NAME + ", running v1.0"); + } else if (oldreg == 0) - { - auth_notice(); - } + { + auth_notice(); + } } void Client::auth_notice() { diff --git a/src/debug/ircsplit.hpp b/src/debug/ircsplit.hpp index e195f79e09..f9a572a962 100644 --- a/src/debug/ircsplit.hpp +++ b/src/debug/ircsplit.hpp @@ -10,40 +10,40 @@ split(const std::string& text, std::string& source) if (text.empty()) return retv; // check for source if (text[0] == ':') - { - x = text.find(" ", 1); - source = text.substr(x); - // early return for source-only msg - if (x == std::string::npos) return retv; - p = x+1; - } + { + x = text.find(" ", 1); + source = text.substr(x); + // early return for source-only msg + if (x == std::string::npos) return retv; + p = x+1; + } // parse remainder do - { - x = text.find(" ", p+1); - size_t y = text.find(":", x+1); // find last param + { + x = text.find(" ", p+1); + size_t y = text.find(":", x+1); // find last param - if (y == x+1) - { - // single argument - retv.push_back(text.substr(p, x-p)); - // ending text argument - retv.push_back(text.substr(y+1)); - break; - } - else if (x != std::string::npos) - { - // single argument - retv.push_back(text.substr(p, x-p)); - } - else - { - // last argument - retv.push_back(text.substr(p)); - } - p = x+1; + if (y == x+1) + { + // single argument + retv.push_back(text.substr(p, x-p)); + // ending text argument + retv.push_back(text.substr(y+1)); + break; + } + else if (x != std::string::npos) + { + // single argument + retv.push_back(text.substr(p, x-p)); + } + else + { + // last argument + retv.push_back(text.substr(p)); + } + p = x+1; - } while (x != std::string::npos); + } while (x != std::string::npos); return retv; } diff --git a/src/debug/test_disk.cpp b/src/debug/test_disk.cpp index 124d4b4fd9..9ef2416bb7 100644 --- a/src/debug/test_disk.cpp +++ b/src/debug/test_disk.cpp @@ -23,106 +23,106 @@ void Service::start() // mount first valid partition (auto-detect and mount) disk->mount( // or specify partition explicitly in parameter - [] (fs::error_t err) - { - if (err) - { - printf("Could not mount filesystem\n"); - return; - } - // get a reference to the mounted filesystem - auto& fs = disk->fs(); + [] (fs::error_t err) + { + if (err) + { + printf("Could not mount filesystem\n"); + return; + } + // get a reference to the mounted filesystem + auto& fs = disk->fs(); - // check contents of disk - auto dirents = fs::new_shared_vector(); - err = fs.ls("/", dirents); - if (err) - printf("Could not list '/' directory\n"); - else - for (auto& e : *dirents) - { - printf("%s: %s\t of size %llu bytes (CL: %llu)\n", - e.type_string().c_str(), e.name().c_str(), e.size, e.block); - } + // check contents of disk + auto dirents = fs::new_shared_vector(); + err = fs.ls("/", dirents); + if (err) + printf("Could not list '/' directory\n"); + else + for (auto& e : *dirents) + { + printf("%s: %s\t of size %llu bytes (CL: %llu)\n", + e.type_string().c_str(), e.name().c_str(), e.size, e.block); + } - auto ent = fs.stat("/test.txt"); - // validate the stat call - if (ent.is_valid()) - { - // read specific area of file - auto buf = fs.read(ent, 1032, 65); - std::string contents((const char*) buf.buffer.get(), buf.len); - printf("[%s contents (%llu bytes)]:\n%s\n[end]\n\n", - ent.name().c_str(), buf.len, contents.c_str()); + auto ent = fs.stat("/test.txt"); + // validate the stat call + if (ent.is_valid()) + { + // read specific area of file + auto buf = fs.read(ent, 1032, 65); + std::string contents((const char*) buf.buffer.get(), buf.len); + printf("[%s contents (%llu bytes)]:\n%s\n[end]\n\n", + ent.name().c_str(), buf.len, contents.c_str()); - } - else - { - printf("Invalid entity for /test.txt\n"); - } - return; + } + else + { + printf("Invalid entity for /test.txt\n"); + } + return; - disk->fs().ls("/", - [] (fs::error_t err, auto ents) - { - if (err) - { - printf("Could not list '/' directory\n"); - return; - } + disk->fs().ls("/", + [] (fs::error_t err, auto ents) + { + if (err) + { + printf("Could not list '/' directory\n"); + return; + } - for (auto& e : *ents) - { - printf("%s: %s\t of size %llu bytes (CL: %llu)\n", - e.type_string().c_str(), e.name().c_str(), e.size, e.block); + for (auto& e : *ents) + { + printf("%s: %s\t of size %llu bytes (CL: %llu)\n", + e.type_string().c_str(), e.name().c_str(), e.size, e.block); - if (e.is_file()) - { - printf("*** Attempting to read: %s\n", e.name().c_str()); - disk->fs().readFile(e, - [e] (fs::error_t err, fs::buffer_t buffer, size_t len) - { - if (err) - { - printf("Failed to read file %s!\n", - e.name().c_str()); - return; - } + if (e.is_file()) + { + printf("*** Attempting to read: %s\n", e.name().c_str()); + disk->fs().readFile(e, + [e] (fs::error_t err, fs::buffer_t buffer, size_t len) + { + if (err) + { + printf("Failed to read file %s!\n", + e.name().c_str()); + return; + } - std::string contents((const char*) buffer.get(), len); - printf("[%s contents]:\n%s\nEOF\n\n", - e.name().c_str(), contents.c_str()); - }); - } - } - }); + std::string contents((const char*) buffer.get(), len); + printf("[%s contents]:\n%s\nEOF\n\n", + e.name().c_str(), contents.c_str()); + }); + } + } + }); - disk->fs().stat("/test.txt", - [] (fs::error_t err, const auto& e) - { - if (err) - { - printf("Could not stat %s\n", e.name().c_str()); - return; - } + disk->fs().stat("/test.txt", + [] (fs::error_t err, const auto& e) + { + if (err) + { + printf("Could not stat %s\n", e.name().c_str()); + return; + } - printf("stat: /test.txt is a %s on cluster %llu\n", - e.type_string().c_str(), e.block); - }); - disk->fs().stat("/Sample Pictures/Koala.jpg", - [] (fs::error_t err, const auto& e) - { - if (err) - { - printf("Could not stat %s\n", e.name().c_str()); - return; - } + printf("stat: /test.txt is a %s on cluster %llu\n", + e.type_string().c_str(), e.block); + }); + disk->fs().stat("/Sample Pictures/Koala.jpg", + [] (fs::error_t err, const auto& e) + { + if (err) + { + printf("Could not stat %s\n", e.name().c_str()); + return; + } - printf("stat: %s is a %s on cluster %llu\n", - e.name().c_str(), e.type_string().c_str(), e.block); - }); + printf("stat: %s is a %s on cluster %llu\n", + e.name().c_str(), e.type_string().c_str(), e.block); + }); - }); // disk->auto_detect() + }); // disk->auto_detect() printf("*** TEST SERVICE STARTED *** \n"); } @@ -130,16 +130,16 @@ void Service::start() void list_partitions(decltype(disk) disk) { disk->partitions( - [] (fs::error_t err, auto& parts) - { - if (err) - { - printf("Failed to retrieve volumes on disk\n"); - return; - } + [] (fs::error_t err, auto& parts) + { + if (err) + { + printf("Failed to retrieve volumes on disk\n"); + return; + } - for (auto& part : parts) - printf("[Partition] '%s' at LBA %u\n", - part.name().c_str(), part.lba()); - }); + for (auto& part : parts) + printf("[Partition] '%s' at LBA %u\n", + part.name().c_str(), part.lba()); + }); } diff --git a/src/debug/test_ipv6.cpp b/src/debug/test_ipv6.cpp index 9bb1b0d917..7fe76ff46d 100644 --- a/src/debug/test_ipv6.cpp +++ b/src/debug/test_ipv6.cpp @@ -40,9 +40,9 @@ void Service::start() // basic UDP service net::Inet::ifconfig( - net::ETH0, - ip4, {{255, 255, 255, 0}}, - ip6); + net::ETH0, + ip4, {{255, 255, 255, 0}}, + ip6); net::Inet* inet = net::Inet::up(); @@ -64,37 +64,37 @@ void Service::start() // basic UDP service static const int UDP_PORT = 64; inet->udp6_listen(UDP_PORT, - [=] (std::shared_ptr& pckt) -> int - { - printf("Received UDP6 packet from %s to my listener on port %d\n", - pckt->src().str().c_str(), pckt->dst_port()); + [=] (std::shared_ptr& pckt) -> int + { + printf("Received UDP6 packet from %s to my listener on port %d\n", + pckt->src().str().c_str(), pckt->dst_port()); - std::string data((const char*) pckt->data(), pckt->data_length()); + std::string data((const char*) pckt->data(), pckt->data_length()); - printf("Contents (len=%d):\n%s\n", pckt->data_length(), data.c_str()); + printf("Contents (len=%d):\n%s\n", pckt->data_length(), data.c_str()); - // unfortunately, - // copy the ether src field of the incoming packet - net::Ethernet::addr ether_src = - ((net::Ethernet::header*) pckt->buffer())->src; + // unfortunately, + // copy the ether src field of the incoming packet + net::Ethernet::addr ether_src = + ((net::Ethernet::header*) pckt->buffer())->src; - // create a response packet with destination [ether_src] dst() - std::shared_ptr newpacket = - inet->udp6_create(ether_src, pckt->dst(), UDP_PORT); + // create a response packet with destination [ether_src] dst() + std::shared_ptr newpacket = + inet->udp6_create(ether_src, pckt->dst(), UDP_PORT); - const char* text = "This is the response packet!"; - // copy text into UDP data section - memcpy( newpacket->data(), text, strlen(text) ); - // set new length - newpacket->set_length(strlen(text)); + const char* text = "This is the response packet!"; + // copy text into UDP data section + memcpy( newpacket->data(), text, strlen(text) ); + // set new length + newpacket->set_length(strlen(text)); - // generate checksum for packet before sending - newpacket->gen_checksum(); + // generate checksum for packet before sending + newpacket->gen_checksum(); - // ship it to the ether - inet->udp6_send(newpacket); - return -1; - } - ); + // ship it to the ether + inet->udp6_send(newpacket); + return -1; + } + ); } diff --git a/src/debug/test_service.cpp b/src/debug/test_service.cpp index 2553927806..c8c14099b7 100644 --- a/src/debug/test_service.cpp +++ b/src/debug/test_service.cpp @@ -35,19 +35,19 @@ void Service::start() hw::Nic& eth0 = hw::Dev::eth<0,VirtioNet>(); inet = std::make_unique >(eth0); inet->network_config( - {{ 10,0,0,42 }}, // IP - {{ 255,255,255,0 }}, // Netmask - {{ 10,0,0,1 }}, // Gateway - {{ 8,8,8,8 }} ); // DNS + {{ 10,0,0,42 }}, // IP + {{ 255,255,255,0 }}, // Netmask + {{ 10,0,0,1 }}, // Gateway + {{ 8,8,8,8 }} ); // DNS /* - auto& tcp = inet->tcp(); - auto& server = tcp.bind(6667); // IRCd default port - server.onConnect( - [] (auto csock) - { + auto& tcp = inet->tcp(); + auto& server = tcp.bind(6667); // IRCd default port + server.onConnect( + [] (auto csock) + { printf("*** Received connection from %s\n", - csock->remote().to_string().c_str()); + csock->remote().to_string().c_str()); /// create client /// size_t index = clients.size(); @@ -59,22 +59,22 @@ void Service::start() csock->onReceive( [&client] (auto conn, bool) { - char buffer[1024]; - size_t bytes = conn->read(buffer, sizeof(buffer)); + char buffer[1024]; + size_t bytes = conn->read(buffer, sizeof(buffer)); - client.read(buffer, bytes); + client.read(buffer, bytes); }); .onDisconnect( [&client] (auto conn, std::string) { - // remove client from various lists - client.remove(); - /// inform others about disconnect - //client.bcast(TK_QUIT, "Disconnected"); + // remove client from various lists + client.remove(); + /// inform others about disconnect + //client.bcast(TK_QUIT, "Disconnected"); }); - });*/ + });*/ /// terminal /// auto& serial = hw::Serial::port<1> (); @@ -82,12 +82,12 @@ void Service::start() term = std::make_unique (serial); // add 'ifconfig' command term->add( - "ifconfig", "Show information about interfaces", - [] (const std::vector&) -> int - { - term->write("%s\r\n", inet->tcp().status().c_str()); - return 0; - }); + "ifconfig", "Show information about interfaces", + [] (const std::vector&) -> int + { + term->write("%s\r\n", inet->tcp().status().c_str()); + return 0; + }); /// terminal /// printf("*** TEST SERVICE STARTED *** \n"); diff --git a/src/debug/test_tcp.cpp b/src/debug/test_tcp.cpp index f42594c305..4318d649f4 100644 --- a/src/debug/test_tcp.cpp +++ b/src/debug/test_tcp.cpp @@ -41,18 +41,18 @@ void Service::start() { auto& server = inet->tcp().bind(80); hw::PIT::instance().onTimeout(5s, [server]{ - printf("Server is running: %s \n", server.to_string().c_str()); - }); + printf("Server is running: %s \n", server.to_string().c_str()); + }); server.onPacketReceived([](auto conn, auto packet) { - printf(" Received: %s\n", packet->to_string().c_str()); + printf(" Received: %s\n", packet->to_string().c_str()); - }).onPacketDropped([](auto packet, std::string reason) { - printf(" Dropped: %s - Reason: %s \n", packet->to_string().c_str(), reason.c_str()); + }).onPacketDropped([](auto packet, std::string reason) { + printf(" Dropped: %s - Reason: %s \n", packet->to_string().c_str(), reason.c_str()); - }).onReceive([](auto conn, bool) { - conn->write("Hey"); - }).onConnect([](auto conn) { - printf(" Connected.\n"); - }); + }).onReceive([](auto conn, bool) { + conn->write("Hey"); + }).onConnect([](auto conn) { + printf(" Connected.\n"); + }); } diff --git a/src/fs/disk.cpp b/src/fs/disk.cpp index f6e8afa24a..c7828319c5 100644 --- a/src/fs/disk.cpp +++ b/src/fs/disk.cpp @@ -21,131 +21,131 @@ namespace fs { - Disk::Disk(hw::IDiskDevice& dev) - : device {dev} +Disk::Disk(hw::IDiskDevice& dev) + : device {dev} { // for now we can only assume FAT, anyways filesys.reset(new FAT(device)); } - void Disk::partitions(on_parts_func func) { +void Disk::partitions(on_parts_func func) { - /** Read Master Boot Record (sector 0) */ - device.read(0, - [this, func] (hw::IDiskDevice::buffer_t data) - { - std::vector parts; + /** Read Master Boot Record (sector 0) */ + device.read(0, + [this, func] (hw::IDiskDevice::buffer_t data) + { + std::vector parts; - if (!data) { - func(true, parts); - return; - } + if (!data) { + func(true, parts); + return; + } - // First sector is the Master Boot Record - auto* mbr =(MBR::mbr*) data.get(); + // First sector is the Master Boot Record + auto* mbr =(MBR::mbr*) data.get(); - for (int i {0}; i < 4; ++i) { - // all the partitions are offsets to potential Volume Boot Records - parts.emplace_back( - mbr->part[i].flags, //< flags - mbr->part[i].type, //< id - mbr->part[i].lba_begin, //< LBA - mbr->part[i].sectors); - } + for (int i {0}; i < 4; ++i) { + // all the partitions are offsets to potential Volume Boot Records + parts.emplace_back( + mbr->part[i].flags, //< flags + mbr->part[i].type, //< id + mbr->part[i].lba_begin, //< LBA + mbr->part[i].sectors); + } - func(no_error, parts); - }); - } + func(no_error, parts); + }); +} - void Disk::mount(on_mount_func func) +void Disk::mount(on_mount_func func) +{ + device.read(0, + [this, func] (hw::IDiskDevice::buffer_t data) { - device.read(0, - [this, func] (hw::IDiskDevice::buffer_t data) - { - if (!data) { - // TODO: error-case for unable to read MBR - mount(INVALID, func); - return; - } + if (!data) { + // TODO: error-case for unable to read MBR + mount(INVALID, func); + return; + } - // auto-detect FAT on MBR: - auto* mbr = (MBR::mbr*) data.get(); - MBR::BPB* bpb = mbr->bpb(); + // auto-detect FAT on MBR: + auto* mbr = (MBR::mbr*) data.get(); + MBR::BPB* bpb = mbr->bpb(); - if (bpb->bytes_per_sector >= 512 - && bpb->fa_tables != 0 - && bpb->signature != 0) // check MBR signature too - { - // we have FAT on MBR (and we are assuming mount FAT) - mount(MBR, func); - return; - } + if (bpb->bytes_per_sector >= 512 + && bpb->fa_tables != 0 + && bpb->signature != 0) // check MBR signature too + { + // we have FAT on MBR (and we are assuming mount FAT) + mount(MBR, func); + return; + } - // go through partition list - for (int i = 0; i < 4; i++) - { - if (mbr->part[i].type != 0 // 0 is unused partition - && mbr->part[i].lba_begin != 0 // 0 is MBR anyways - && mbr->part[i].sectors != 0) // 0 means no size, so... - { - mount((partition_t) (VBR1 + i), func); - return; - } - } + // go through partition list + for (int i = 0; i < 4; i++) + { + if (mbr->part[i].type != 0 // 0 is unused partition + && mbr->part[i].lba_begin != 0 // 0 is MBR anyways + && mbr->part[i].sectors != 0) // 0 means no size, so... + { + mount((partition_t) (VBR1 + i), func); + return; + } + } - // no partition was found (TODO: extended partitions) - mount(INVALID, func); - return; - }); - } + // no partition was found (TODO: extended partitions) + mount(INVALID, func); + return; + }); +} - void Disk::mount(partition_t part, on_mount_func func) { +void Disk::mount(partition_t part, on_mount_func func) { - if (part == INVALID) - { - // Something bad happened maybe in auto-detect - // Either way, no partition was found - func(true); - return; - } - else if (part == MBR) - { - // For the MBR case, all we need to do is mount on sector 0 - fs().mount(0, device.size(), func); + if (part == INVALID) + { + // Something bad happened maybe in auto-detect + // Either way, no partition was found + func(true); + return; + } + else if (part == MBR) + { + // For the MBR case, all we need to do is mount on sector 0 + fs().mount(0, device.size(), func); + } + else + { + /** + * Otherwise, we will have to read the LBA offset + * of the partition to be mounted + */ + device.read(0, + [this, part, func] (hw::IDiskDevice::buffer_t data) + { + if (!data) { + // TODO: error-case for unable to read MBR + func(true); + return; } - else - { - /** - * Otherwise, we will have to read the LBA offset - * of the partition to be mounted - */ - device.read(0, - [this, part, func] (hw::IDiskDevice::buffer_t data) - { - if (!data) { - // TODO: error-case for unable to read MBR - func(true); - return; - } - auto* mbr = (MBR::mbr*) data.get(); //< Treat data as MBR - auto pint = static_cast(part - 1); //< Treat VBR1 as index 0 etc. + auto* mbr = (MBR::mbr*) data.get(); //< Treat data as MBR + auto pint = static_cast(part - 1); //< Treat VBR1 as index 0 etc. - /** Get LBA from selected partition */ - auto lba_base = mbr->part[pint].lba_begin; - auto lba_size = mbr->part[pint].sectors; + /** Get LBA from selected partition */ + auto lba_base = mbr->part[pint].lba_begin; + auto lba_size = mbr->part[pint].sectors; - /** - * Call the filesystems mount function - * with lba_begin as base address - */ - fs().mount(lba_base, lba_size, func); - }); - } + /** + * Call the filesystems mount function + * with lba_begin as base address + */ + fs().mount(lba_base, lba_size, func); + }); } +} - std::string Disk::Partition::name() const { - return MBR::id_to_name(id); - } +std::string Disk::Partition::name() const { + return MBR::id_to_name(id); +} } //< namespace fs diff --git a/src/fs/ext4.cpp b/src/fs/ext4.cpp index a361e72173..7a6e26cd9b 100644 --- a/src/fs/ext4.cpp +++ b/src/fs/ext4.cpp @@ -19,26 +19,26 @@ namespace fs void EXT4::mount(uint64_t start, uint64_t size, on_mount_func on_mount) { printf("Superblock: %u bytes, Block group desc: %u bytes\n", - sizeof(superblock), sizeof(group_desc)); + sizeof(superblock), sizeof(group_desc)); assert(sizeof(superblock) == 1024); assert(sizeof(group_desc) == 64); printf("Inode table: %u\n", - sizeof(inode_table)); + sizeof(inode_table)); // read Master Boot Record (sector 0) device.read(start, - [this, start, size, on_mount] (buffer_t data) - { - auto* mbr = (MBR::mbr*) data.get(); - assert(mbr != nullptr); + [this, start, size, on_mount] (buffer_t data) + { + auto* mbr = (MBR::mbr*) data.get(); + assert(mbr != nullptr); - /// now what? - printf("Mounting EXT4 from LBA %llu to %llu\n", - start, size); + /// now what? + printf("Mounting EXT4 from LBA %llu to %llu\n", + start, size); - init(data.get()); - }); + init(data.get()); + }); } diff --git a/src/fs/fat.cpp b/src/fs/fat.cpp index 72a126a5de..361c5dfc81 100644 --- a/src/fs/fat.cpp +++ b/src/fs/fat.cpp @@ -15,8 +15,8 @@ #define unlikely(x) __builtin_expect(!!(x), 0) inline std::string trim_right_copy( - const std::string& s, - const std::string& delimiters = " \f\n\r\t\v" ) + const std::string& s, + const std::string& delimiters = " \f\n\r\t\v" ) { return s.substr( 0, s.find_last_not_of( delimiters ) + 1 ); } @@ -37,11 +37,11 @@ namespace fs MBR::BPB* bpb = mbr->bpb(); this->sector_size = bpb->bytes_per_sector; if (unlikely(this->sector_size < 512)) - { - printf("Invalid sector size (%u) for FAT32 partition\n", sector_size); - printf("Are you mounting the correct partition?\n"); - panic("FAT32: Invalid sector size"); - } + { + printf("Invalid sector size (%u) for FAT32 partition\n", sector_size); + printf("Are you mounting the correct partition?\n"); + panic("FAT32: Invalid sector size"); + } // Let's begin our incantation // To drive out the demons of old DOS we have to read some PBP values @@ -70,7 +70,7 @@ namespace fs // sectors per FAT (not sure about the rule here) this->sectors_per_fat = bpb->sectors_per_fat; if (this->sectors_per_fat == 0) - this->sectors_per_fat = *(uint32_t*) &mbr->boot[25]; + this->sectors_per_fat = *(uint32_t*) &mbr->boot[25]; // root dir sectors from root entries this->root_dir_sectors = ((bpb->root_entries * 32) + (sector_size - 1)) / sector_size; // calculate index of first data sector @@ -92,28 +92,28 @@ namespace fs // now that we're here, we can determine the actual FAT type // using the official method: if (this->clusters < 4085) - { - this->fat_type = FAT::T_FAT12; - this->root_cluster = 2; - debug("The image is type FAT12, with %u clusters\n", this->clusters); - } + { + this->fat_type = FAT::T_FAT12; + this->root_cluster = 2; + debug("The image is type FAT12, with %u clusters\n", this->clusters); + } else if (this->clusters < 65525) - { - this->fat_type = FAT::T_FAT16; - this->root_cluster = 2; - debug("The image is type FAT16, with %u clusters\n", this->clusters); - } + { + this->fat_type = FAT::T_FAT16; + this->root_cluster = 2; + debug("The image is type FAT16, with %u clusters\n", this->clusters); + } else - { - this->fat_type = FAT::T_FAT32; - this->root_cluster = *(uint32_t*) &mbr->boot[33]; - this->root_cluster = 2; - debug("The image is type FAT32, with %u clusters\n", this->clusters); - //printf("Root dir entries: %u clusters\n", bpb->root_entries); - //assert(bpb->root_entries == 0); - //this->root_dir_sectors = 0; - //this->data_index = bpb->reserved_sectors + bpb->fa_tables * this->sectors_per_fat; - } + { + this->fat_type = FAT::T_FAT32; + this->root_cluster = *(uint32_t*) &mbr->boot[33]; + this->root_cluster = 2; + debug("The image is type FAT32, with %u clusters\n", this->clusters); + //printf("Root dir entries: %u clusters\n", bpb->root_entries); + //assert(bpb->root_entries == 0); + //this->root_dir_sectors = 0; + //this->data_index = bpb->reserved_sectors + bpb->fa_tables * this->sectors_per_fat; + } debug("Root cluster index: %u (sector %u)\n", this->root_cluster, cl_to_sector(root_cluster)); debug("System ID: %.8s\n", bpb->system_id); } @@ -125,149 +125,149 @@ namespace fs // read Partition block device.read(this->lba_base, - [this, on_mount] (buffer_t data) - { - auto* mbr = (MBR::mbr*) data.get(); - assert(mbr != nullptr); + [this, on_mount] (buffer_t data) + { + auto* mbr = (MBR::mbr*) data.get(); + assert(mbr != nullptr); - // verify image signature - debug("OEM name: \t%s\n", mbr->oem_name); - debug("MBR signature: \t0x%x\n", mbr->magic); - assert(mbr->magic == 0xAA55); + // verify image signature + debug("OEM name: \t%s\n", mbr->oem_name); + debug("MBR signature: \t0x%x\n", mbr->magic); + assert(mbr->magic == 0xAA55); - // initialize FAT16 or FAT32 filesystem - init(mbr); + // initialize FAT16 or FAT32 filesystem + init(mbr); - // determine which FAT version is mounted - std::string inf = "ofs: " + std::to_string(lba_base) + - "size: " + std::to_string(lba_size) + - " (" + std::to_string(this->lba_size * sector_size) + " bytes)\n"; + // determine which FAT version is mounted + std::string inf = "ofs: " + std::to_string(lba_base) + + "size: " + std::to_string(lba_size) + + " (" + std::to_string(this->lba_size * sector_size) + " bytes)\n"; - switch (this->fat_type) - { - case FAT::T_FAT12: - INFO("FS", "Mounting FAT12 filesystem"); - break; - case FAT::T_FAT16: - INFO("FS", "Mounting FAT16 filesystem"); - break; - case FAT::T_FAT32: - INFO("FS", "Mounting FAT32 filesystem"); - break; - } - INFO2("[ofs=%u size=%u (%u bytes)]\n", - this->lba_base, this->lba_size, this->lba_size * 512); + switch (this->fat_type) + { + case FAT::T_FAT12: + INFO("FS", "Mounting FAT12 filesystem"); + break; + case FAT::T_FAT16: + INFO("FS", "Mounting FAT16 filesystem"); + break; + case FAT::T_FAT32: + INFO("FS", "Mounting FAT32 filesystem"); + break; + } + INFO2("[ofs=%u size=%u (%u bytes)]\n", + this->lba_base, this->lba_size, this->lba_size * 512); - // on_mount callback - on_mount(no_error); - }); + // on_mount callback + on_mount(no_error); + }); } bool FAT::int_dirent( - uint32_t sector, - const void* data, - dirvec_t dirents) + uint32_t sector, + const void* data, + dirvec_t dirents) { - auto* root = (cl_dir*) data; - bool found_last = false; + auto* root = (cl_dir*) data; + bool found_last = false; - for (int i = 0; i < 16; i++) + for (int i = 0; i < 16; i++) { if (unlikely(root[i].shortname[0] == 0x0)) - { - //printf("end of dir\n"); - found_last = true; - // end of directory - break; - } + { + //printf("end of dir\n"); + found_last = true; + // end of directory + break; + } else if (unlikely(root[i].shortname[0] == 0xE5)) - { - // unused index - } + { + // unused index + } else - { + { // traverse long names, then final cluster // to read all the relevant info if (likely(root[i].is_longname())) - { - auto* L = (cl_long*) &root[i]; - // the last long index is part of a chain of entries - if (L->is_last()) - { - // buffer for long filename - char final_name[256]; - int final_count = 0; + { + auto* L = (cl_long*) &root[i]; + // the last long index is part of a chain of entries + if (L->is_last()) + { + // buffer for long filename + char final_name[256]; + int final_count = 0; - int total = L->long_index(); - // go to the last entry and work backwards - i += total-1; - L += total-1; + int total = L->long_index(); + // go to the last entry and work backwards + i += total-1; + L += total-1; - for (int idx = total; idx > 0; idx--) - { - uint16_t longname[13]; - memcpy(longname+ 0, L->first, 10); - memcpy(longname+ 5, L->second, 12); - memcpy(longname+11, L->third, 4); + for (int idx = total; idx > 0; idx--) + { + uint16_t longname[13]; + memcpy(longname+ 0, L->first, 10); + memcpy(longname+ 5, L->second, 12); + memcpy(longname+11, L->third, 4); - for (int j = 0; j < 13; j++) - { - // 0xFFFF indicates end of name - if (unlikely(longname[j] == 0xFFFF)) break; - // sometimes, invalid stuff are snuck into filenames - if (unlikely(longname[j] == 0x0)) break; + for (int j = 0; j < 13; j++) + { + // 0xFFFF indicates end of name + if (unlikely(longname[j] == 0xFFFF)) break; + // sometimes, invalid stuff are snuck into filenames + if (unlikely(longname[j] == 0x0)) break; - final_name[final_count] = longname[j] & 0xFF; - final_count++; - } - L--; + final_name[final_count] = longname[j] & 0xFF; + final_count++; + } + L--; - if (unlikely(final_count > 240)) - { - debug("Suspicious long name length, breaking...\n"); - break; - } - } + if (unlikely(final_count > 240)) + { + debug("Suspicious long name length, breaking...\n"); + break; + } + } - final_name[final_count] = 0; - debug("Long name: %s\n", final_name); + final_name[final_count] = 0; + debug("Long name: %s\n", final_name); - i++; // skip over the long version - // to the short version for the stats and cluster - auto* D = &root[i]; - std::string dirname(final_name, final_count); - dirname = trim_right_copy(dirname); + i++; // skip over the long version + // to the short version for the stats and cluster + auto* D = &root[i]; + std::string dirname(final_name, final_count); + dirname = trim_right_copy(dirname); - dirents->emplace_back( - D->type(), - dirname, - D->dir_cluster(root_cluster), - sector, // parent block - D->size(), - D->attrib); - } - } + dirents->emplace_back( + D->type(), + dirname, + D->dir_cluster(root_cluster), + sector, // parent block + D->size(), + D->attrib); + } + } else - { - auto* D = &root[i]; - debug("Short name: %.11s\n", D->shortname); + { + auto* D = &root[i]; + debug("Short name: %.11s\n", D->shortname); - std::string dirname((char*) D->shortname, 11); - dirname = trim_right_copy(dirname); + std::string dirname((char*) D->shortname, 11); + dirname = trim_right_copy(dirname); - dirents->emplace_back( - D->type(), - dirname, - D->dir_cluster(root_cluster), - sector, // parent block - D->size(), - D->attrib); - } - } + dirents->emplace_back( + D->type(), + dirname, + D->dir_cluster(root_cluster), + sector, // parent block + D->size(), + D->attrib); + } + } } // directory list - return found_last; + return found_last; } } diff --git a/src/fs/fat_async.cpp b/src/fs/fat_async.cpp index ca1cb4b1db..965a35de98 100644 --- a/src/fs/fat_async.cpp +++ b/src/fs/fat_async.cpp @@ -15,43 +15,43 @@ namespace fs { void FAT::int_ls( - uint32_t sector, - dirvec_t dirents, - on_internal_ls_func callback) + uint32_t sector, + dirvec_t dirents, + on_internal_ls_func callback) { // list contents of meme sector by sector typedef std::function next_func_t; auto next = std::make_shared (); *next = - [this, sector, callback, dirents, next] (uint32_t sector) - { - debug("int_ls: sec=%u\n", sector); - device.read(sector, - [this, sector, callback, dirents, next] (buffer_t data) + [this, sector, callback, dirents, next] (uint32_t sector) + { + debug("int_ls: sec=%u\n", sector); + device.read(sector, + [this, sector, callback, dirents, next] (buffer_t data) { if (!data) - { - // could not read sector - callback(true, dirents); - return; - } + { + // could not read sector + callback(true, dirents); + return; + } // parse entries in sector bool done = int_dirent(sector, data.get(), dirents); if (done) - { - // execute callback - callback(no_error, dirents); - } + { + // execute callback + callback(no_error, dirents); + } else - { - // go to next sector - (*next)(sector+1); - } + { + // go to next sector + (*next)(sector+1); + } }); // read root dir - }; + }; // start reading sectors asynchronously (*next)(sector); @@ -65,68 +65,68 @@ namespace fs // asynch stack traversal auto next = std::make_shared (); *next = - [this, path, next, callback] (uint32_t cluster) + [this, path, next, callback] (uint32_t cluster) + { + if (path->empty()) { - if (path->empty()) - { - // attempt to read directory - uint32_t S = this->cl_to_sector(cluster); + // attempt to read directory + uint32_t S = this->cl_to_sector(cluster); - // result allocated on heap - auto dirents = std::make_shared> (); + // result allocated on heap + auto dirents = std::make_shared> (); - int_ls(S, dirents, - [callback] (error_t error, dirvec_t ents) - { - callback(error, ents); - }); - return; - } + int_ls(S, dirents, + [callback] (error_t error, dirvec_t ents) + { + callback(error, ents); + }); + return; + } - // retrieve next name - std::string name = path->front(); - path->pop_front(); + // retrieve next name + std::string name = path->front(); + path->pop_front(); - uint32_t S = this->cl_to_sector(cluster); - debug("Current target: %s on cluster %u (sector %u)\n", name.c_str(), cluster, S); + uint32_t S = this->cl_to_sector(cluster); + debug("Current target: %s on cluster %u (sector %u)\n", name.c_str(), cluster, S); - // result allocated on heap - auto dirents = std::make_shared> (); + // result allocated on heap + auto dirents = std::make_shared> (); - // list directory contents - int_ls(S, dirents, - [name, dirents, next, callback] (error_t error, dirvec_t ents) + // list directory contents + int_ls(S, dirents, + [name, dirents, next, callback] (error_t error, dirvec_t ents) { if (unlikely(error)) - { - debug("Could not find: %s\n", name.c_str()); - callback(true, dirents); - return; - } + { + debug("Could not find: %s\n", name.c_str()); + callback(true, dirents); + return; + } // look for name in directory for (auto& e : *ents) - { - if (unlikely(e.name() == name)) - { - // go to this directory, unless its the last name - debug("Found match for %s", name.c_str()); - // enter the matching directory - debug("\t\t cluster: %llu\n", e.block); - // only follow directories - if (e.type() == DIR) - (*next)(e.block); - else - callback(true, dirents); - return; - } - } // for (ents) + { + if (unlikely(e.name() == name)) + { + // go to this directory, unless its the last name + debug("Found match for %s", name.c_str()); + // enter the matching directory + debug("\t\t cluster: %llu\n", e.block); + // only follow directories + if (e.type() == DIR) + (*next)(e.block); + else + callback(true, dirents); + return; + } + } // for (ents) debug("NO MATCH for %s\n", name.c_str()); callback(true, dirents); }); - }; + }; // start by reading root directory (*next)(0); } @@ -137,10 +137,10 @@ namespace fs auto pstk = std::make_shared (path); traverse(pstk, - [on_ls] (error_t error, dirvec_t dirents) - { - on_ls(error, dirents); - }); + [on_ls] (error_t error, dirvec_t dirents) + { + on_ls(error, dirents); + }); } void FAT::read(const Dirent& ent, uint64_t pos, uint64_t n, on_read_func callback) @@ -156,51 +156,51 @@ namespace fs auto next = std::make_shared (); *next = - [this, sector, buffer, callback, next] (size_t start, size_t n, size_t end) + [this, sector, buffer, callback, next] (size_t start, size_t n, size_t end) + { + if (unlikely(n == end)) { - if (unlikely(n == end)) - { - // report back to HQ - debug("DONE start=%lu, current=%lu, total=%lu\n", start, n, end - start); - // create shared buffer - auto buffer_ptr = buffer_t(buffer, std::default_delete()); - // notify caller - callback(no_error, buffer_ptr, end - start); - return; - } + // report back to HQ + debug("DONE start=%lu, current=%lu, total=%lu\n", start, n, end - start); + // create shared buffer + auto buffer_ptr = buffer_t(buffer, std::default_delete()); + // notify caller + callback(no_error, buffer_ptr, end - start); + return; + } - // read the current sector based on position @n - uint32_t current_sector = sector + n / this->sector_size; + // read the current sector based on position @n + uint32_t current_sector = sector + n / this->sector_size; - device.read(current_sector, - [this, start, n, end, buffer, &callback, sector, next] (buffer_t data) + device.read(current_sector, + [this, start, n, end, buffer, &callback, sector, next] (buffer_t data) { if (!data) - { - // general I/O error occurred - debug("Failed to read sector %u for read()", sector); - // cleanup - delete[] buffer; - callback(true, buffer_t(), 0); - return; - } + { + // general I/O error occurred + debug("Failed to read sector %u for read()", sector); + // cleanup + delete[] buffer; + callback(true, buffer_t(), 0); + return; + } uint32_t length = n & (sector_size-1); if (n == start && n > 0) - { - length = sector_size - length; - } + { + length = sector_size - length; + } else - { - length = (n + sector_size) < end ? sector_size : (end - n); - } + { + length = (n + sector_size) < end ? sector_size : (end - n); + } // copy over data memcpy(buffer + n, data.get(), length); // continue reading next sector (*next)(start, n + length, end); }); - }; + }; // start! (*next)(pos, pos, pos + n); @@ -210,52 +210,52 @@ namespace fs { auto path = std::make_shared (strpath); if (unlikely(path->empty())) - { - // there is no possible file to read where path is empty - callback(true, nullptr, 0); - return; - } + { + // there is no possible file to read where path is empty + callback(true, nullptr, 0); + return; + } debug("readFile: %s\n", path->back().c_str()); std::string filename = path->back(); path->pop_back(); traverse(path, - [this, filename, &callback] (error_t error, dirvec_t dirents) - { - if (unlikely(error)) - { - // no path, no file! - callback(error, buffer_t(), 0); - return; - } + [this, filename, &callback] (error_t error, dirvec_t dirents) + { + if (unlikely(error)) + { + // no path, no file! + callback(error, buffer_t(), 0); + return; + } - // find the matching filename in directory - for (auto& ent : *dirents) - { - if (unlikely(ent.name() == filename)) - { - // read this file - read(ent, 0, ent.size, callback); - return; - } - } + // find the matching filename in directory + for (auto& ent : *dirents) + { + if (unlikely(ent.name() == filename)) + { + // read this file + read(ent, 0, ent.size, callback); + return; + } + } - // file not found - callback(true, buffer_t(), 0); - }); + // file not found + callback(true, buffer_t(), 0); + }); } // readFile() void FAT::stat(const std::string& strpath, on_stat_func func) { auto path = std::make_shared (strpath); if (unlikely(path->empty())) - { - // root doesn't have any stat anyways - // Note: could use ATTR_VOLUME_ID in FAT - func(true, Dirent(INVALID_ENTITY, strpath)); - return; - } + { + // root doesn't have any stat anyways + // Note: could use ATTR_VOLUME_ID in FAT + func(true, Dirent(INVALID_ENTITY, strpath)); + return; + } debug("stat: %s\n", path->back().c_str()); // extract file we are looking for @@ -265,28 +265,28 @@ namespace fs auto callback = std::make_shared (func); traverse(path, - [this, filename, callback] (error_t error, dirvec_t dirents) - { - if (unlikely(error)) - { - // no path, no file! - (*callback)(error, Dirent(INVALID_ENTITY, filename)); - return; - } + [this, filename, callback] (error_t error, dirvec_t dirents) + { + if (unlikely(error)) + { + // no path, no file! + (*callback)(error, Dirent(INVALID_ENTITY, filename)); + return; + } - // find the matching filename in directory - for (auto& e : *dirents) - { - if (unlikely(e.name() == filename)) - { - // read this file - (*callback)(no_error, e); - return; - } - } + // find the matching filename in directory + for (auto& e : *dirents) + { + if (unlikely(e.name() == filename)) + { + // read this file + (*callback)(no_error, e); + return; + } + } - // not found - (*callback)(true, Dirent(INVALID_ENTITY, filename)); - }); + // not found + (*callback)(true, Dirent(INVALID_ENTITY, filename)); + }); } } diff --git a/src/fs/fat_sync.cpp b/src/fs/fat_sync.cpp index ffe3dd2730..6a446d3712 100644 --- a/src/fs/fat_sync.cpp +++ b/src/fs/fat_sync.cpp @@ -35,11 +35,11 @@ namespace fs // if what we want to read is larger than the rest, exit early if (rest > n) - { - memcpy(result, data.get() + internal_ofs, n); + { + memcpy(result, data.get() + internal_ofs, n); - return Buffer(no_error, buffer_t(result), n); - } + return Buffer(no_error, buffer_t(result), n); + } // otherwise, read to the sector border uint8_t* ptr = result; memcpy(ptr, data.get() + internal_ofs, rest); @@ -49,21 +49,21 @@ namespace fs // copy entire sectors while (n > device.block_size()) - { - data = device.read_sync(sector); + { + data = device.read_sync(sector); - memcpy(ptr, data.get(), device.block_size()); - ptr += device.block_size(); - n -= device.block_size(); - sector += 1; - } + memcpy(ptr, data.get(), device.block_size()); + ptr += device.block_size(); + n -= device.block_size(); + sector += 1; + } // copy remainder if (likely(n > 0)) - { - data = device.read_sync(sector); - memcpy(ptr, data.get(), n); - } + { + data = device.read_sync(sector); + memcpy(ptr, data.get(), n); + } return Buffer(no_error, buffer_t(result), total); } @@ -72,10 +72,10 @@ namespace fs { Path path(strpath); if (unlikely(path.empty())) - { - // there is no possible file to read where path is empty - return Buffer(true, nullptr, 0); - } + { + // there is no possible file to read where path is empty + return Buffer(true, nullptr, 0); + } debug("readFile: %s\n", path.back().c_str()); std::string filename = path.back(); @@ -89,13 +89,13 @@ namespace fs // find the matching filename in directory for (auto& e : *dirents) + { + if (unlikely(e.name() == filename)) { - if (unlikely(e.name() == filename)) - { - // read this file - return read(e, 0, e.size); - } + // read this file + return read(e, 0, e.size); } + } // entry not found return Buffer(true, buffer_t(), 0); } // readFile() @@ -104,15 +104,15 @@ namespace fs { bool done = false; while (!done) - { - // read sector sync - buffer_t data = device.read_sync(sector); - if (!data) return true; - // parse directory into @ents - done = int_dirent(sector, data.get(), ents); - // go to next sector until done - sector++; - } + { + // read sector sync + buffer_t data = device.read_sync(sector); + if (!data) return true; + // parse directory into @ents + done = int_dirent(sector, data.get(), ents); + // go to next sector until done + sector++; + } return no_error; } @@ -125,46 +125,46 @@ namespace fs Dirent found(INVALID_ENTITY); while (!path.empty()) - { - uint32_t S = this->cl_to_sector(cluster); - dirents->clear(); // mui importante - // sync read entire directory - auto err = int_ls(S, dirents); - if (err) return err; - // the name we are looking for - std::string name = path.front(); - path.pop_front(); + { + uint32_t S = this->cl_to_sector(cluster); + dirents->clear(); // mui importante + // sync read entire directory + auto err = int_ls(S, dirents); + if (err) return err; + // the name we are looking for + std::string name = path.front(); + path.pop_front(); - // check for matches in dirents - for (auto& e : *dirents) - if (unlikely(e.name() == name)) - { - // go to this directory, unless its the last name - debug("traverse_sync: Found match for %s", name.c_str()); - // enter the matching directory - debug("\t\t cluster: %lu\n", e.block); - // only follow if the name is a directory - if (e.type() == DIR) - { - found = e; - break; - } - else - { - // not dir = error, for now - return true; - } - } // for (ents) + // check for matches in dirents + for (auto& e : *dirents) + if (unlikely(e.name() == name)) + { + // go to this directory, unless its the last name + debug("traverse_sync: Found match for %s", name.c_str()); + // enter the matching directory + debug("\t\t cluster: %lu\n", e.block); + // only follow if the name is a directory + if (e.type() == DIR) + { + found = e; + break; + } + else + { + // not dir = error, for now + return true; + } + } // for (ents) - // validate result - if (found.type() == INVALID_ENTITY) - { - debug("traverse_sync: NO MATCH for %s\n", name.c_str()); - return true; - } - // set next cluster - cluster = found.block; + // validate result + if (found.type() == INVALID_ENTITY) + { + debug("traverse_sync: NO MATCH for %s\n", name.c_str()); + return true; } + // set next cluster + cluster = found.block; + } uint32_t S = this->cl_to_sector(cluster); // read result directory entries into ents @@ -180,10 +180,10 @@ namespace fs { Path path(strpath); if (unlikely(path.empty())) - { - // root doesn't have any stat anyways (except ATTR_VOLUME_ID in FAT) - return Dirent(INVALID_ENTITY); - } + { + // root doesn't have any stat anyways (except ATTR_VOLUME_ID in FAT) + return Dirent(INVALID_ENTITY); + } debug("stat_sync: %s\n", path.back().c_str()); // extract file we are looking for @@ -198,13 +198,13 @@ namespace fs // find the matching filename in directory for (auto& e : *dirents) + { + if (unlikely(e.name() == filename)) { - if (unlikely(e.name() == filename)) - { - // return this directory entry - return e; - } + // return this directory entry + return e; } + } // entry not found return Dirent(INVALID_ENTITY); } diff --git a/src/fs/mbr.cpp b/src/fs/mbr.cpp index 0e1dabc188..38af37731d 100644 --- a/src/fs/mbr.cpp +++ b/src/fs/mbr.cpp @@ -5,74 +5,74 @@ namespace fs std::string MBR::id_to_name(uint8_t id) { switch (id) - { - case 0x00: - return "Empty"; - case 0x01: - return "DOS 12-bit FAT"; - case 0x02: - return "XENIX root"; - case 0x03: - return "XENIX /usr"; - case 0x04: - return "DOS 3.0+ 16-bit FAT"; - case 0x05: - return "DOS 3.3+ Extended Partition"; - case 0x06: - return "DOS 3.31+ 16-bit FAT (32M+)"; - case 0x07: - return "NTFS or exFAT"; - case 0x08: - return "Commodore DOS logical FAT"; - case 0x0b: - return "WIN95 OSR2 FAT32"; - case 0x0c: - return "WIN95 OSR2 FAT32, LBA-mapped"; - case 0x0d: - return "SILICON SAFE"; - case 0x0e: - return "WIN95: DOS 16-bit FAT, LBA-mapped"; - case 0x0f: - return "WIN95: Extended partition, LBA-mapped"; - case 0x11: - return "Hidden DOS 12-bit FAT"; - case 0x12: - return "Configuration utility partition (Compaq)"; - case 0x14: - return "Hidden DOS 16-bit FAT <32M"; - case 0x16: - return "Hidden DOS 16-bit FAT >= 32M"; - case 0x27: - return "Windows RE hidden partition"; - case 0x3c: - return "PartitionMagic recovery partition"; - case 0x82: - return "Linux swap"; - case 0x83: - return "Linux native partition"; - case 0x84: - return "Hibernation partition"; - case 0x85: - return "Linux extended partition"; - case 0x86: - return "FAT16 fault tolerant volume set"; - case 0x87: - return "NTFS fault tolerant volume set"; - case 0x8e: - return "Linux Logical Volume Manager partition"; - case 0x9f: - return "BSDI (BSD/OS)"; - case 0xa6: - return "OpenBSD"; - case 0xa8: - return "Apple MacOS X (BSD-like filesystem)"; - case 0xa9: - return "NetBSD"; - case 0xaf: - return "MacOS X HFS"; - default: - return "Invalid identifier: " + std::to_string(id); - } + { + case 0x00: + return "Empty"; + case 0x01: + return "DOS 12-bit FAT"; + case 0x02: + return "XENIX root"; + case 0x03: + return "XENIX /usr"; + case 0x04: + return "DOS 3.0+ 16-bit FAT"; + case 0x05: + return "DOS 3.3+ Extended Partition"; + case 0x06: + return "DOS 3.31+ 16-bit FAT (32M+)"; + case 0x07: + return "NTFS or exFAT"; + case 0x08: + return "Commodore DOS logical FAT"; + case 0x0b: + return "WIN95 OSR2 FAT32"; + case 0x0c: + return "WIN95 OSR2 FAT32, LBA-mapped"; + case 0x0d: + return "SILICON SAFE"; + case 0x0e: + return "WIN95: DOS 16-bit FAT, LBA-mapped"; + case 0x0f: + return "WIN95: Extended partition, LBA-mapped"; + case 0x11: + return "Hidden DOS 12-bit FAT"; + case 0x12: + return "Configuration utility partition (Compaq)"; + case 0x14: + return "Hidden DOS 16-bit FAT <32M"; + case 0x16: + return "Hidden DOS 16-bit FAT >= 32M"; + case 0x27: + return "Windows RE hidden partition"; + case 0x3c: + return "PartitionMagic recovery partition"; + case 0x82: + return "Linux swap"; + case 0x83: + return "Linux native partition"; + case 0x84: + return "Hibernation partition"; + case 0x85: + return "Linux extended partition"; + case 0x86: + return "FAT16 fault tolerant volume set"; + case 0x87: + return "NTFS fault tolerant volume set"; + case 0x8e: + return "Linux Logical Volume Manager partition"; + case 0x9f: + return "BSDI (BSD/OS)"; + case 0xa6: + return "OpenBSD"; + case 0xa8: + return "Apple MacOS X (BSD-like filesystem)"; + case 0xa9: + return "NetBSD"; + case 0xaf: + return "MacOS X HFS"; + default: + return "Invalid identifier: " + std::to_string(id); + } } diff --git a/src/fs/memdisk.cpp b/src/fs/memdisk.cpp index 83fed8ddab..6ae3c5e588 100644 --- a/src/fs/memdisk.cpp +++ b/src/fs/memdisk.cpp @@ -31,55 +31,55 @@ extern "C" { namespace fs { - MemDisk::MemDisk() noexcept +MemDisk::MemDisk() noexcept : image_start { &_DISK_START_ }, image_end { &_DISK_END_ } {} - void MemDisk::read(block_t blk, on_read_func callback) { - auto* sector_loc = ((char*) image_start) + blk * block_size(); - // Disallow reading memory past disk image - if (unlikely(sector_loc >= image_end)) - { - callback(buffer_t()); return; - } +void MemDisk::read(block_t blk, on_read_func callback) { + auto* sector_loc = ((char*) image_start) + blk * block_size(); + // Disallow reading memory past disk image + if (unlikely(sector_loc >= image_end)) + { + callback(buffer_t()); return; + } - auto* buffer = new uint8_t[block_size()]; - assert( memcpy(buffer, sector_loc, block_size()) == buffer ); + auto* buffer = new uint8_t[block_size()]; + assert( memcpy(buffer, sector_loc, block_size()) == buffer ); - callback( buffer_t(buffer, std::default_delete()) ); - } + callback( buffer_t(buffer, std::default_delete()) ); +} - void MemDisk::read(block_t start, block_t count, on_read_func callback) { - auto* start_loc = ((char*) image_start) + start * block_size(); - auto* end_loc = start_loc + count * block_size(); - // Disallow reading memory past disk image - if (unlikely(end_loc >= image_end)) - { - callback(buffer_t()); return; - } +void MemDisk::read(block_t start, block_t count, on_read_func callback) { + auto* start_loc = ((char*) image_start) + start * block_size(); + auto* end_loc = start_loc + count * block_size(); + // Disallow reading memory past disk image + if (unlikely(end_loc >= image_end)) + { + callback(buffer_t()); return; + } - auto* buffer = new uint8_t[count * block_size()]; - assert( memcpy(buffer, start_loc, count * block_size()) == buffer ); + auto* buffer = new uint8_t[count * block_size()]; + assert( memcpy(buffer, start_loc, count * block_size()) == buffer ); - callback( buffer_t(buffer, std::default_delete()) ); - } + callback( buffer_t(buffer, std::default_delete()) ); +} - MemDisk::buffer_t MemDisk::read_sync(block_t blk) - { - auto* loc = ((char*) image_start) + blk * block_size(); - // Disallow reading memory past disk image - if (unlikely(loc >= image_end)) - return buffer_t(); +MemDisk::buffer_t MemDisk::read_sync(block_t blk) +{ + auto* loc = ((char*) image_start) + blk * block_size(); + // Disallow reading memory past disk image + if (unlikely(loc >= image_end)) + return buffer_t(); - auto* buffer = new uint8_t[block_size()]; - assert( memcpy(buffer, loc, block_size()) == buffer ); + auto* buffer = new uint8_t[block_size()]; + assert( memcpy(buffer, loc, block_size()) == buffer ); - return buffer_t(buffer, std::default_delete()); - } + return buffer_t(buffer, std::default_delete()); +} - MemDisk::block_t MemDisk::size() const noexcept { - return ((char*) image_end - (char*) image_start) / SECTOR_SIZE; - } +MemDisk::block_t MemDisk::size() const noexcept { + return ((char*) image_end - (char*) image_start) / SECTOR_SIZE; +} } //< namespace fs diff --git a/src/fs/path.cpp b/src/fs/path.cpp index 45fe6a7612..e124f137ed 100644 --- a/src/fs/path.cpp +++ b/src/fs/path.cpp @@ -22,102 +22,102 @@ namespace fs { - static const char PATH_SEPARATOR = '/'; + static const char PATH_SEPARATOR = '/'; - Path::Path() - : Path("/") - { - // uses current directory - } - Path::Path(const std::string& path) - { - // parse full path - this->state = parse(path); + Path::Path() + : Path("/") + { + // uses current directory + } + Path::Path(const std::string& path) + { + // parse full path + this->state = parse(path); - } // Path::Path(std::string) + } // Path::Path(std::string) - std::string Path::to_string() const - { - // build path - //std::stringstream ss; + std::string Path::to_string() const + { + // build path + //std::stringstream ss; std::string ss; - for (const auto& p : this->stk) - { - ss += PATH_SEPARATOR + p; - } - // append path/ to end - ss += PATH_SEPARATOR; - return ss; - } + for (const auto& p : this->stk) + { + ss += PATH_SEPARATOR + p; + } + // append path/ to end + ss += PATH_SEPARATOR; + return ss; + } - int Path::parse(const std::string& path) - { - if (path.empty()) - { - // do nothing? - return 0; - } + int Path::parse(const std::string& path) + { + if (path.empty()) + { + // do nothing? + return 0; + } - std::string buffer(path.size(), 0); - char lastChar = 0; - int bufi = 0; + std::string buffer(path.size(), 0); + char lastChar = 0; + int bufi = 0; - for (size_t i = 0; i < path.size(); i++) - { - if (path[i] == PATH_SEPARATOR) - { - if (lastChar == PATH_SEPARATOR) - { // invalid path containing // (more than one forw-slash) - return -EINVAL; - } - if (bufi) - { - name_added(std::string(buffer, 0, bufi)); - bufi = 0; - } - else if (i == 0) - { - // if the first character is / separator, - // the path is relative to root, so clear stack - stk.clear(); - } - } - else - { - buffer[bufi] = path[i]; - bufi++; - } - lastChar = path[i]; - } // parse path - if (bufi) - { - name_added(std::string(buffer, 0, bufi)); - } + for (size_t i = 0; i < path.size(); i++) + { + if (path[i] == PATH_SEPARATOR) + { + if (lastChar == PATH_SEPARATOR) + { // invalid path containing // (more than one forw-slash) + return -EINVAL; + } + if (bufi) + { + name_added(std::string(buffer, 0, bufi)); + bufi = 0; + } + else if (i == 0) + { + // if the first character is / separator, + // the path is relative to root, so clear stack + stk.clear(); + } + } + else + { + buffer[bufi] = path[i]; + bufi++; + } + lastChar = path[i]; + } // parse path + if (bufi) + { + name_added(std::string(buffer, 0, bufi)); + } return 0; - } + } - void Path::name_added(const std::string& name) - { - //std::cout << "Path: " << toString() << " --> " << name << std::endl; + void Path::name_added(const std::string& name) + { + //std::cout << "Path: " << toString() << " --> " << name << std::endl; - if (name == ".") - { - // same directory - } - /*else if (name == "..") - { - // if the stack is empty we are at root - if (stk.empty()) - { - // trying to go above root is an error (?) - return; - } + if (name == ".") + { + // same directory + } + /*else if (name == "..") + { + // if the stack is empty we are at root + if (stk.empty()) + { + // trying to go above root is an error (?) + return; + } stk.pop_back(); - }*/ - else - { - // otherwise treat as directory - stk.push_back(name); - } - } + }*/ + else + { + // otherwise treat as directory + stk.push_back(name); + } + } } diff --git a/src/hw/cpu_freq_sampling.cpp b/src/hw/cpu_freq_sampling.cpp index b6899ccf9b..c7953a683b 100644 --- a/src/hw/cpu_freq_sampling.cpp +++ b/src/hw/cpu_freq_sampling.cpp @@ -25,83 +25,83 @@ namespace hw { - /** @note C-style code here, since we're dealing with interrupt handling. - The hardware expects a pure function pointer, and asm can't (easily) - call class member functions. */ +/** @note C-style code here, since we're dealing with interrupt handling. + The hardware expects a pure function pointer, and asm can't (easily) + call class member functions. */ - // This is how you provide storage for a static constexpr variable. - constexpr MHz PIT::frequency_; +// This is how you provide storage for a static constexpr variable. +constexpr MHz PIT::frequency_; - extern "C" double _CPUFreq_ = 0; - extern "C" constexpr uint16_t _cpu_sampling_freq_divider_ = KHz(PIT::frequency()).count() * 10; // Run 1 KHz Lowest: 0xffff +extern "C" double _CPUFreq_ = 0; +extern "C" constexpr uint16_t _cpu_sampling_freq_divider_ = KHz(PIT::frequency()).count() * 10; // Run 1 KHz Lowest: 0xffff - static constexpr int do_samples_ = 20; +static constexpr int do_samples_ = 20; - std::vector _cpu_timestamps; - std::vector _cpu_freq_samples; +std::vector _cpu_timestamps; +std::vector _cpu_freq_samples; - constexpr MHz test_frequency(){ - return MHz(PIT::frequency().count() / _cpu_sampling_freq_divider_); - } +constexpr MHz test_frequency(){ + return MHz(PIT::frequency().count() / _cpu_sampling_freq_divider_); +} - MHz calculate_cpu_frequency(){ +MHz calculate_cpu_frequency(){ - // We expect the cpu_sampling_irq_handler to push in samples; - while (_cpu_timestamps.size() < do_samples_) - OS::halt(); + // We expect the cpu_sampling_irq_handler to push in samples; + while (_cpu_timestamps.size() < do_samples_) + OS::halt(); - debug("_cpu_sampling_freq_divider_ : %i \n",_cpu_sampling_freq_divider_); + debug("_cpu_sampling_freq_divider_ : %i \n",_cpu_sampling_freq_divider_); -#ifdef DEBUG - for (auto t : _cpu_timestamps) debug("%lu \n",(uint32_t)t); -#endif + #ifdef DEBUG + for (auto t : _cpu_timestamps) debug("%lu \n",(uint32_t)t); + #endif - // Subtract the time it takes to measure time :-) - auto t1 = OS::cycles_since_boot(); - OS::cycles_since_boot(); - auto t3 = OS::cycles_since_boot(); - auto overhead = (t3 - t1) * 2; + // Subtract the time it takes to measure time :-) + auto t1 = OS::cycles_since_boot(); + OS::cycles_since_boot(); + auto t3 = OS::cycles_since_boot(); + auto overhead = (t3 - t1) * 2; - debug ("Overhead: %lu \n", (uint32_t)overhead); + debug ("Overhead: %lu \n", (uint32_t)overhead); - for (size_t i = 1; i < _cpu_timestamps.size(); i++){ - // Compute delta in cycles - auto cycles = _cpu_timestamps[i] - _cpu_timestamps[i-1] + overhead; - // Cycles pr. second == Hertz - auto freq = cycles / (1 / test_frequency().count()); - _cpu_freq_samples.push_back(freq); - debug("%lu - %lu = Delta: %lu Current PIT-Freq: %f Hz CPU Freq: %f MHz \n", - (uint32_t)_cpu_timestamps[i], (uint32_t)_cpu_timestamps[i-1], - (uint32_t)cycles, Hz(test_frequency()), freq); - } + for (size_t i = 1; i < _cpu_timestamps.size(); i++){ + // Compute delta in cycles + auto cycles = _cpu_timestamps[i] - _cpu_timestamps[i-1] + overhead; + // Cycles pr. second == Hertz + auto freq = cycles / (1 / test_frequency().count()); + _cpu_freq_samples.push_back(freq); + debug("%lu - %lu = Delta: %lu Current PIT-Freq: %f Hz CPU Freq: %f MHz \n", + (uint32_t)_cpu_timestamps[i], (uint32_t)_cpu_timestamps[i-1], + (uint32_t)cycles, Hz(test_frequency()), freq); + } #ifdef DEBUG - double sum = 0; - for (auto freq : _cpu_freq_samples) - sum += freq; - double mean = sum / _cpu_freq_samples.size(); + double sum = 0; + for (auto freq : _cpu_freq_samples) + sum += freq; + double mean = sum / _cpu_freq_samples.size(); #endif - std::sort(_cpu_freq_samples.begin(), _cpu_freq_samples.end()); - double median = _cpu_freq_samples[_cpu_freq_samples.size() / 2]; + std::sort(_cpu_freq_samples.begin(), _cpu_freq_samples.end()); + double median = _cpu_freq_samples[_cpu_freq_samples.size() / 2]; - debug(" MEAN: %f MEDIAN: %f \n",mean, median); - _CPUFreq_ = median; + debug(" MEAN: %f MEDIAN: %f \n",mean, median); + _CPUFreq_ = median; - return MHz(median); + return MHz(median); - } +} - void cpu_sampling_irq_handler(){ +void cpu_sampling_irq_handler(){ - auto t2 = OS::cycles_since_boot(); + auto t2 = OS::cycles_since_boot(); - if (_cpu_timestamps.size() < do_samples_) - _cpu_timestamps.push_back(t2); + if (_cpu_timestamps.size() < do_samples_) + _cpu_timestamps.push_back(t2); - IRQ_manager::eoi(0); - return; - } + IRQ_manager::eoi(0); + return; +} } //< namespace hw diff --git a/src/hw/ide.cpp b/src/hw/ide.cpp index e73db8c197..8f0245ea63 100644 --- a/src/hw/ide.cpp +++ b/src/hw/ide.cpp @@ -55,11 +55,11 @@ namespace hw { - IDE::IDE(hw::PCI_Device& pcidev, selector_t sel) : - _pcidev {pcidev}, - _drive {(uint8_t) ((sel == MASTER) ? 0 : 1)}, - _iobase {0U}, - _nb_blk {0U} +IDE::IDE(hw::PCI_Device& pcidev, selector_t sel) : + _pcidev {pcidev}, + _drive {(uint8_t) ((sel == MASTER) ? 0 : 1)}, + _iobase {0U}, + _nb_blk {0U} { INFO("IDE","VENDOR_ID : 0x%x, PRODUCT_ID : 0x%x", _pcidev.vendor_id(), _pcidev.product_id()); INFO("IDE","Attaching to PCI addr 0x%x",_pcidev.pci_addr()); @@ -108,157 +108,157 @@ namespace hw { INFO("IDE", "Initialization complete"); } - /** - * FIXME: this is a simple trick as we actually can't properly access the private - * members of the class during the IRQ handling... - */ - static IDE::on_read_func _callback = nullptr; // Current callback for asynchronous read - static int _nb_irqs = 0; // Number of IRQs that we expect - - void IDE::read(block_t blk, on_read_func callback) { - if (blk >= _nb_blk) { - // avoid reading past the disk boundaries - callback(buffer_t()); - return; - } +/** + * FIXME: this is a simple trick as we actually can't properly access the private + * members of the class during the IRQ handling... + */ +static IDE::on_read_func _callback = nullptr; // Current callback for asynchronous read +static int _nb_irqs = 0; // Number of IRQs that we expect - callback(read_sync(blk)); +void IDE::read(block_t blk, on_read_func callback) { + if (blk >= _nb_blk) { + // avoid reading past the disk boundaries + callback(buffer_t()); return; - - set_irq_mode(true); - set_drive(0xE0 | (_drive << 4) | ((blk >> 24) & 0x0F)); - set_nbsectors(1); - set_blocknum(blk); - set_command(IDE_CMD_READ); - - _callback = callback; - _nb_irqs = 1; } - void IDE::read(block_t blk, block_t count, on_read_func callback) - { - if (blk + count >= _nb_blk) { - // avoid reading past the disk boundaries - callback(buffer_t()); - return; - } + callback(read_sync(blk)); + return; - set_irq_mode(true); - set_drive(0xE0 | (_drive << 4) | ((blk >> 24) & 0x0F)); - set_nbsectors(count); - set_blocknum(blk); - set_command(IDE_CMD_READ); - - _callback = callback; - _nb_irqs = count; + set_irq_mode(true); + set_drive(0xE0 | (_drive << 4) | ((blk >> 24) & 0x0F)); + set_nbsectors(1); + set_blocknum(blk); + set_command(IDE_CMD_READ); + + _callback = callback; + _nb_irqs = 1; +} + +void IDE::read(block_t blk, block_t count, on_read_func callback) +{ + if (blk + count >= _nb_blk) { + // avoid reading past the disk boundaries + callback(buffer_t()); + return; } + + set_irq_mode(true); + set_drive(0xE0 | (_drive << 4) | ((blk >> 24) & 0x0F)); + set_nbsectors(count); + set_blocknum(blk); + set_command(IDE_CMD_READ); + + _callback = callback; + _nb_irqs = count; +} - IDE::buffer_t IDE::read_sync(block_t blk) - { - if (blk >= _nb_blk) { - // avoid reading past the disk boundaries - return buffer_t(); - } +IDE::buffer_t IDE::read_sync(block_t blk) +{ + if (blk >= _nb_blk) { + // avoid reading past the disk boundaries + return buffer_t(); + } - set_irq_mode(false); - set_drive(0xE0 | (_drive << 4) | ((blk >> 24) & 0x0F)); - set_nbsectors(1); - set_blocknum(blk); - set_command(IDE_CMD_READ); + set_irq_mode(false); + set_drive(0xE0 | (_drive << 4) | ((blk >> 24) & 0x0F)); + set_nbsectors(1); + set_blocknum(blk); + set_command(IDE_CMD_READ); - auto* buffer = new uint8_t[block_size()]; + auto* buffer = new uint8_t[block_size()]; - wait_status_flags(IDE_DRDY, false); + wait_status_flags(IDE_DRDY, false); - uint16_t* wptr = (uint16_t*) buffer; - uint16_t* wend = (uint16_t*)&buffer[block_size()]; - while (wptr < wend) - *(wptr++) = inw(IDE_DATA); + uint16_t* wptr = (uint16_t*) buffer; + uint16_t* wend = (uint16_t*)&buffer[block_size()]; + while (wptr < wend) + *(wptr++) = inw(IDE_DATA); - // return a shared_ptr wrapper for the buffer - return buffer_t(buffer, std::default_delete()); - } + // return a shared_ptr wrapper for the buffer + return buffer_t(buffer, std::default_delete()); +} - void IDE::wait_status_busy() const noexcept { - uint8_t ret; - while (((ret = inb(IDE_STATUS)) & IDE_BUSY) == IDE_BUSY); - } +void IDE::wait_status_busy() const noexcept { + uint8_t ret; + while (((ret = inb(IDE_STATUS)) & IDE_BUSY) == IDE_BUSY); +} - void IDE::wait_status_flags(const int flags, const bool set) const noexcept { - wait_status_busy(); +void IDE::wait_status_flags(const int flags, const bool set) const noexcept { + wait_status_busy(); - auto ret = inb(IDE_STATUS); + auto ret = inb(IDE_STATUS); - for (int i {IDE_TIMEOUT}; i; --i) { - if (set) { - if ((ret & flags) == flags) - break; - } else { - if ((ret & flags) not_eq flags) - break; - } - - ret = inb(IDE_STATUS); + for (int i {IDE_TIMEOUT}; i; --i) { + if (set) { + if ((ret & flags) == flags) + break; + } else { + if ((ret & flags) not_eq flags) + break; } + + ret = inb(IDE_STATUS); } +} - void IDE::set_drive(const uint8_t drive) const noexcept { - wait_status_flags(IDE_DRQ, true); - outb(IDE_DRV, drive); - } +void IDE::set_drive(const uint8_t drive) const noexcept { + wait_status_flags(IDE_DRQ, true); + outb(IDE_DRV, drive); +} - void IDE::set_nbsectors(const uint8_t cnt) const noexcept { - wait_status_flags(IDE_DRQ, true); - outb(IDE_SECCNT, cnt); - } +void IDE::set_nbsectors(const uint8_t cnt) const noexcept { + wait_status_flags(IDE_DRQ, true); + outb(IDE_SECCNT, cnt); +} - void IDE::set_blocknum(block_t blk) const noexcept { - wait_status_flags(IDE_DRQ, true); - outb(IDE_BLKLO, blk & 0xFF); +void IDE::set_blocknum(block_t blk) const noexcept { + wait_status_flags(IDE_DRQ, true); + outb(IDE_BLKLO, blk & 0xFF); - wait_status_flags(IDE_DRQ, true); - outb(IDE_BLKMID, (blk & 0xFF00) >> 8); + wait_status_flags(IDE_DRQ, true); + outb(IDE_BLKMID, (blk & 0xFF00) >> 8); - wait_status_flags(IDE_DRQ, true); - outb(IDE_BLKHI, (blk & 0xFF0000) >> 16); - } + wait_status_flags(IDE_DRQ, true); + outb(IDE_BLKHI, (blk & 0xFF0000) >> 16); +} - void IDE::set_command(const uint16_t command) const noexcept { - wait_status_flags(IDE_DRDY, false); - outb(IDE_CMD, command); - } +void IDE::set_command(const uint16_t command) const noexcept { + wait_status_flags(IDE_DRDY, false); + outb(IDE_CMD, command); +} - void IDE::set_irq_mode(const bool on) const noexcept { - wait_status_flags(IDE_DRDY, false); - outb(IDE_CTRL_IRQ, on ? 0 : 1); - } +void IDE::set_irq_mode(const bool on) const noexcept { + wait_status_flags(IDE_DRDY, false); + outb(IDE_CTRL_IRQ, on ? 0 : 1); +} - void IDE::irq_handler() { - if (!_nb_irqs || _callback == nullptr) { - set_irq_mode(false); - IRQ_manager::eoi(IDE_IRQN); - return; - } +void IDE::irq_handler() { + if (!_nb_irqs || _callback == nullptr) { + set_irq_mode(false); + IRQ_manager::eoi(IDE_IRQN); + return; + } - auto* buffer = new uint8_t[block_size()]; + auto* buffer = new uint8_t[block_size()]; - wait_status_flags(IDE_DRDY, false); + wait_status_flags(IDE_DRDY, false); - uint16_t* wptr = (uint16_t*) buffer; + uint16_t* wptr = (uint16_t*) buffer; - for (block_t i = 0; i < block_size() / sizeof (uint16_t); ++i) - wptr[i] = inw(IDE_DATA); + for (block_t i = 0; i < block_size() / sizeof (uint16_t); ++i) + wptr[i] = inw(IDE_DATA); - _callback(buffer_t(buffer, std::default_delete())); - _nb_irqs--; + _callback(buffer_t(buffer, std::default_delete())); + _nb_irqs--; - IRQ_manager::eoi(IDE_IRQN); - } + IRQ_manager::eoi(IDE_IRQN); +} - void IDE::enable_irq_handler() { - auto del(delegate::from(this)); - IRQ_manager::enable_irq(IDE_IRQN); - IRQ_manager::subscribe(IDE_IRQN, del); - } +void IDE::enable_irq_handler() { + auto del(delegate::from(this)); + IRQ_manager::enable_irq(IDE_IRQN); + IRQ_manager::subscribe(IDE_IRQN, del); +} } //< namespace hw diff --git a/src/hw/nic.cpp b/src/hw/nic.cpp index 74d9df8dbd..e6c40ccf1a 100644 --- a/src/hw/nic.cpp +++ b/src/hw/nic.cpp @@ -19,46 +19,46 @@ #include /* - namespace hw { +namespace hw { */ /* - template <> const char* Nic::name(){ +template <> const char* Nic::name(){ //return "Fantastic VirtioNic No.1"; return driver.name(); - } +} */ /* - template <> Nic::Nic(PCI_Device* _dev) +template <> Nic::Nic(PCI_Device* _dev) : pcidev(_dev) //Device(this) - { +{ printf("\n Nic at PCI addr 0x%x scanning for resources\n",_dev->pci_addr()); _dev->probe_resources(); - } +} */ /* - template <> const char* Nic::name(){ +template <> const char* Nic::name(){ return "Specialized E1000 No.1"; - } +} - template <> Nic::Nic(PCI_Device* _dev) +template <> Nic::Nic(PCI_Device* _dev) : pcidev(_dev) //Device(this) - { +{ printf("\n Nic at PCI addr 0x%x scanning for resources\n",_dev->pci_addr()); _dev->probe_resources(); - } +} */ /* - } //< namespace hw +} //< namespace hw */ diff --git a/src/hw/pci_device.cpp b/src/hw/pci_device.cpp index 2a1174856c..749363fcff 100644 --- a/src/hw/pci_device.cpp +++ b/src/hw/pci_device.cpp @@ -24,129 +24,129 @@ namespace hw { - constexpr int NUM_CLASSCODES {19}; - - static const char* classcodes[NUM_CLASSCODES] { - "Too-Old-To-Tell", // 0 - "Mass Storage Controller", // 1 - "Network Controller", // 2 - "Display Controller", // 3 - "Multimedia Controller", // 4 - "Memory Controller", // 5 - "Bridge", // 6 - "Simple communications controllers", - "Base system peripherals", // 8 - "Inupt device", // 9 - "Docking Station", - "Processor", - "Serial Bus Controller", - "Wireless Controller", - "Intelligent I/O Controller", - "Satellite Communication Controller", // 15 - "Encryption/Decryption Controller", // 16 - "Data Acquisition and Signal Processing Controller", // 17 - NULL - }; - - constexpr int SS_BR {3}; - - static const char* bridge_subclasses[SS_BR] { - "Host", - "ISA", - "Other" - }; - - constexpr int SS_NIC {2}; - - static const char* nic_subclasses[SS_NIC] { - "Ethernet", - "Other" - }; - - struct _pci_vendor { - uint16_t id; - const char* name; - } _pci_vendorlist[] { - {0x8086,"Intel Corp."}, - {0x1013,"Cirrus Logic"}, - {0x10EC,"Realtek Semi.Corp."}, - {0x1AF4,"Virtio (Rusty Russell)"}, // Virtio creator - {0x1022,"AMD"}, - {0x0000,NULL} - }; - - static unsigned long pci_size(const unsigned long base, const unsigned long mask) noexcept { - // Find the significant bits - unsigned long size = mask & base; - - // Get the lowest of them to find the decode size - size &= ~(size - 1); - - return size; - } +constexpr int NUM_CLASSCODES {19}; + +static const char* classcodes[NUM_CLASSCODES] { + "Too-Old-To-Tell", // 0 + "Mass Storage Controller", // 1 + "Network Controller", // 2 + "Display Controller", // 3 + "Multimedia Controller", // 4 + "Memory Controller", // 5 + "Bridge", // 6 + "Simple communications controllers", + "Base system peripherals", // 8 + "Inupt device", // 9 + "Docking Station", + "Processor", + "Serial Bus Controller", + "Wireless Controller", + "Intelligent I/O Controller", + "Satellite Communication Controller", // 15 + "Encryption/Decryption Controller", // 16 + "Data Acquisition and Signal Processing Controller", // 17 + NULL +}; + +constexpr int SS_BR {3}; + +static const char* bridge_subclasses[SS_BR] { + "Host", + "ISA", + "Other" +}; + +constexpr int SS_NIC {2}; + +static const char* nic_subclasses[SS_NIC] { + "Ethernet", + "Other" +}; + +struct _pci_vendor { + uint16_t id; + const char* name; +} _pci_vendorlist[] { + {0x8086,"Intel Corp."}, + {0x1013,"Cirrus Logic"}, + {0x10EC,"Realtek Semi.Corp."}, + {0x1AF4,"Virtio (Rusty Russell)"}, // Virtio creator + {0x1022,"AMD"}, + {0x0000,NULL} +}; + +static unsigned long pci_size(const unsigned long base, const unsigned long mask) noexcept { + // Find the significant bits + unsigned long size = mask & base; + + // Get the lowest of them to find the decode size + size &= ~(size - 1); + + return size; +} - uint32_t PCI_Device::iobase() const noexcept { - assert(res_io_ != nullptr); - return res_io_->start_; - }; +uint32_t PCI_Device::iobase() const noexcept { + assert(res_io_ != nullptr); + return res_io_->start_; +}; - void PCI_Device::probe_resources() noexcept { - //Find resources on this PCI device (scan the BAR's) - uint32_t value {PCI::WTF}; +void PCI_Device::probe_resources() noexcept { + //Find resources on this PCI device (scan the BAR's) + uint32_t value {PCI::WTF}; - uint32_t reg {0}; - uint32_t len {0}; + uint32_t reg {0}; + uint32_t len {0}; - for(int bar {0}; bar < 6; ++bar) { - //Read the current BAR register - reg = PCI::CONFIG_BASE_ADDR_0 + (bar << 2); - value = read_dword(reg); + for(int bar {0}; bar < 6; ++bar) { + //Read the current BAR register + reg = PCI::CONFIG_BASE_ADDR_0 + (bar << 2); + value = read_dword(reg); - if (!value) continue; + if (!value) continue; - //Write all 1's to the register, to get the length value (osdev) - write_dword(reg, 0xFFFFFFFF); - len = read_dword(reg); + //Write all 1's to the register, to get the length value (osdev) + write_dword(reg, 0xFFFFFFFF); + len = read_dword(reg); - //Put the value back - write_dword(reg, value); + //Put the value back + write_dword(reg, value); - uint32_t unmasked_val {0}; - uint32_t pci__size {0}; + uint32_t unmasked_val {0}; + uint32_t pci__size {0}; - if (value & 1) { // Resource type IO + if (value & 1) { // Resource type IO - unmasked_val = value & PCI::BASE_ADDRESS_IO_MASK; - pci__size = pci_size(len, PCI::BASE_ADDRESS_IO_MASK & 0xFFFF); + unmasked_val = value & PCI::BASE_ADDRESS_IO_MASK; + pci__size = pci_size(len, PCI::BASE_ADDRESS_IO_MASK & 0xFFFF); - // Add it to resource list - add_resource(new Resource(unmasked_val, pci__size), res_io_); - assert(res_io_ != nullptr); + // Add it to resource list + add_resource(new Resource(unmasked_val, pci__size), res_io_); + assert(res_io_ != nullptr); - } else { //Resource type Mem + } else { //Resource type Mem - unmasked_val = value & PCI::BASE_ADDRESS_MEM_MASK; - pci__size = pci_size(len, PCI::BASE_ADDRESS_MEM_MASK); + unmasked_val = value & PCI::BASE_ADDRESS_MEM_MASK; + pci__size = pci_size(len, PCI::BASE_ADDRESS_MEM_MASK); - //Add it to resource list - add_resource(new Resource(unmasked_val, pci__size), res_mem_); - assert(res_mem_ != nullptr); - } - - INFO2(""); - INFO2("[ Resource @ BAR %i ]", bar); - INFO2(" Address: 0x%x Size: 0x%x", unmasked_val, pci__size); - INFO2(" Type: %s", value & 1 ? "IO Resource" : "Memory Resource"); + //Add it to resource list + add_resource(new Resource(unmasked_val, pci__size), res_mem_); + assert(res_mem_ != nullptr); } - + INFO2(""); + INFO2("[ Resource @ BAR %i ]", bar); + INFO2(" Address: 0x%x Size: 0x%x", unmasked_val, pci__size); + INFO2(" Type: %s", value & 1 ? "IO Resource" : "Memory Resource"); } + + INFO2(""); +} - PCI_Device::PCI_Device(const uint16_t pci_addr, const uint32_t device_id) noexcept: +PCI_Device::PCI_Device(const uint16_t pci_addr, const uint32_t device_id) noexcept: pci_addr_{pci_addr}, device_id_{device_id} - // Device(Device::PCI) - // Why not inherit Device? Well, I think "PCI devices" are too general to be useful by itself, - // and the "Device" class is Public ABI, so it should only know about stuff that's relevant for the user. +// Device(Device::PCI) +// Why not inherit Device? Well, I think "PCI devices" are too general to be useful by itself, +// and the "Device" class is Public ABI, so it should only know about stuff that's relevant for the user. { //We have device, so probe for details devtype_.reg = read_dword(pci_addr, PCI::CONFIG_CLASS_REV); @@ -159,14 +159,14 @@ namespace hw { switch (devtype_.classcode) { case PCI::BRIDGE: INFO2("+--+ %s %s (0x%x)", - bridge_subclasses[devtype_.subclass < SS_BR ? devtype_.subclass : SS_BR-1], - classcodes[devtype_.classcode],devtype_.subclass); + bridge_subclasses[devtype_.subclass < SS_BR ? devtype_.subclass : SS_BR-1], + classcodes[devtype_.classcode],devtype_.subclass); break; case PCI::NIC: INFO2("+--+ %s %s (0x%x)", - nic_subclasses[devtype_.subclass < SS_NIC ? devtype_.subclass : SS_NIC-1], - classcodes[devtype_.classcode],devtype_.subclass); + nic_subclasses[devtype_.subclass < SS_NIC ? devtype_.subclass : SS_NIC-1], + classcodes[devtype_.classcode],devtype_.subclass); break; default: @@ -179,39 +179,39 @@ namespace hw { } - void PCI_Device::write_dword(const uint8_t reg, const uint32_t value) noexcept { - PCI::msg req; +void PCI_Device::write_dword(const uint8_t reg, const uint32_t value) noexcept { + PCI::msg req; - req.data = 0x80000000; - req.addr = pci_addr_; - req.reg = reg; + req.data = 0x80000000; + req.addr = pci_addr_; + req.reg = reg; - outpd(PCI::CONFIG_ADDR, static_cast(0x80000000) | req.data); - outpd(PCI::CONFIG_DATA, value); - } + outpd(PCI::CONFIG_ADDR, static_cast(0x80000000) | req.data); + outpd(PCI::CONFIG_DATA, value); +} - uint32_t PCI_Device::read_dword(const uint8_t reg) noexcept { - PCI::msg req; +uint32_t PCI_Device::read_dword(const uint8_t reg) noexcept { + PCI::msg req; - req.data = 0x80000000; - req.addr = pci_addr_; - req.reg = reg; + req.data = 0x80000000; + req.addr = pci_addr_; + req.reg = reg; - outpd(PCI::CONFIG_ADDR, static_cast(0x80000000) | req.data); + outpd(PCI::CONFIG_ADDR, static_cast(0x80000000) | req.data); - return inpd(PCI::CONFIG_DATA); - } + return inpd(PCI::CONFIG_DATA); +} - uint32_t PCI_Device::read_dword(const uint16_t pci_addr, const uint8_t reg) noexcept { - PCI::msg req; +uint32_t PCI_Device::read_dword(const uint16_t pci_addr, const uint8_t reg) noexcept { + PCI::msg req; - req.data = 0x80000000; - req.addr = pci_addr; - req.reg = reg; + req.data = 0x80000000; + req.addr = pci_addr; + req.reg = reg; - outpd(PCI::CONFIG_ADDR, static_cast(0x80000000) | req.data); + outpd(PCI::CONFIG_ADDR, static_cast(0x80000000) | req.data); - return inpd(PCI::CONFIG_DATA); - } + return inpd(PCI::CONFIG_DATA); +} } //< namespace hw diff --git a/src/hw/pit.cpp b/src/hw/pit.cpp index 503eb42538..cbb26c65f1 100644 --- a/src/hw/pit.cpp +++ b/src/hw/pit.cpp @@ -25,262 +25,262 @@ namespace hw { - // Bit 0-3: Mode 0 - "Interrupt on terminal count" - // Bit 4-5: Both set, access mode "Lobyte / Hibyte" - const uint8_t PIT_mode_register = 0x43; - const uint8_t PIT_chan0 = 0x40; +// Bit 0-3: Mode 0 - "Interrupt on terminal count" +// Bit 4-5: Both set, access mode "Lobyte / Hibyte" +const uint8_t PIT_mode_register = 0x43; +const uint8_t PIT_chan0 = 0x40; - // PIT state - PIT::Mode PIT::current_mode_ = NONE; - PIT::Mode PIT::temp_mode_ = NONE; - uint16_t PIT::current_freq_divider_ = 0; - uint16_t PIT::temp_freq_divider_ = 0; +// PIT state +PIT::Mode PIT::current_mode_ = NONE; +PIT::Mode PIT::temp_mode_ = NONE; +uint16_t PIT::current_freq_divider_ = 0; +uint16_t PIT::temp_freq_divider_ = 0; - uint64_t PIT::IRQ_counter_ = 0; +uint64_t PIT::IRQ_counter_ = 0; - // Used for cpu frequency sampling - extern "C" double _CPUFreq_; - extern "C" uint16_t _cpu_sampling_freq_divider_; - extern "C" void irq_timer_entry(); +// Used for cpu frequency sampling +extern "C" double _CPUFreq_; +extern "C" uint16_t _cpu_sampling_freq_divider_; +extern "C" void irq_timer_entry(); - // Time keeping - uint64_t PIT::millisec_counter = 0; +// Time keeping +uint64_t PIT::millisec_counter = 0; - // The default recurring timer condition - std::function PIT::forever = []{ return true; }; +// The default recurring timer condition +std::function PIT::forever = []{ return true; }; - // Timer ID's - uint32_t PIT::Timer::timers_count_ = 0; +// Timer ID's +uint32_t PIT::Timer::timers_count_ = 0; - using namespace std::chrono; +using namespace std::chrono; - PIT::Timer::Timer(Type t, timeout_handler handler, std::chrono::milliseconds ms, repeat_condition cond) - : type_{t}, id_{++timers_count_}, handler_{handler}, interval_{ms}, cond_{cond} {}; +PIT::Timer::Timer(Type t, timeout_handler handler, std::chrono::milliseconds ms, repeat_condition cond) + : type_{t}, id_{++timers_count_}, handler_{handler}, interval_{ms}, cond_{cond} {}; - void PIT::disable_regular_interrupts() - { - oneshot(1); - } +void PIT::disable_regular_interrupts() +{ + oneshot(1); +} - PIT::~PIT(){} +PIT::~PIT(){} - PIT::PIT(){ - debug(" Instantiating. \n"); +PIT::PIT(){ + debug(" Instantiating. \n"); - auto handler(IRQ_manager::irq_delegate::from(this)); + auto handler(IRQ_manager::irq_delegate::from(this)); - IRQ_manager::subscribe(0, handler); - } + IRQ_manager::subscribe(0, handler); +} - void PIT::estimateCPUFrequency(){ +void PIT::estimateCPUFrequency(){ - debug(" Saving state: curr_freq_div %i \n",current_freq_divider_); - // Save PIT-state - temp_mode_ = current_mode_; - temp_freq_divider_ = current_freq_divider_; + debug(" Saving state: curr_freq_div %i \n",current_freq_divider_); + // Save PIT-state + temp_mode_ = current_mode_; + temp_freq_divider_ = current_freq_divider_; - auto prev_irq_handler = IRQ_manager::get_handler(32); + auto prev_irq_handler = IRQ_manager::get_handler(32); - debug(" Sampling\n"); - IRQ_manager::set_handler(32, cpu_sampling_irq_entry); + debug(" Sampling\n"); + IRQ_manager::set_handler(32, cpu_sampling_irq_entry); - // GO! - set_mode(RATE_GEN); - set_freq_divider(_cpu_sampling_freq_divider_); + // GO! + set_mode(RATE_GEN); + set_freq_divider(_cpu_sampling_freq_divider_); - // BLOCKING call to external measurment. - calculate_cpu_frequency(); + // BLOCKING call to external measurment. + calculate_cpu_frequency(); - debug(" Done. Result: %f \n", _CPUFreq_); + debug(" Done. Result: %f \n", _CPUFreq_); - set_mode(temp_mode_); - set_freq_divider(temp_freq_divider_); + set_mode(temp_mode_); + set_freq_divider(temp_freq_divider_); - IRQ_manager::set_handler(32, prev_irq_handler); - } + IRQ_manager::set_handler(32, prev_irq_handler); +} - MHz PIT::CPUFrequency(){ - if (! _CPUFreq_) - estimateCPUFrequency(); +MHz PIT::CPUFrequency(){ + if (! _CPUFreq_) + estimateCPUFrequency(); - return MHz(_CPUFreq_); - } + return MHz(_CPUFreq_); +} - void PIT::start_timer(Timer t, std::chrono::milliseconds in_msecs){ - if (in_msecs < 1ms) panic("Can't wait less than 1 ms. "); +void PIT::start_timer(Timer t, std::chrono::milliseconds in_msecs){ + if (in_msecs < 1ms) panic("Can't wait less than 1 ms. "); - if (current_mode_ != RATE_GEN) - set_mode(RATE_GEN); + if (current_mode_ != RATE_GEN) + set_mode(RATE_GEN); - if (current_freq_divider_ != millisec_interval) - set_freq_divider(millisec_interval); + if (current_freq_divider_ != millisec_interval) + set_freq_divider(millisec_interval); - auto cycles_pr_millisec = KHz(CPUFrequency()); - debug(" CPU KHz: %f Cycles to wait: %f \n",cycles_pr_millisec.count(), cycles_pr_millisec.count() * in_msecs); + auto cycles_pr_millisec = KHz(CPUFrequency()); + debug(" CPU KHz: %f Cycles to wait: %f \n",cycles_pr_millisec.count(), cycles_pr_millisec.count() * in_msecs); - auto ticks = in_msecs / KHz(current_frequency()).count(); - debug(" PIT KHz: %f * %i = %f ms. \n", - KHz(current_frequency()).count(), (uint32_t)ticks.count(), ((uint32_t)ticks.count() * KHz(current_frequency()).count())); + auto ticks = in_msecs / KHz(current_frequency()).count(); + debug(" PIT KHz: %f * %i = %f ms. \n", + KHz(current_frequency()).count(), (uint32_t)ticks.count(), ((uint32_t)ticks.count() * KHz(current_frequency()).count())); - t.setStart(OS::cycles_since_boot()); - t.setEnd(t.start() + uint64_t(cycles_pr_millisec.count() * in_msecs.count())); + t.setStart(OS::cycles_since_boot()); + t.setEnd(t.start() + uint64_t(cycles_pr_millisec.count() * in_msecs.count())); - auto key = millisec_counter + ticks.count(); + auto key = millisec_counter + ticks.count(); - // We could emplace, but the timer exists allready, and might be a reused one - timers_.insert(std::make_pair(key, t)); + // We could emplace, but the timer exists allready, and might be a reused one + timers_.insert(std::make_pair(key, t)); - debug(" Key: %i id: %i, t.cond()(): %s There are %i timers. \n", - (uint32_t)key, t.id(), t.cond()() ? "true" : "false", timers_.size()); + debug(" Key: %i id: %i, t.cond()(): %s There are %i timers. \n", + (uint32_t)key, t.id(), t.cond()() ? "true" : "false", timers_.size()); - } +} - void PIT::onRepeatedTimeout(std::chrono::milliseconds ms, timeout_handler handler, repeat_condition cond){ - debug(" setting a %i ms. repeating timer \n", (uint32_t)ms.count()); +void PIT::onRepeatedTimeout(std::chrono::milliseconds ms, timeout_handler handler, repeat_condition cond){ + debug(" setting a %i ms. repeating timer \n", (uint32_t)ms.count()); - Timer t(Timer::REPEAT_WHILE, handler, ms, cond); - start_timer(t, ms); - }; + Timer t(Timer::REPEAT_WHILE, handler, ms, cond); + start_timer(t, ms); +}; - void PIT::onTimeout(std::chrono::milliseconds msec, timeout_handler handler){ - Timer t(Timer::ONE_SHOT, handler, msec); +void PIT::onTimeout(std::chrono::milliseconds msec, timeout_handler handler){ + Timer t(Timer::ONE_SHOT, handler, msec); - debug(" setting a %i ms. one-shot timer. Id: %i \n", - (uint32_t)msec.count(), t.id()); + debug(" setting a %i ms. one-shot timer. Id: %i \n", + (uint32_t)msec.count(), t.id()); - start_timer(t, msec); + start_timer(t, msec); - }; +}; - uint8_t PIT::read_back(uint8_t){ - const uint8_t READ_BACK_CMD = 0xc2; +uint8_t PIT::read_back(uint8_t){ + const uint8_t READ_BACK_CMD = 0xc2; - hw::outb(PIT_mode_register, READ_BACK_CMD ); + hw::outb(PIT_mode_register, READ_BACK_CMD ); - auto res = hw::inb(PIT_chan0); + auto res = hw::inb(PIT_chan0); - debug("STATUS: %#x \n", res); + debug("STATUS: %#x \n", res); - return res; + return res; - } +} - void PIT::irq_handler(){ - // All IRQ-handlers has to send EOI - IRQ_manager::eoi(0); +void PIT::irq_handler(){ + // All IRQ-handlers has to send EOI + IRQ_manager::eoi(0); - IRQ_counter_ ++; + IRQ_counter_ ++; - if (current_freq_divider_ == millisec_interval) - millisec_counter++; + if (current_freq_divider_ == millisec_interval) + millisec_counter++; -#ifdef DEBUG - if (millisec_counter % 100 == 0) - OS::rsprint("."); -#endif + #ifdef DEBUG + if (millisec_counter % 100 == 0) + OS::rsprint("."); + #endif - // Iterate over expired timers (we break on the first non-expired) - for (auto it = timers_.begin(); it != timers_.end(); it++) { + // Iterate over expired timers (we break on the first non-expired) + for (auto it = timers_.begin(); it != timers_.end(); it++) { - // Map-keys are sorted. If this timer isn't expired, neither are the rest - if (it->first > millisec_counter) - break; + // Map-keys are sorted. If this timer isn't expired, neither are the rest + if (it->first > millisec_counter) + break; - debug2 ("\n**** Timer type %i, id: %i expired. Running handler **** \n", - it->second.type(), it->second.id()); + debug2 ("\n**** Timer type %i, id: %i expired. Running handler **** \n", + it->second.type(), it->second.id()); - // Execute the handler - it->second.handler()(); + // Execute the handler + it->second.handler()(); - // Re-queue repeating timers - if (it->second.type() == Timer::REPEAT) { - debug2 (" REPEAT: Requeuing the timer \n"); - start_timer(it->second, it->second.interval()); + // Re-queue repeating timers + if (it->second.type() == Timer::REPEAT) { + debug2 (" REPEAT: Requeuing the timer \n"); + start_timer(it->second, it->second.interval()); - }else if (it->second.type() == Timer::REPEAT_WHILE and it->second.cond()()) { - debug2 (" REPEAT_WHILE: Requeuing the timer COND \n"); - start_timer(it->second, it->second.interval()); - } + }else if (it->second.type() == Timer::REPEAT_WHILE and it->second.cond()()) { + debug2 (" REPEAT_WHILE: Requeuing the timer COND \n"); + start_timer(it->second, it->second.interval()); + } - debug2 ("Timer done. Erasing. \n"); + debug2 ("Timer done. Erasing. \n"); - // Escape iterator death - auto remove = it; - it++; + // Escape iterator death + auto remove = it; + it++; - // Erase the timer - timers_.erase(remove); + // Erase the timer + timers_.erase(remove); - // If this was the last timer, we can turn off the clock - if (timers_.empty()){ - // Disable the PIT - oneshot(1); + // If this was the last timer, we can turn off the clock + if (timers_.empty()){ + // Disable the PIT + oneshot(1); - debug2 ("Timers done. PIT disabled for now. \n"); - // Escape iterator death - break; - } + debug2 ("Timers done. PIT disabled for now. \n"); + // Escape iterator death + break; + } - debug2 ("Timers left: %i \n", timers_.size()); + debug2 ("Timers left: %i \n", timers_.size()); -#ifdef DEBUG2 - for (auto t : timers_) - debug2("Key: %i , id: %i, Type: %i", (uint32_t)t.first, t.second.id(), t.second.type()); -#endif - - debug2("\n---------------------------\n\n"); - } + #ifdef DEBUG2 + for (auto t : timers_) + debug2("Key: %i , id: %i, Type: %i", (uint32_t)t.first, t.second.id(), t.second.type()); + #endif + debug2("\n---------------------------\n\n"); } - void PIT::init(){ - debug(" Initializing @ frequency: %16.16f MHz. Assigning myself to all timer interrupts.\n ", frequency()); - PIT::disable_regular_interrupts(); - IRQ_manager::enable_irq(0); - } +} - void PIT::set_mode(Mode mode){ - // Channel is the last two bits in the PIT mode register - // ...we always use channel 0 - auto channel = 0x00; - uint8_t config = mode | LO_HI | channel; - debug(" Setting mode %#x, config: %#x \n", mode, config); +void PIT::init(){ + debug(" Initializing @ frequency: %16.16f MHz. Assigning myself to all timer interrupts.\n ", frequency()); + PIT::disable_regular_interrupts(); + IRQ_manager::enable_irq(0); +} - hw::outb(PIT_mode_register, config); - current_mode_ = mode; +void PIT::set_mode(Mode mode){ + // Channel is the last two bits in the PIT mode register + // ...we always use channel 0 + auto channel = 0x00; + uint8_t config = mode | LO_HI | channel; + debug(" Setting mode %#x, config: %#x \n", mode, config); - } + hw::outb(PIT_mode_register, config); + current_mode_ = mode; - void PIT::set_freq_divider(uint16_t freq_divider){ - union{ - uint16_t whole; - uint8_t part[2]; - }data{freq_divider}; +} - // Send frequency hi/lo to PIT - hw::outb(PIT_chan0, data.part[0]); - hw::outb(PIT_chan0, data.part[1]); +void PIT::set_freq_divider(uint16_t freq_divider){ + union{ + uint16_t whole; + uint8_t part[2]; + }data{freq_divider}; - current_freq_divider_ = freq_divider; + // Send frequency hi/lo to PIT + hw::outb(PIT_chan0, data.part[0]); + hw::outb(PIT_chan0, data.part[1]); - } + current_freq_divider_ = freq_divider; - void PIT::oneshot(uint16_t t){ +} - // Enable 1-shot mode - set_mode(ONE_SHOT); +void PIT::oneshot(uint16_t t){ - // Set a frequency for shot - set_freq_divider(t); - } + // Enable 1-shot mode + set_mode(ONE_SHOT); + + // Set a frequency for shot + set_freq_divider(t); +} } //< namespace hw diff --git a/src/include/hw/cpu_freq_sampling.hpp b/src/include/hw/cpu_freq_sampling.hpp index 44b902a251..733dde58df 100644 --- a/src/include/hw/cpu_freq_sampling.hpp +++ b/src/include/hw/cpu_freq_sampling.hpp @@ -21,17 +21,17 @@ namespace hw { - /** Proper IRQ-handler for CPU frequency sampling - implemented in interrupts.s - @Note - PIT::estimateCPUFrequency() will register- /de-register this as needed */ - extern "C" void cpu_sampling_irq_handler(); +/** Proper IRQ-handler for CPU frequency sampling - implemented in interrupts.s + @Note + PIT::estimateCPUFrequency() will register- /de-register this as needed */ +extern "C" void cpu_sampling_irq_handler(); - /** CPU frequency sampling. Implemented in hw/cpu_freq_sampling.cpp - @Note this will be automatically called by the oirq-handler */ - extern "C" void cpu_sampling_irq_entry(); +/** CPU frequency sampling. Implemented in hw/cpu_freq_sampling.cpp + @Note this will be automatically called by the oirq-handler */ +extern "C" void cpu_sampling_irq_entry(); - extern "C" void irq_32_entry(); +extern "C" void irq_32_entry(); - extern "C" MHz calculate_cpu_frequency(); +extern "C" MHz calculate_cpu_frequency(); } //< namespace hw diff --git a/src/kernel/cpuid.cpp b/src/kernel/cpuid.cpp index 0a38bfb572..7982f55c3d 100644 --- a/src/kernel/cpuid.cpp +++ b/src/kernel/cpuid.cpp @@ -95,32 +95,32 @@ static cpuid_t cpuid_info(const unsigned int func, const unsigned int subfunc) { cpuid_t info; __asm__ __volatile__ ( - "cpuid" - : "=a"(info.EAX), "=b"(info.EBX), "=c"(info.ECX), "=d"(info.EDX) - : "a"(func), "c"(subfunc) : "%eax", "%ebx", "%ecx", "%edx" - ); + "cpuid" + : "=a"(info.EAX), "=b"(info.EBX), "=c"(info.ECX), "=d"(info.EDX) + : "a"(func), "c"(subfunc) : "%eax", "%ebx", "%ecx", "%edx" + ); return info; } bool CPUID::isAmdCpu() { cpuid_t info = cpuid_info(0, 0); if (memcmp((char *) (&info.EBX), "htuA", 4) == 0 - && memcmp((char *) (&info.EDX), "itne", 4) == 0 - && memcmp((char *) (&info.ECX), "DMAc", 4) == 0) - { + && memcmp((char *) (&info.EDX), "itne", 4) == 0 + && memcmp((char *) (&info.ECX), "DMAc", 4) == 0) + { return true; - } + } return false; } bool CPUID::isIntelCpu() { cpuid_t info = cpuid_info(0, 0); if (memcmp((char *) (&info.EBX), "Genu", 4) == 0 - && memcmp((char *) (&info.EDX), "ineI", 4) == 0 - && memcmp((char *) (&info.ECX), "ntel", 4) == 0) - { + && memcmp((char *) (&info.EDX), "ineI", 4) == 0 + && memcmp((char *) (&info.ECX), "ntel", 4) == 0) + { return true; - } + } return false; } diff --git a/src/kernel/irq_manager.cpp b/src/kernel/irq_manager.cpp index 8c2ada8c24..376b4ef331 100644 --- a/src/kernel/irq_manager.cpp +++ b/src/kernel/irq_manager.cpp @@ -66,39 +66,39 @@ extern "C" } /** Default Exception-handler, which just prints its number */ -#define EXCEPTION_HANDLER(I) \ - void exception_##I##_handler() { \ - printf("\n\n>>>> !!! CPU EXCEPTION %i !!! <<<<<\n", I); \ - printf("Heap end: %#x \n", (uint32_t)&_end); \ - kill(1, 9); \ +#define EXCEPTION_HANDLER(I) \ + void exception_##I##_handler() { \ + printf("\n\n>>>> !!! CPU EXCEPTION %i !!! <<<<<\n", I); \ + printf("Heap end: %#x \n", (uint32_t)&_end); \ + kill(1, 9); \ } void exception_handler() { -#define frp(N, ra) \ - (__builtin_frame_address(N) != nullptr) && \ - (ra = __builtin_return_address(N)) != nullptr + #define frp(N, ra) \ + (__builtin_frame_address(N) != nullptr) && \ + (ra = __builtin_return_address(N)) != nullptr printf("\n"); -#define PRINT_TRACE(N, ra) \ - printf("[%d] Return %p\n", N, ra); + #define PRINT_TRACE(N, ra) \ + printf("[%d] Return %p\n", N, ra); void* ra; if (frp(0, ra)) { - PRINT_TRACE(0, ra); - if (frp(1, ra)) { - PRINT_TRACE(1, ra); - if (frp(2, ra)) { - PRINT_TRACE(2, ra); - if (frp(3, ra)) { - PRINT_TRACE(3, ra); - if (frp(4, ra)) { - PRINT_TRACE(4, ra); - if (frp(5, ra)) { - PRINT_TRACE(5, ra); - if (frp(6, ra)) - PRINT_TRACE(6, ra); - }}}}}} + PRINT_TRACE(0, ra); + if (frp(1, ra)) { + PRINT_TRACE(1, ra); + if (frp(2, ra)) { + PRINT_TRACE(2, ra); + if (frp(3, ra)) { + PRINT_TRACE(3, ra); + if (frp(4, ra)) { + PRINT_TRACE(4, ra); + if (frp(5, ra)) { + PRINT_TRACE(5, ra); + if (frp(6, ra)) + PRINT_TRACE(6, ra); + }}}}}} printf(">>>> !!! CPU EXCEPTION !!! <<<<\n"); extern char _end; @@ -115,19 +115,19 @@ void exception_handler() uint32_t IRQ_manager::irq_counters_[32] {0}; -#define IRQ_HANDLER(I) \ - void irq_##I##_handler() { \ - IRQ_manager::register_interrupt(I); \ +#define IRQ_HANDLER(I) \ + void irq_##I##_handler() { \ + IRQ_manager::register_interrupt(I); \ } /* Macro magic to register default gates */ -#define REG_DEFAULT_EXCPT(I) create_gate(&(idt[I]),exception_entry, \ - default_sel, default_attr ); +#define REG_DEFAULT_EXCPT(I) create_gate(&(idt[I]),exception_entry, \ + default_sel, default_attr ); -#define REG_DEFAULT_IRQ(I) create_gate(&(idt[I + irq_base]),irq_##I##_entry, \ - default_sel, default_attr ); +#define REG_DEFAULT_IRQ(I) create_gate(&(idt[I + irq_base]),irq_##I##_entry, \ + default_sel, default_attr ); -/* EXCEPTIONS */ + /* EXCEPTIONS */ #define EXCEPTION_PAIR(I) void exception_entry(); #define IRQ_PAIR(I) void irq_##I##_entry(); IRQ_HANDLER(I) @@ -191,27 +191,27 @@ void IRQ_manager::init() // Assign the lower 32 IRQ's : Exceptions REG_DEFAULT_EXCPT(0) REG_DEFAULT_EXCPT(1) REG_DEFAULT_EXCPT(2) - REG_DEFAULT_EXCPT(3) REG_DEFAULT_EXCPT(4) REG_DEFAULT_EXCPT(5) - REG_DEFAULT_EXCPT(6) REG_DEFAULT_EXCPT(7) REG_DEFAULT_EXCPT(8) - REG_DEFAULT_EXCPT(9) REG_DEFAULT_EXCPT(10) REG_DEFAULT_EXCPT(11) - REG_DEFAULT_EXCPT(12) REG_DEFAULT_EXCPT(13) REG_DEFAULT_EXCPT(14) - REG_DEFAULT_EXCPT(15) REG_DEFAULT_EXCPT(16) REG_DEFAULT_EXCPT(17) - REG_DEFAULT_EXCPT(18) REG_DEFAULT_EXCPT(19) REG_DEFAULT_EXCPT(20) - // GATES 21-29 are reserved - REG_DEFAULT_EXCPT(30) REG_DEFAULT_EXCPT(31) - INFO2("+ Exception gates set for irq < 32"); + REG_DEFAULT_EXCPT(3) REG_DEFAULT_EXCPT(4) REG_DEFAULT_EXCPT(5) + REG_DEFAULT_EXCPT(6) REG_DEFAULT_EXCPT(7) REG_DEFAULT_EXCPT(8) + REG_DEFAULT_EXCPT(9) REG_DEFAULT_EXCPT(10) REG_DEFAULT_EXCPT(11) + REG_DEFAULT_EXCPT(12) REG_DEFAULT_EXCPT(13) REG_DEFAULT_EXCPT(14) + REG_DEFAULT_EXCPT(15) REG_DEFAULT_EXCPT(16) REG_DEFAULT_EXCPT(17) + REG_DEFAULT_EXCPT(18) REG_DEFAULT_EXCPT(19) REG_DEFAULT_EXCPT(20) + // GATES 21-29 are reserved + REG_DEFAULT_EXCPT(30) REG_DEFAULT_EXCPT(31) + INFO2("+ Exception gates set for irq < 32"); //Redirected IRQ 0 - 15 REG_DEFAULT_IRQ(0) REG_DEFAULT_IRQ(1) REG_DEFAULT_IRQ(3) - REG_DEFAULT_IRQ(4) REG_DEFAULT_IRQ(5) REG_DEFAULT_IRQ(6) - REG_DEFAULT_IRQ(7) REG_DEFAULT_IRQ(8) REG_DEFAULT_IRQ(9) - REG_DEFAULT_IRQ(10) REG_DEFAULT_IRQ(11) REG_DEFAULT_IRQ(12) - REG_DEFAULT_IRQ(13) REG_DEFAULT_IRQ(14) REG_DEFAULT_IRQ(15) - - //Set all irq-gates (> 47) to the default handler - for(int i=48;i 47) to the default handler + for(int i=48;i= 32"); //Load IDT @@ -234,9 +234,9 @@ union addr_union { }; void IRQ_manager::create_gate(IDTDescr* idt_entry, - void (*function_addr)(), - uint16_t segment_sel, - char attributes) { + void (*function_addr)(), + uint16_t segment_sel, + char attributes) { addr_union addr; addr.whole = (uint32_t)function_addr; idt_entry->offset_1 = addr.lo16; @@ -270,7 +270,7 @@ IRQ_manager::irq_delegate IRQ_manager::get_subscriber(uint8_t irq) { } void IRQ_manager::enable_irq(uint8_t irq) { - hw::PIC::enable_irq(irq); + hw::PIC::enable_irq(irq); } int IRQ_manager::timer_interrupts {0}; @@ -327,9 +327,9 @@ void IRQ_manager::notify() { // Spinlock? Well, we can't lock out the IRQ-handler // ... and we don't have a timer interrupt so we can't do blocking locks. if (!irq_counters_[irq]) { - // Remove the IRQ from pending list - irq_pending_ &= ~(1 << irq); - //debug(" IRQ's pending: 0x%lx\n",irq_pending_); + // Remove the IRQ from pending list + irq_pending_ &= ~(1 << irq); + //debug(" IRQ's pending: 0x%lx\n",irq_pending_); } // Critical section end @@ -344,7 +344,7 @@ void IRQ_manager::notify() { } void IRQ_manager::eoi(uint8_t irq) { - hw::PIC::eoi(irq); + hw::PIC::eoi(irq); } void irq_default_handler() { diff --git a/src/kernel/os.cpp b/src/kernel/os.cpp index 532e9e6eea..e4c31c920e 100644 --- a/src/kernel/os.cpp +++ b/src/kernel/os.cpp @@ -68,16 +68,16 @@ void OS::start() { /** Estimate CPU frequency - MYINFO("Estimating CPU-frequency"); - INFO2("|"); - INFO2("+--(10 samples, %f sec. interval)", - (hw::PIT::frequency() / _cpu_sampling_freq_divider_).count()); - INFO2("|"); + MYINFO("Estimating CPU-frequency"); + INFO2("|"); + INFO2("+--(10 samples, %f sec. interval)", + (hw::PIT::frequency() / _cpu_sampling_freq_divider_).count()); + INFO2("|"); - // TODO: Debug why actual measurments sometimes causes problems. Issue #246. - cpu_mhz_ = hw::PIT::CPUFrequency(); + // TODO: Debug why actual measurments sometimes causes problems. Issue #246. + cpu_mhz_ = hw::PIT::CPUFrequency(); - INFO2("+--> %f MHz", cpu_mhz_.count()); + INFO2("+--> %f MHz", cpu_mhz_.count()); **/ diff --git a/src/kernel/pci_manager.cpp b/src/kernel/pci_manager.cpp index e643043ea4..a0998e590f 100644 --- a/src/kernel/pci_manager.cpp +++ b/src/kernel/pci_manager.cpp @@ -35,11 +35,11 @@ void PCI_manager::init() { uint32_t id {PCI::WTF}; for (uint16_t pci_addr {0}; pci_addr < 255; ++pci_addr) { - id = hw::PCI_Device::read_dword(pci_addr, PCI::CONFIG_VENDOR); - if (id != PCI::WTF) { - hw::PCI_Device dev {pci_addr, id}; - devices_[dev.classcode()].emplace_back(dev); - } + id = hw::PCI_Device::read_dword(pci_addr, PCI::CONFIG_VENDOR); + if (id != PCI::WTF) { + hw::PCI_Device dev {pci_addr, id}; + devices_[dev.classcode()].emplace_back(dev); + } } // Pretty printing, end of device tree diff --git a/src/kernel/rdrand.cpp b/src/kernel/rdrand.cpp index aa927244c5..a24ece1541 100644 --- a/src/kernel/rdrand.cpp +++ b/src/kernel/rdrand.cpp @@ -25,9 +25,9 @@ bool rdrand16(uint16_t* result) { int res = 0; while (res == 0) - { - res = _rdrand16_step(result); - } + { + res = _rdrand16_step(result); + } return (res == 1); } @@ -35,8 +35,8 @@ bool rdrand32(uint32_t* result) { int res = 0; while (res == 0) - { - res = _rdrand32_step(result); - } + { + res = _rdrand32_step(result); + } return (res == 1); } diff --git a/src/kernel/syscalls.cpp b/src/kernel/syscalls.cpp index 706fb0288e..112cd976b1 100644 --- a/src/kernel/syscalls.cpp +++ b/src/kernel/syscalls.cpp @@ -111,7 +111,7 @@ int read(int UNUSED(file), void* UNUSED(ptr), size_t UNUSED(len)) { int write(int file, const void* ptr, size_t len) { if (file == syscall_fd and not debug_syscalls) { - return len; + return len; } return OS::rsprint((const char*) ptr, len); } diff --git a/src/kernel/terminal.cpp b/src/kernel/terminal.cpp index 781c4410b1..180983141c 100644 --- a/src/kernel/terminal.cpp +++ b/src/kernel/terminal.cpp @@ -32,22 +32,22 @@ Terminal::Terminal(Connection_ptr csock) : Terminal() { csock->onReceive( - [this] (auto conn, bool) - { - char buffer[1024]; - size_t bytes = conn->read(buffer, sizeof(buffer)); + [this] (auto conn, bool) + { + char buffer[1024]; + size_t bytes = conn->read(buffer, sizeof(buffer)); - this->read(buffer, bytes); - }); + this->read(buffer, bytes); + }); on_write = - [csock] (const char* buffer, size_t len) - { - csock->write(buffer, len); - }; + [csock] (const char* buffer, size_t len) + { + csock->write(buffer, len); + }; on_exit = - [csock] { + [csock] { csock->close(); }; // after setting up everything, show introduction @@ -58,29 +58,29 @@ Terminal::Terminal(hw::Serial& serial) : Terminal() { serial.on_data( - [this, &serial] (char c) - { - this->read(&c, 1); - if (c == CR) - { - c = LF; - this->read(&c, 1); - } - else - { - serial.write(c); - } - }); + [this, &serial] (char c) + { + this->read(&c, 1); + if (c == CR) + { + c = LF; + this->read(&c, 1); + } + else + { + serial.write(c); + } + }); on_write = - [&serial] (const char* buffer, size_t len) - { - for (size_t i = 0; i < len; i++) - serial.write(buffer[i]); - }; + [&serial] (const char* buffer, size_t len) + { + for (size_t i = 0; i < len; i++) + serial.write(buffer[i]); + }; on_exit = - [] { + [] { // do nothing }; // after setting up everything, show introduction @@ -90,86 +90,86 @@ Terminal::Terminal(hw::Serial& serial) void Terminal::read(const char* buf, size_t len) { while (len) + { + if (this->subcmd) + { + // execute options + option(this->subcmd, (uint8_t) *buf); + this->subcmd = 0; + } + else if (this->iac) + { + command(*(uint8_t*) buf); + this->iac = false; + } + else if (*buf == 13 && !newline) { - if (this->subcmd) - { - // execute options - option(this->subcmd, (uint8_t) *buf); - this->subcmd = 0; - } - else if (this->iac) - { - command(*(uint8_t*) buf); - this->iac = false; - } - else if (*buf == 13 && !newline) - { - newline = true; - } - else if (*buf == 10 && newline) - { - newline = false; - // parse message - run(buffer); - buffer.clear(); - } - else if (*buf == 0) - { - // NOP - } - else if ((uint8_t) *buf == 0xFF) - { - // Interpret as Command - this->iac = true; - } - else - { - buffer.append(buf, 1); - } - buf++; len--; + newline = true; } + else if (*buf == 10 && newline) + { + newline = false; + // parse message + run(buffer); + buffer.clear(); + } + else if (*buf == 0) + { + // NOP + } + else if ((uint8_t) *buf == 0xFF) + { + // Interpret as Command + this->iac = true; + } + else + { + buffer.append(buf, 1); + } + buf++; len--; + } } void Terminal::command(uint8_t cmd) { switch (cmd) - { - case 247: // erase char - printf("CMD: Erase char\n"); - break; - case 248: // erase line - printf("CMD: Erase line\n"); - break; - case 250: // Begin - printf("CMD: Begin...\n"); - break; - case 251: // Will USE - case 252: // Won't USE - case 253: // Start USE - case 254: // Stop USE - //printf("CMD: Command %d\n", cmd); - this->subcmd = cmd; - break; - case 255: - //printf("CMD: Command %d\n", cmd); - this->subcmd = cmd; - break; - default: - printf("CMD: Unknown command %d\n", cmd); - } + { + case 247: // erase char + printf("CMD: Erase char\n"); + break; + case 248: // erase line + printf("CMD: Erase line\n"); + break; + case 250: // Begin + printf("CMD: Begin...\n"); + break; + case 251: // Will USE + case 252: // Won't USE + case 253: // Start USE + case 254: // Stop USE + //printf("CMD: Command %d\n", cmd); + this->subcmd = cmd; + break; + case 255: + //printf("CMD: Command %d\n", cmd); + this->subcmd = cmd; + break; + default: + printf("CMD: Unknown command %d\n", cmd); + } } void Terminal::option(uint8_t option, uint8_t cmd) { (void) option; switch (cmd) - { - case 24: // terminal type - break; - default: - //printf("CMD: Unknown cmd %d for option %d\n", cmd, option); - break; - } + { + case 24: // terminal type + break; + default: + //printf("CMD: Unknown cmd %d for option %d\n", cmd, option); + break; + } } std::vector @@ -185,41 +185,41 @@ split(const std::string& text, std::string& command) x = text.find(" "); // early return for cmd-only msg if (x == std::string::npos) - { - command = text; - return retv; - } + { + command = text; + return retv; + } // command is substring command = text.substr(0, x); p = x+1; } // parse remainder do - { - x = text.find(" ", p+1); - size_t y = text.find(":", x+1); // find last param + { + x = text.find(" ", p+1); + size_t y = text.find(":", x+1); // find last param - if (y == x+1) - { - // single argument - retv.push_back(text.substr(p, x-p)); - // ending text argument - retv.push_back(text.substr(y+1)); - break; - } - else if (x != std::string::npos) - { - // single argument - retv.push_back(text.substr(p, x-p)); - } - else - { - // last argument - retv.push_back(text.substr(p)); - } - p = x+1; + if (y == x+1) + { + // single argument + retv.push_back(text.substr(p, x-p)); + // ending text argument + retv.push_back(text.substr(y+1)); + break; + } + else if (x != std::string::npos) + { + // single argument + retv.push_back(text.substr(p, x-p)); + } + else + { + // last argument + retv.push_back(text.substr(p)); + } + p = x+1; - } while (x != std::string::npos); + } while (x != std::string::npos); return retv; } @@ -229,20 +229,20 @@ void Terminal::run(const std::string& cmd_string) std::string cmd_name; auto cmd_vec = split(cmd_string, cmd_name); if (cmd_name.size()) - { - printf("Terminal::run(): %s\n", cmd_name.c_str()); + { + printf("Terminal::run(): %s\n", cmd_name.c_str()); - auto it = commands.find(cmd_name); - if (it != commands.end()) - { - int retv = it->second.main(cmd_vec); - if (retv) write("%s returned: %d\r\n", cmd_name.c_str(), retv); - } - else - { - write("No such command: '%s'\r\n", cmd_name.c_str()); - } + auto it = commands.find(cmd_name); + if (it != commands.end()) + { + int retv = it->second.main(cmd_vec); + if (retv) write("%s returned: %d\r\n", cmd_name.c_str(), retv); + } + else + { + write("No such command: '%s'\r\n", cmd_name.c_str()); } + } prompt(); } @@ -250,29 +250,29 @@ void Terminal::add_basic_commands() { // ?: add( - "?", "List available commands", - [this] (const std::vector&) -> int + "?", "List available commands", + [this] (const std::vector&) -> int + { + for (auto cmd : this->commands) { - for (auto cmd : this->commands) - { - write("%s \t-- %s\r\n", cmd.first.c_str(), cmd.second.desc.c_str()); - } - return 0; - }); + write("%s \t-- %s\r\n", cmd.first.c_str(), cmd.second.desc.c_str()); + } + return 0; + }); // exit: add( - "exit", "Close the terminal", - [this] (const std::vector&) -> int - { - this->on_exit(); - return 0; - }); + "exit", "Close the terminal", + [this] (const std::vector&) -> int + { + this->on_exit(); + return 0; + }); } void Terminal::intro() { std::string banana = - R"baaa( + R"baaa( ____ ___ | _ \ ___ _ _.' _ `. _ | [_) )' _ `._ _ ___ ! \ | | (_) | _ @@ -282,13 +282,13 @@ void Terminal::intro() !::, `-!_| | | |\ | | | | | \ !_!.' ':;! !::; ":;:!.!.\_!_!_!.!-'-':;:'' '''! ';:' `::;::;' '' ., . - `: .,. `' .::... . .::;::;' - `..:;::;:.. ::;::;:;:;, :;::;' + `: .,. `' .::... . .::;::;' + `..:;::;:.. ::;::;:;:;, :;::;' "-:;::;:;: ':;::;:'' ;.-' ""`---...________...---'"" - > Banana Terminal v1 < - )baaa"; +> Banana Terminal v1 < +)baaa"; write("%s", banana.c_str()); prompt(); diff --git a/src/kernel/terminal_disk.cpp b/src/kernel/terminal_disk.cpp index 77b8586a1c..03966875aa 100644 --- a/src/kernel/terminal_disk.cpp +++ b/src/kernel/terminal_disk.cpp @@ -45,116 +45,116 @@ void Terminal::add_disk_commands(Disk_ptr disk) // add 'cd' command add("cd", "Change current directory", - [this, curdir, disk] (const std::vector& args) -> int - { - // current directory, somehow... - std::string target = "/"; - if (!args.empty()) target = args[0]; + [this, curdir, disk] (const std::vector& args) -> int + { + // current directory, somehow... + std::string target = "/"; + if (!args.empty()) target = args[0]; - Path path(*curdir); - path += target; + Path path(*curdir); + path += target; - int rv = target_directory(disk, path); - if (rv) - { - this->write("cd: %s: No such file or directory\r\n", target.c_str()); - return rv; - } - *curdir = path.to_string(); - return 0; - }); + int rv = target_directory(disk, path); + if (rv) + { + this->write("cd: %s: No such file or directory\r\n", target.c_str()); + return rv; + } + *curdir = path.to_string(); + return 0; + }); // add 'ls' command add("ls", "List files in a folder", - [this, curdir, disk] (const std::vector& args) -> int - { - // current directory, somehow... - Path path(*curdir); - if (!args.empty()) path += args[0]; + [this, curdir, disk] (const std::vector& args) -> int + { + // current directory, somehow... + Path path(*curdir); + if (!args.empty()) path += args[0]; - int rv = target_directory(disk, path); - if (rv) - { - this->write("ls: %s: No such file or directory\r\n", path.to_string().c_str()); - return rv; - } + int rv = target_directory(disk, path); + if (rv) + { + this->write("ls: %s: No such file or directory\r\n", path.to_string().c_str()); + return rv; + } - std::string target = path.to_string(); + std::string target = path.to_string(); - auto& fs = disk->fs(); - auto vec = fs::new_shared_vector(); - auto err = fs.ls(target, vec); - if (!err) - { - this->write("%s \t%s \t%s \t%s\r\n", - "Name", "Size", "Type", "Sector"); - for (auto& ent : *vec) - { - this->write("%s \t%llu \t%s \t%llu\r\n", - ent.name().c_str(), ent.size, ent.type_string().c_str(), ent.block); - } - this->write("Total %u\r\n", vec->size()); - return 0; - } - else - { - this->write("Could not list %s\r\n", args[0].c_str()); - return 1; - } - }); + auto& fs = disk->fs(); + auto vec = fs::new_shared_vector(); + auto err = fs.ls(target, vec); + if (!err) + { + this->write("%s \t%s \t%s \t%s\r\n", + "Name", "Size", "Type", "Sector"); + for (auto& ent : *vec) + { + this->write("%s \t%llu \t%s \t%llu\r\n", + ent.name().c_str(), ent.size, ent.type_string().c_str(), ent.block); + } + this->write("Total %u\r\n", vec->size()); + return 0; + } + else + { + this->write("Could not list %s\r\n", args[0].c_str()); + return 1; + } + }); // add 'stat' command add("stat", "List file information", - [this, disk] (const std::vector& args) -> int + [this, disk] (const std::vector& args) -> int + { + if (!args.empty()) + { + auto& fs = disk->fs(); + auto ent = fs.stat(args[0]); + if (ent.is_valid()) + { + this->write("%s \t%s \t%s \t%s\r\n", + "Name", "Size", "Type", "Sector"); + this->write("%s \t%llu \t%s \t%llu\r\n", + ent.name().c_str(), ent.size, ent.type_string().c_str(), ent.block); + return 0; + } + else + { + this->write("stat: Cannot stat '%s'\r\n", args[0].c_str()); + return 1; + } + } + else { - if (!args.empty()) - { - auto& fs = disk->fs(); - auto ent = fs.stat(args[0]); - if (ent.is_valid()) - { - this->write("%s \t%s \t%s \t%s\r\n", - "Name", "Size", "Type", "Sector"); - this->write("%s \t%llu \t%s \t%llu\r\n", - ent.name().c_str(), ent.size, ent.type_string().c_str(), ent.block); - return 0; - } - else - { - this->write("stat: Cannot stat '%s'\r\n", args[0].c_str()); - return 1; - } - } - else - { - this->write("%s\r\n", "stat: Not enough arguments"); - return 1; - } - }); + this->write("%s\r\n", "stat: Not enough arguments"); + return 1; + } + }); // add 'cat' command add("cat", "Concatenate files and print", - [this, disk] (const std::vector& args) -> int - { - auto& fs = disk->fs(); + [this, disk] (const std::vector& args) -> int + { + auto& fs = disk->fs(); - for (const auto& file : args) - { - // get file information - auto ent = fs.stat(file); - if (!ent.is_valid()) - { - this->write("cat: '%s': No such file or directory\r\n", file.c_str()); - return 1; - } - // read file contents - auto buf = fs.read(ent, 0, ent.size); - if (!buf.buffer) - { - this->write("cat: '%s': I/O error\r\n", file.c_str()); - return 1; - } - // write to terminal client - std::string buffer((char*) buf.buffer.get(), buf.len); - this->write("%s\r\n", buffer.c_str()); - } - return 0; - }); + for (const auto& file : args) + { + // get file information + auto ent = fs.stat(file); + if (!ent.is_valid()) + { + this->write("cat: '%s': No such file or directory\r\n", file.c_str()); + return 1; + } + // read file contents + auto buf = fs.read(ent, 0, ent.size); + if (!buf.buffer) + { + this->write("cat: '%s': I/O error\r\n", file.c_str()); + return 1; + } + // write to terminal client + std::string buffer((char*) buf.buffer.get(), buf.len); + this->write("%s\r\n", buffer.c_str()); + } + return 0; + }); } diff --git a/src/kernel/vga.cpp b/src/kernel/vga.cpp index d48340b320..e820fc1328 100644 --- a/src/kernel/vga.cpp +++ b/src/kernel/vga.cpp @@ -25,10 +25,10 @@ static uint16_t make_vgaentry(const char c, const uint8_t color) noexcept { return c16 | color16 << 8; } const uint16_t ConsoleVGA::DEFAULT_ENTRY = - make_vgaentry(32, make_color(COLOR_LIGHT_GREY, COLOR_BLACK)); + make_vgaentry(32, make_color(COLOR_LIGHT_GREY, COLOR_BLACK)); ConsoleVGA::ConsoleVGA() noexcept: -row{0}, column{0} + row{0}, column{0} { this->color = make_color(COLOR_WHITE, COLOR_BLACK); this->buffer = reinterpret_cast(0xB8000); diff --git a/src/net/arp.cpp b/src/net/arp.cpp index ed43f967e2..46666b9eb0 100644 --- a/src/net/arp.cpp +++ b/src/net/arp.cpp @@ -27,205 +27,205 @@ namespace net { - static void ignore(Packet_ptr UNUSED(pckt)) { - debug2(" linklayer> Empty handler - DROP!\n"); - } +static void ignore(Packet_ptr UNUSED(pckt)) { + debug2(" linklayer> Empty handler - DROP!\n"); +} // Initialize - Arp::Arp(net::Inet& inet) noexcept: +Arp::Arp(net::Inet& inet) noexcept: inet_ {inet}, - mac_ (inet.link_addr()), - linklayer_out_ {ignore} + mac_ (inet.link_addr()), + linklayer_out_ {ignore} {} - void Arp::bottom(Packet_ptr pckt) { - debug2(" got %i bytes of data\n", pckt->size()); +void Arp::bottom(Packet_ptr pckt) { + debug2(" got %i bytes of data\n", pckt->size()); - header* hdr = reinterpret_cast(pckt->buffer()); + header* hdr = reinterpret_cast(pckt->buffer()); - debug2("Have valid cache? %s\n", is_valid_cached(hdr->sipaddr) ? "YES" : "NO"); - cache(hdr->sipaddr, hdr->shwaddr); + debug2("Have valid cache? %s\n", is_valid_cached(hdr->sipaddr) ? "YES" : "NO"); + cache(hdr->sipaddr, hdr->shwaddr); - switch(hdr->opcode) { + switch(hdr->opcode) { - case H_request: { - debug2("\t ARP REQUEST: "); - debug2("%s is looking for %s\n", - hdr->sipaddr.str().c_str(), - hdr->dipaddr.str().c_str()); + case H_request: { + debug2("\t ARP REQUEST: "); + debug2("%s is looking for %s\n", + hdr->sipaddr.str().c_str(), + hdr->dipaddr.str().c_str()); - if (hdr->dipaddr == inet_.ip_addr()) { - arp_respond(hdr); - } else { - debug2("\t NO MATCH for My IP (%s). DROP!\n", - inet_.ip_addr().str().c_str()); - } - break; + if (hdr->dipaddr == inet_.ip_addr()) { + arp_respond(hdr); + } else { + debug2("\t NO MATCH for My IP (%s). DROP!\n", + inet_.ip_addr().str().c_str()); } + break; + } - case H_reply: { - debug2("\t ARP REPLY: %s belongs to %s\n", - hdr->sipaddr.str().c_str(), hdr->shwaddr.str().c_str()); - - auto waiting = waiting_packets_.find(hdr->sipaddr); - - if (waiting != waiting_packets_.end()) { - debug("Had a packet waiting for this IP. Sending\n"); - transmit(waiting->second); - waiting_packets_.erase(waiting); - } - break; + case H_reply: { + debug2("\t ARP REPLY: %s belongs to %s\n", + hdr->sipaddr.str().c_str(), hdr->shwaddr.str().c_str()); + + auto waiting = waiting_packets_.find(hdr->sipaddr); + + if (waiting != waiting_packets_.end()) { + debug("Had a packet waiting for this IP. Sending\n"); + transmit(waiting->second); + waiting_packets_.erase(waiting); } - - default: - debug2("\t UNKNOWN OPCODE\n"); - break; - } //< switch(hdr->opcode) + break; } + + default: + debug2("\t UNKNOWN OPCODE\n"); + break; + } //< switch(hdr->opcode) +} - void Arp::cache(IP4::addr ip, Ethernet::addr mac) { - debug2("Caching IP %s for %s\n", ip.str().c_str(), mac.str().c_str()); +void Arp::cache(IP4::addr ip, Ethernet::addr mac) { + debug2("Caching IP %s for %s\n", ip.str().c_str(), mac.str().c_str()); - auto entry = cache_.find(ip); + auto entry = cache_.find(ip); - if (entry != cache_.end()) { - debug2("Cached entry found: %s recorded @ %llu. Updating timestamp\n", - entry->second.mac_.str().c_str(), entry->second.timestamp_); + if (entry != cache_.end()) { + debug2("Cached entry found: %s recorded @ %llu. Updating timestamp\n", + entry->second.mac_.str().c_str(), entry->second.timestamp_); - // Update - entry->second.update(); + // Update + entry->second.update(); - } else { - cache_[ip] = mac; // Insert - } + } else { + cache_[ip] = mac; // Insert } +} - bool Arp::is_valid_cached(IP4::addr ip) { - auto entry = cache_.find(ip); - - if (entry != cache_.end()) { - debug("Cached entry, mac: %s time: %llu Expiry: %llu\n", - entry->second.mac_.str().c_str(), - entry->second.timestamp_, entry->second.timestamp_ + cache_exp_t_); - debug("Time now: %llu\n", static_cast(OS::uptime())); - } +bool Arp::is_valid_cached(IP4::addr ip) { + auto entry = cache_.find(ip); - return entry != cache_.end() - and (entry->second.timestamp_ + cache_exp_t_ > static_cast(OS::uptime())); + if (entry != cache_.end()) { + debug("Cached entry, mac: %s time: %llu Expiry: %llu\n", + entry->second.mac_.str().c_str(), + entry->second.timestamp_, entry->second.timestamp_ + cache_exp_t_); + debug("Time now: %llu\n", static_cast(OS::uptime())); } + + return entry != cache_.end() + and (entry->second.timestamp_ + cache_exp_t_ > static_cast(OS::uptime())); +} - extern "C" { - unsigned long ether_crc(int length, unsigned char *data); - } +extern "C" { + unsigned long ether_crc(int length, unsigned char *data); +} - void Arp::arp_respond(header* hdr_in) { - debug2("\t IP Match. Constructing ARP Reply\n"); +void Arp::arp_respond(header* hdr_in) { + debug2("\t IP Match. Constructing ARP Reply\n"); - // Populate ARP-header - auto res = std::static_pointer_cast(inet_.createPacket(sizeof(header))); - res->init(mac_, inet_.ip_addr()); + // Populate ARP-header + auto res = std::static_pointer_cast(inet_.createPacket(sizeof(header))); + res->init(mac_, inet_.ip_addr()); - res->set_dest_mac(hdr_in->shwaddr); - res->set_dest_ip(hdr_in->sipaddr); - res->set_opcode(H_reply); + res->set_dest_mac(hdr_in->shwaddr); + res->set_dest_ip(hdr_in->sipaddr); + res->set_opcode(H_reply); - debug2("\t My IP: %s belongs to My Mac: %s\n", - res->source_ip().str().c_str(), res->source_mac().str().c_str()); + debug2("\t My IP: %s belongs to My Mac: %s\n", + res->source_ip().str().c_str(), res->source_mac().str().c_str()); - linklayer_out_(res); - } + linklayer_out_(res); +} - void Arp::transmit(Packet_ptr pckt) { - assert(pckt->size()); +void Arp::transmit(Packet_ptr pckt) { + assert(pckt->size()); - /** Get destination IP from IP header */ - IP4::ip_header* iphdr = reinterpret_cast(pckt->buffer() - + sizeof(Ethernet::header)); - IP4::addr sip = iphdr->saddr; - IP4::addr dip = pckt->next_hop(); + /** Get destination IP from IP header */ + IP4::ip_header* iphdr = reinterpret_cast(pckt->buffer() + + sizeof(Ethernet::header)); + IP4::addr sip = iphdr->saddr; + IP4::addr dip = pckt->next_hop(); - debug2(" physical> Transmitting %i bytes to %s\n", - pckt->size(), dip.str().c_str()); + debug2(" physical> Transmitting %i bytes to %s\n", + pckt->size(), dip.str().c_str()); - Ethernet::addr dest_mac; + Ethernet::addr dest_mac; - if (iphdr->daddr == IP4::INADDR_BCAST) { - // When broadcasting our source IP should be either - // our own IP or 0.0.0.0 + if (iphdr->daddr == IP4::INADDR_BCAST) { + // When broadcasting our source IP should be either + // our own IP or 0.0.0.0 - if (sip != inet_.ip_addr() && sip != IP4::INADDR_ANY) { - debug2(" Dropping outbound broadcast packet due to " - "invalid source IP %s\n", sip.str().c_str()); - return; - } - // mui importante - dest_mac = Ethernet::addr::BROADCAST_FRAME; + if (sip != inet_.ip_addr() && sip != IP4::INADDR_ANY) { + debug2(" Dropping outbound broadcast packet due to " + "invalid source IP %s\n", sip.str().c_str()); + return; + } + // mui importante + dest_mac = Ethernet::addr::BROADCAST_FRAME; - } else { - if (sip != inet_.ip_addr()) { - debug2(" physical> Not bound to source IP %s. My IP is %s. DROP!\n", - sip.str().c_str(), inet_.ip_addr().str().c_str()); - return; - } + } else { + if (sip != inet_.ip_addr()) { + debug2(" physical> Not bound to source IP %s. My IP is %s. DROP!\n", + sip.str().c_str(), inet_.ip_addr().str().c_str()); + return; + } - // If we don't have a cached IP, perform address resolution - if (!is_valid_cached(dip)) { + // If we don't have a cached IP, perform address resolution + if (!is_valid_cached(dip)) { arp_resolver_(pckt); return; - } - - // Get MAC from cache - dest_mac = cache_[dip].mac_; } - - /** Attach next-hop mac and ethertype to ethernet header */ - Ethernet::header* ethhdr = reinterpret_cast(pckt->buffer()); - ethhdr->src = mac_; - ethhdr->dest = dest_mac; - ethhdr->type = Ethernet::ETH_IP4; - - debug2(" physical> Sending packet to %s\n", mac_.str().c_str()); - linklayer_out_(pckt); - } - - void Arp::await_resolution(Packet_ptr pckt, IP4::addr) { - auto queue = waiting_packets_.find(pckt->next_hop()); - - if (queue != waiting_packets_.end()) { - debug(" Packets already queueing for this IP\n"); - queue->second->chain(pckt); - } else { - debug(" This is the first packet going to that IP\n"); - waiting_packets_.emplace(std::make_pair(pckt->next_hop(), pckt)); - } + + // Get MAC from cache + dest_mac = cache_[dip].mac_; } - - void Arp::arp_resolve(Packet_ptr pckt) { - debug(" %s\n", pckt->next_hop().str().c_str()); - - await_resolution(pckt, pckt->next_hop()); - - auto req = view_packet_as(inet_.createPacket(sizeof(header))); - req->init(mac_, inet_.ip_addr()); - req->set_dest_mac(Ethernet::addr::BROADCAST_FRAME); - req->set_dest_ip(pckt->next_hop()); - req->set_opcode(H_request); - - linklayer_out_(req); - } - - void Arp::hh_map(Packet_ptr pckt) { - (void) pckt; - debug("ARP-resolution using the HH-hack"); - /** - // Fixed mac prefix - mac.minor = 0x01c0; //Big-endian c001 - // Destination IP - mac.major = dip.whole; - debug("ARP cache missing. Guessing Mac %s from next-hop IP: %s (dest.ip: %s)", - mac.str().c_str(), dip.str().c_str(), iphdr->daddr.str().c_str()); - **/ - } + /** Attach next-hop mac and ethertype to ethernet header */ + Ethernet::header* ethhdr = reinterpret_cast(pckt->buffer()); + ethhdr->src = mac_; + ethhdr->dest = dest_mac; + ethhdr->type = Ethernet::ETH_IP4; + + debug2(" physical> Sending packet to %s\n", mac_.str().c_str()); + linklayer_out_(pckt); +} + +void Arp::await_resolution(Packet_ptr pckt, IP4::addr) { + auto queue = waiting_packets_.find(pckt->next_hop()); + + if (queue != waiting_packets_.end()) { + debug(" Packets already queueing for this IP\n"); + queue->second->chain(pckt); + } else { + debug(" This is the first packet going to that IP\n"); + waiting_packets_.emplace(std::make_pair(pckt->next_hop(), pckt)); + } +} + +void Arp::arp_resolve(Packet_ptr pckt) { + debug(" %s\n", pckt->next_hop().str().c_str()); + + await_resolution(pckt, pckt->next_hop()); + + auto req = view_packet_as(inet_.createPacket(sizeof(header))); + req->init(mac_, inet_.ip_addr()); + + req->set_dest_mac(Ethernet::addr::BROADCAST_FRAME); + req->set_dest_ip(pckt->next_hop()); + req->set_opcode(H_request); + + linklayer_out_(req); +} + +void Arp::hh_map(Packet_ptr pckt) { + (void) pckt; + debug("ARP-resolution using the HH-hack"); + /** + // Fixed mac prefix + mac.minor = 0x01c0; //Big-endian c001 + // Destination IP + mac.major = dip.whole; + debug("ARP cache missing. Guessing Mac %s from next-hop IP: %s (dest.ip: %s)", + mac.str().c_str(), dip.str().c_str(), iphdr->daddr.str().c_str()); + **/ +} } //< namespace net diff --git a/src/net/buffer_store.cpp b/src/net/buffer_store.cpp index 8b575538e4..16000a4fef 100644 --- a/src/net/buffer_store.cpp +++ b/src/net/buffer_store.cpp @@ -24,16 +24,16 @@ namespace net { - BufferStore::BufferStore(size_t num, size_t bufsize, size_t device_offset ) : - bufcount_ {num}, - bufsize_ {bufsize}, - device_offset_ {device_offset}, - pool_ {static_cast(memalign(PAGE_SIZE, num * bufsize))} +BufferStore::BufferStore(size_t num, size_t bufsize, size_t device_offset ) : + bufcount_ {num}, + bufsize_ {bufsize}, + device_offset_ {device_offset}, + pool_ {static_cast(memalign(PAGE_SIZE, num * bufsize))} { assert(pool_); debug (" Creating buffer store of %i * %i bytes.\n", - num, bufsize); + num, bufsize); for (buffer_t b = pool_; b < pool_ + (num * bufsize); b += bufsize) available_buffers_.push_back(b); @@ -42,62 +42,62 @@ namespace net { available_buffers_.size(), pool_, pool_ + (bufcount_ * bufsize_)); } - BufferStore::~BufferStore() { - free(pool_); - } +BufferStore::~BufferStore() { + free(pool_); +} - /** - * @todo : We (think we) want a list of pools, that we increase as needed. - */ - void BufferStore::increaseStorage() { - panic(" Storage pool full! Don't know how to increase pool size yet.\n"); - } +/** + * @todo : We (think we) want a list of pools, that we increase as needed. + */ +void BufferStore::increaseStorage() { + panic(" Storage pool full! Don't know how to increase pool size yet.\n"); +} - BufferStore::buffer_t BufferStore::get_raw_buffer() { - if (available_buffers_.empty()) - increaseStorage(); +BufferStore::buffer_t BufferStore::get_raw_buffer() { + if (available_buffers_.empty()) + increaseStorage(); - auto buf = available_buffers_.front(); - available_buffers_.pop_front(); + auto buf = available_buffers_.front(); + available_buffers_.pop_front(); - debug2(" Provisioned a buffer. %i buffers remaining.\n", - available_buffers_.size()); - - return buf; - } - - BufferStore::buffer_t BufferStore::get_offset_buffer() { - return get_raw_buffer() + device_offset_; - } - - void BufferStore::release_raw_buffer(buffer_t b, size_t bufsize) { - debug2(" Trying to release %i sized buffer @%p.\n", bufsize, b); - // Make sure the buffer comes from here. Otherwise, ignore it. - if (address_is_from_pool(b) - and address_is_bufstart(b) - and bufsize == bufsize_) - { - available_buffers_.push_back(b); - debug(" Releasing %p. %i available buffers.\n", b, available_buffers_.size()); - return; - } - - debug(" IGNORING buffer @%p. It isn't mine.\n", b); - } - - void BufferStore::release_offset_buffer(buffer_t b, size_t bufsize) { - debug2(" Trying to release %i + %i sized buffer @%p.\n", bufsize, device_offset_, b); - // Make sure the buffer comes from here. Otherwise, ignore it. - if (address_is_from_pool(b) - and address_is_offset_bufstart(b) - and bufsize == bufsize_ - device_offset_) - { - available_buffers_.push_back(b - device_offset_); - debug(" Releasing %p. %i available buffers.\n", b, available_buffers_.size()); - return; - } - - debug(" IGNORING buffer @%p. It isn't mine.\n", b); - } + debug2(" Provisioned a buffer. %i buffers remaining.\n", + available_buffers_.size()); + + return buf; +} + +BufferStore::buffer_t BufferStore::get_offset_buffer() { + return get_raw_buffer() + device_offset_; +} + +void BufferStore::release_raw_buffer(buffer_t b, size_t bufsize) { + debug2(" Trying to release %i sized buffer @%p.\n", bufsize, b); + // Make sure the buffer comes from here. Otherwise, ignore it. + if (address_is_from_pool(b) + and address_is_bufstart(b) + and bufsize == bufsize_) + { + available_buffers_.push_back(b); + debug(" Releasing %p. %i available buffers.\n", b, available_buffers_.size()); + return; + } + + debug(" IGNORING buffer @%p. It isn't mine.\n", b); +} + +void BufferStore::release_offset_buffer(buffer_t b, size_t bufsize) { + debug2(" Trying to release %i + %i sized buffer @%p.\n", bufsize, device_offset_, b); + // Make sure the buffer comes from here. Otherwise, ignore it. + if (address_is_from_pool(b) + and address_is_offset_bufstart(b) + and bufsize == bufsize_ - device_offset_) + { + available_buffers_.push_back(b - device_offset_); + debug(" Releasing %p. %i available buffers.\n", b, available_buffers_.size()); + return; + } + + debug(" IGNORING buffer @%p. It isn't mine.\n", b); +} } //< namespace net diff --git a/src/net/dhcp/dh4client.cpp b/src/net/dhcp/dh4client.cpp index 94d5341fa8..9e2f8740f0 100644 --- a/src/net/dhcp/dh4client.cpp +++ b/src/net/dhcp/dh4client.cpp @@ -220,29 +220,29 @@ namespace net socket.bcast(IP4::INADDR_ANY, DHCP_DEST_PORT, packet, packetlen); socket.onRead( - [this] (Socket& sock, IP4::addr addr, UDP::port_t port, - const char* data, int len) -> int - { - (void) addr; - if (port == DHCP_DEST_PORT) - { - // we have got a DHCP Offer - debug("Received possible DHCP OFFER from %s:%d\n", - addr.str().c_str(), DHCP_DEST_PORT); - this->offer(sock, data, len); - } - return -1; - }); + [this] (Socket& sock, IP4::addr addr, UDP::port_t port, + const char* data, int len) -> int + { + (void) addr; + if (port == DHCP_DEST_PORT) + { + // we have got a DHCP Offer + debug("Received possible DHCP OFFER from %s:%d\n", + addr.str().c_str(), DHCP_DEST_PORT); + this->offer(sock, data, len); + } + return -1; + }); } const dhcp_option_t* get_option(const uint8_t* options, uint8_t code) { const dhcp_option_t* opt = (const dhcp_option_t*) options; while (opt->code != code && opt->code != DHO_END) - { - // go to next option - opt = (const dhcp_option_t*) (((const uint8_t*) opt) + 2 + opt->length); - } + { + // go to next option + opt = (const dhcp_option_t*) (((const uint8_t*) opt) + 2 + opt->length); + } return opt; } @@ -260,68 +260,68 @@ namespace net opt = get_option(dhcp->options, DHO_DHCP_MESSAGE_TYPE); if (opt->code == DHO_DHCP_MESSAGE_TYPE) - { - // verify that the type is indeed DHCPOFFER - debug("Found DHCP message type %d (DHCP Offer = %d)\n", - opt->val[0], DHCPOFFER); + { + // verify that the type is indeed DHCPOFFER + debug("Found DHCP message type %d (DHCP Offer = %d)\n", + opt->val[0], DHCPOFFER); - // ignore when not a DHCP Offer - if (opt->val[0] != DHCPOFFER) return; - } + // ignore when not a DHCP Offer + if (opt->val[0] != DHCPOFFER) return; + } // ignore message when DHCP message type is missing else return; // the offered IP address: this->ipaddr = dhcp->yiaddr; MYINFO("IP ADDRESS: \t%s", - this->ipaddr.str().c_str()); + this->ipaddr.str().c_str()); opt = get_option(dhcp->options, DHO_SUBNET_MASK); if (opt->code == DHO_SUBNET_MASK) - { - memcpy(&this->netmask, opt->val, sizeof(IP4::addr)); - MYINFO("SUBNET MASK: \t%s", - this->netmask.str().c_str()); - } + { + memcpy(&this->netmask, opt->val, sizeof(IP4::addr)); + MYINFO("SUBNET MASK: \t%s", + this->netmask.str().c_str()); + } opt = get_option(dhcp->options, DHO_DHCP_LEASE_TIME); if (opt->code == DHO_DHCP_LEASE_TIME) - { - memcpy(&this->lease_time, opt->val, sizeof(this->lease_time)); - MYINFO("LEASE TIME: \t%u mins", this->lease_time / 60); - } + { + memcpy(&this->lease_time, opt->val, sizeof(this->lease_time)); + MYINFO("LEASE TIME: \t%u mins", this->lease_time / 60); + } // now validate the offer, checking for minimum information opt = get_option(dhcp->options, DHO_ROUTERS); if (opt->code == DHO_ROUTERS) - { - memcpy(&this->router, opt->val, sizeof(IP4::addr)); - MYINFO("GATEWAY: \t%s", - this->router.str().c_str()); - } + { + memcpy(&this->router, opt->val, sizeof(IP4::addr)); + MYINFO("GATEWAY: \t%s", + this->router.str().c_str()); + } // assume that the server we received the request from is the gateway else + { + opt = get_option(dhcp->options, DHO_DHCP_SERVER_IDENTIFIER); + if (opt->code == DHO_DHCP_SERVER_IDENTIFIER) { - opt = get_option(dhcp->options, DHO_DHCP_SERVER_IDENTIFIER); - if (opt->code == DHO_DHCP_SERVER_IDENTIFIER) - { - memcpy(&this->router, opt->val, sizeof(IP4::addr)); - MYINFO("GATEWAY: \t%s", - this->router.str().c_str()); - } - // silently ignore when both ROUTER and SERVER_ID is missing - else return; + memcpy(&this->router, opt->val, sizeof(IP4::addr)); + MYINFO("GATEWAY: \t%s", + this->router.str().c_str()); } + // silently ignore when both ROUTER and SERVER_ID is missing + else return; + } opt = get_option(dhcp->options, DHO_DOMAIN_NAME_SERVERS); if (opt->code == DHO_DOMAIN_NAME_SERVERS) - { - memcpy(&this->dns_server, opt->val, sizeof(IP4::addr)); - } + { + memcpy(&this->dns_server, opt->val, sizeof(IP4::addr)); + } else - { // just try using ROUTER as DNS server - this->dns_server = this->router; - } + { // just try using ROUTER as DNS server + this->dns_server = this->router; + } MYINFO("DNS SERVER: \t%s", this->dns_server.str().c_str()); // we can accept the offer now by requesting the IP! @@ -396,19 +396,19 @@ namespace net // set our onRead function to point to a hopeful DHCP ACK! sock.onRead( - [this] (Socket&, IP4::addr addr, UDP::port_t port, - const char* data, int len) -> int - { - (void) addr; - if (port == DHCP_DEST_PORT) - { - // we have hopefully got a DHCP Ack - debug("\tReceived DHCP ACK from %s:%d\n", - addr.str().c_str(), DHCP_DEST_PORT); - this->acknowledge(data, len); - } - return -1; - }); + [this] (Socket&, IP4::addr addr, UDP::port_t port, + const char* data, int len) -> int + { + (void) addr; + if (port == DHCP_DEST_PORT) + { + // we have hopefully got a DHCP Ack + debug("\tReceived DHCP ACK from %s:%d\n", + addr.str().c_str(), DHCP_DEST_PORT); + this->acknowledge(data, len); + } + return -1; + }); // send our DHCP Request sock.bcast(IP4::INADDR_ANY, DHCP_DEST_PORT, packet, packetlen); @@ -428,14 +428,14 @@ namespace net opt = get_option(dhcp->options, DHO_DHCP_MESSAGE_TYPE); if (opt->code == DHO_DHCP_MESSAGE_TYPE) - { - // verify that the type is indeed DHCPOFFER - debug("\tFound DHCP message type %d (DHCP Ack = %d)\n", - opt->val[0], DHCPACK); + { + // verify that the type is indeed DHCPOFFER + debug("\tFound DHCP message type %d (DHCP Ack = %d)\n", + opt->val[0], DHCPACK); - // ignore when not a DHCP Offer - if (opt->val[0] != DHCPACK) return; - } + // ignore when not a DHCP Offer + if (opt->val[0] != DHCPACK) return; + } // ignore message when DHCP message type is missing else return; diff --git a/src/net/dns/client.cpp b/src/net/dns/client.cpp index d17d9d570b..3b8fffa4fb 100644 --- a/src/net/dns/client.cpp +++ b/src/net/dns/client.cpp @@ -39,14 +39,14 @@ namespace net // wait for response // FIXME: WE DO NOT CHECK TRANSACTION IDS HERE (yet), GOD HELP US ALL sock.onRead( [this, hostname, request, func] - (Socket&, IP4::addr, UDP::port_t, const char* data, int) mutable -> int - { - // original request ID = this->id; - request.parseResponse(data); + (Socket&, IP4::addr, UDP::port_t, const char* data, int) mutable -> int + { + // original request ID = this->id; + request.parseResponse(data); - // fire onResolve event - func(this->stack, hostname, request.getFirstIP4()); - return -1; - }); + // fire onResolve event + func(this->stack, hostname, request.getFirstIP4()); + return -1; + }); } } diff --git a/src/net/dns/dns.cpp b/src/net/dns/dns.cpp index 56f28e6c0d..a1e6a39537 100644 --- a/src/net/dns/dns.cpp +++ b/src/net/dns/dns.cpp @@ -32,12 +32,12 @@ namespace net std::string resp; while (*(tmp)!=0) - { - int len = *tmp++; - resp.append((char*) tmp, len); - resp.append("."); - tmp += len; - } + { + int len = *tmp++; + resp.append((char*) tmp, len); + resp.append("."); + tmp += len; + } return resp; } @@ -79,7 +79,7 @@ namespace net // initial response size unsigned short packetlen = sizeof(header) + - sizeof(question) + parsed_query.size() + 1; + sizeof(question) + parsed_query.size() + 1; // set DNS QR to RESPONSE hdr.qr = DNS_QR_RESPONSE; @@ -91,45 +91,45 @@ namespace net std::vector* addrs = lookup(parsed_query); if (addrs == nullptr) - { - // not found - debug("*** Could not find: %s", parsed_query.c_str()); - hdr.ans_count = 0; - hdr.rcode = DNS::NO_ERROR; - } + { + // not found + debug("*** Could not find: %s", parsed_query.c_str()); + hdr.ans_count = 0; + hdr.rcode = DNS::NO_ERROR; + } else + { + debug("*** Found %lu results for %s", addrs->size(), parsed_query.c_str()); + // append answers + for (auto addr : *addrs) { - debug("*** Found %lu results for %s", addrs->size(), parsed_query.c_str()); - // append answers - for (auto addr : *addrs) - { - debug("*** Result: %s", addr.str().c_str()); - // add query - int qlen = parsed_query.size() + 1; - memcpy(buffer, query, qlen); - buffer += qlen; - packetlen += qlen; // (!) + debug("*** Result: %s", addr.str().c_str()); + // add query + int qlen = parsed_query.size() + 1; + memcpy(buffer, query, qlen); + buffer += qlen; + packetlen += qlen; // (!) - // add resource record - rr_data* data = (rr_data*) buffer; + // add resource record + rr_data* data = (rr_data*) buffer; - data->type = htons(DNS_TYPE_A); - data->_class = htons(DNS_CLASS_INET); - data->ttl = htons(0x7FFF); // just because - data->data_len = htons(sizeof(IP4::addr)); - buffer += sizeof(rr_data); + data->type = htons(DNS_TYPE_A); + data->_class = htons(DNS_CLASS_INET); + data->ttl = htons(0x7FFF); // just because + data->data_len = htons(sizeof(IP4::addr)); + buffer += sizeof(rr_data); - // add resource itself - *((IP4::addr*) buffer) = addr; // IPv4 address - buffer += sizeof(IP4::addr); + // add resource itself + *((IP4::addr*) buffer) = addr; // IPv4 address + buffer += sizeof(IP4::addr); - packetlen += sizeof(rr_data) + sizeof(IP4::addr); // (!) - } // addr + packetlen += sizeof(rr_data) + sizeof(IP4::addr); // (!) + } // addr - // set dns header answer count (!) - hdr.ans_count = htons((addrs->size() & 0xFFFF)); - hdr.rcode = DNS::NO_ERROR; - } + // set dns header answer count (!) + hdr.ans_count = htons((addrs->size() & 0xFFFF)); + hdr.rcode = DNS::NO_ERROR; + } return packetlen; } @@ -160,7 +160,7 @@ namespace net dns->auth_count = 0; dns->add_count = 0; - // point to the query portion + // point to the query portion char* qname = buffer + sizeof(DNS::header); // convert host to dns name format @@ -197,7 +197,7 @@ namespace net for (int i = 0; i < ntohs(dns->auth_count); i++) auth.emplace_back(reader, buffer); - // parse additional + // parse additional for (int i = 0; i < ntohs(dns->add_count); i++) addit.emplace_back(reader, buffer); @@ -231,24 +231,24 @@ namespace net // convert www.google.com to 3www6google3com void DNS::Request::dnsNameFormat(char* dns) { - int lock = 0; + int lock = 0; - std::string copy = this->hostname + "."; - int len = copy.size(); + std::string copy = this->hostname + "."; + int len = copy.size(); - for(int i = 0; i < len; i++) + for(int i = 0; i < len; i++) { - if (copy[i] == '.') + if (copy[i] == '.') { - *dns++ = i - lock; - for(; lock < i; lock++) + *dns++ = i - lock; + for(; lock < i; lock++) { - *dns++ = copy[lock]; + *dns++ = copy[lock]; } - lock++; + lock++; } } - *dns++ = '\0'; + *dns++ = '\0'; } DNS::Request::rr_t::rr_t(const char*& reader, const char* buffer) @@ -263,54 +263,54 @@ namespace net // if its an ipv4 address if (ntohs(resource.type) == DNS_TYPE_A) - { - int len = ntohs(resource.data_len); + { + int len = ntohs(resource.data_len); - this->rdata = std::string(reader, len); - reader += len; - } + this->rdata = std::string(reader, len); + reader += len; + } else - { - this->rdata = readName(reader, buffer, stop); - reader += stop; - } + { + this->rdata = readName(reader, buffer, stop); + reader += stop; + } } IP4::addr DNS::Request::rr_t::getIP4() const { switch (ntohs(resource.type)) - { - case DNS_TYPE_A: - { - IP4::addr* addr = (IP4::addr*) rdata.c_str(); - return *addr; - } - case DNS_TYPE_ALIAS: - case DNS_TYPE_NS: - default: - return IP4::addr{{0}}; - } + { + case DNS_TYPE_A: + { + IP4::addr* addr = (IP4::addr*) rdata.c_str(); + return *addr; + } + case DNS_TYPE_ALIAS: + case DNS_TYPE_NS: + default: + return IP4::addr{{0}}; + } } void DNS::Request::rr_t::print() { printf("Name: %s ", name.c_str()); switch (ntohs(resource.type)) + { + case DNS_TYPE_A: { - case DNS_TYPE_A: - { - IP4::addr* addr = (IP4::addr*) rdata.c_str(); - printf("has IPv4 address: %s", addr->str().c_str()); - } - break; - case DNS_TYPE_ALIAS: - printf("has alias: %s", rdata.c_str()); - break; - case DNS_TYPE_NS: - printf("has authoritative nameserver : %s", rdata.c_str()); - break; - default: - printf("has unknown resource type: %d", ntohs(resource.type)); + IP4::addr* addr = (IP4::addr*) rdata.c_str(); + printf("has IPv4 address: %s", addr->str().c_str()); } + break; + case DNS_TYPE_ALIAS: + printf("has alias: %s", rdata.c_str()); + break; + case DNS_TYPE_NS: + printf("has authoritative nameserver : %s", rdata.c_str()); + break; + default: + printf("has unknown resource type: %d", ntohs(resource.type)); + } printf("\n"); } @@ -325,22 +325,22 @@ namespace net unsigned char* ureader = (unsigned char*) reader; while (*ureader) + { + if (*ureader >= 192) { - if (*ureader >= 192) - { - offset = (*ureader) * 256 + *(ureader+1) - 49152; // = 11000000 00000000 - ureader = (unsigned char*) buffer + offset - 1; - jumped = true; // we have jumped to another location so counting wont go up! - } - else - { - name[p++] = *ureader; - } - ureader++; - - // if we havent jumped to another location then we can count up - if (jumped == false) count++; + offset = (*ureader) * 256 + *(ureader+1) - 49152; // = 11000000 00000000 + ureader = (unsigned char*) buffer + offset - 1; + jumped = true; // we have jumped to another location so counting wont go up! + } + else + { + name[p++] = *ureader; } + ureader++; + + // if we havent jumped to another location then we can count up + if (jumped == false) count++; + } name.resize(p); // number of steps we actually moved forward in the packet @@ -351,16 +351,16 @@ namespace net int len = p; // same as name.size() int i; for(i = 0; i < len; i++) - { - p = name[i]; + { + p = name[i]; - for(unsigned j = 0; j < p; j++) - { - name[i] = name[i+1]; - i++; - } - name[i] = '.'; + for(unsigned j = 0; j < p; j++) + { + name[i] = name[i+1]; + i++; } + name[i] = '.'; + } name[i - 1] = '\0'; // remove the last dot return name; diff --git a/src/net/ethernet.cpp b/src/net/ethernet.cpp index 75af7441e2..42dc4aaf28 100644 --- a/src/net/ethernet.cpp +++ b/src/net/ethernet.cpp @@ -26,90 +26,90 @@ namespace net { - // uint16_t(0x0000), uint32_t(0x01000000) - const Ethernet::addr Ethernet::addr::MULTICAST_FRAME {{0,0,0x01,0,0,0}}; +// uint16_t(0x0000), uint32_t(0x01000000) +const Ethernet::addr Ethernet::addr::MULTICAST_FRAME {{0,0,0x01,0,0,0}}; - // uint16_t(0xFFFF), uint32_t(0xFFFFFFFF) - const Ethernet::addr Ethernet::addr::BROADCAST_FRAME {{0xff,0xff,0xff,0xff,0xff,0xff}}; +// uint16_t(0xFFFF), uint32_t(0xFFFFFFFF) +const Ethernet::addr Ethernet::addr::BROADCAST_FRAME {{0xff,0xff,0xff,0xff,0xff,0xff}}; - // uint16_t(0x3333), uint32_t(0x01000000) - const Ethernet::addr Ethernet::addr::IPv6mcast_01 {{0x33,0x33,0x01,0,0,0}}; +// uint16_t(0x3333), uint32_t(0x01000000) +const Ethernet::addr Ethernet::addr::IPv6mcast_01 {{0x33,0x33,0x01,0,0,0}}; - // uint16_t(0x3333), uint32_t(0x02000000) - const Ethernet::addr Ethernet::addr::IPv6mcast_02 {{0x33,0x33,0x02,0,0,0}}; +// uint16_t(0x3333), uint32_t(0x02000000) +const Ethernet::addr Ethernet::addr::IPv6mcast_02 {{0x33,0x33,0x02,0,0,0}}; - static void ignore(Packet_ptr UNUSED(pckt)) noexcept { - debug(" Ignoring data (no real handler)\n"); - } +static void ignore(Packet_ptr UNUSED(pckt)) noexcept { + debug(" Ignoring data (no real handler)\n"); +} - Ethernet::Ethernet(addr mac) noexcept +Ethernet::Ethernet(addr mac) noexcept : mac_(mac), ip4_handler_{ignore}, ip6_handler_{ignore}, arp_handler_{ignore} {} - void Ethernet::transmit(Packet_ptr pckt) { - header* hdr = reinterpret_cast(pckt->buffer()); +void Ethernet::transmit(Packet_ptr pckt) { + header* hdr = reinterpret_cast(pckt->buffer()); - // Verify ethernet header - assert(hdr->dest.major != 0 || hdr->dest.minor !=0); - assert(hdr->type != 0); + // Verify ethernet header + assert(hdr->dest.major != 0 || hdr->dest.minor !=0); + assert(hdr->type != 0); - // Add source address - hdr->src = mac_; + // Add source address + hdr->src = mac_; - debug2(" Transmitting %i b, from %s -> %s. Type: %i\n", - pckt->size(), mac_.str().c_str(), hdr->dest.str().c_str(), hdr->type); + debug2(" Transmitting %i b, from %s -> %s. Type: %i\n", + pckt->size(), mac_.str().c_str(), hdr->dest.str().c_str(), hdr->type); - physical_out_(pckt); - } + physical_out_(pckt); +} + +void Ethernet::bottom(Packet_ptr pckt) { + assert(pckt->size() > 0); + + header* eth = reinterpret_cast(pckt->buffer()); + + /** Do we pass on ethernet headers? As for now, yes. + data += sizeof(header); + len -= sizeof(header); + */ + debug2(" %s => %s , Eth.type: 0x%x ", + eth->src.str().c_str(), eth->dest.str().c_str(), eth->type); + + switch(eth->type) { + case ETH_IP4: + debug2("IPv4 packet\n"); + ip4_handler_(pckt); + break; + + case ETH_IP6: + debug2("IPv6 packet\n"); + ip6_handler_(pckt); + break; + + case ETH_ARP: + debug2("ARP packet\n"); + arp_handler_(pckt); + break; + + case ETH_WOL: + debug2("Wake-on-LAN packet\n"); + break; + + case ETH_VLAN: + debug("VLAN tagged frame (not yet supported)"); + break; - void Ethernet::bottom(Packet_ptr pckt) { - assert(pckt->size() > 0); - - header* eth = reinterpret_cast(pckt->buffer()); - - /** Do we pass on ethernet headers? As for now, yes. - data += sizeof(header); - len -= sizeof(header); - */ - debug2(" %s => %s , Eth.type: 0x%x ", - eth->src.str().c_str(), eth->dest.str().c_str(), eth->type); - - switch(eth->type) { - case ETH_IP4: - debug2("IPv4 packet\n"); - ip4_handler_(pckt); - break; - - case ETH_IP6: - debug2("IPv6 packet\n"); - ip6_handler_(pckt); - break; - - case ETH_ARP: - debug2("ARP packet\n"); - arp_handler_(pckt); - break; - - case ETH_WOL: - debug2("Wake-on-LAN packet\n"); - break; - - case ETH_VLAN: - debug("VLAN tagged frame (not yet supported)"); - break; - - default: - // This might be 802.3 LLC traffic - if (net::ntohs(eth->type) > 1500) { - debug(" UNKNOWN ethertype 0x%x\n", ntohs(eth->type)); - }else { - debug2("IEEE802.3 Length field: 0x%x\n", ntohs(eth->type)); - } - break; + default: + // This might be 802.3 LLC traffic + if (net::ntohs(eth->type) > 1500) { + debug(" UNKNOWN ethertype 0x%x\n", ntohs(eth->type)); + }else { + debug2("IEEE802.3 Length field: 0x%x\n", ntohs(eth->type)); } + break; } +} } // namespace net diff --git a/src/net/inet.cpp b/src/net/inet.cpp index 760c9a2931..a22428e9e3 100644 --- a/src/net/inet.cpp +++ b/src/net/inet.cpp @@ -22,10 +22,10 @@ namespace net { Inet::Inet() : - //_eth(eth0.mac()),_arp(eth0.mac(),ip) - _ip4(_ip4_list[0],_netmask_list[0]), _udp(_ip4_list[0]), - _ip6(_ip6_list[0]), - _icmp6(_ip6_list[0]), _udp6(_ip6_list[0]) + //_eth(eth0.mac()),_arp(eth0.mac(),ip) + _ip4(_ip4_list[0],_netmask_list[0]), _udp(_ip4_list[0]), + _ip6(_ip6_list[0]), + _icmp6(_ip6_list[0]), _udp6(_ip6_list[0]) { // For now we're just using the one interface auto& eth0 = Dev::eth<0,VirtioNet>(); diff --git a/src/net/inet_common.cpp b/src/net/inet_common.cpp index e96efc4a44..e5b135f7d5 100644 --- a/src/net/inet_common.cpp +++ b/src/net/inet_common.cpp @@ -23,27 +23,27 @@ namespace net { - // Should be pretty much like the example in RFC 1071, - // but using a uinon for readability - uint16_t checksum(void* data, size_t len) noexcept { +// Should be pretty much like the example in RFC 1071, +// but using a uinon for readability +uint16_t checksum(void* data, size_t len) noexcept { - uint16_t* buf = reinterpret_cast(data); + uint16_t* buf = reinterpret_cast(data); - union sum { - uint32_t whole; - uint16_t part[2]; - } sum32 {0}; + union sum { + uint32_t whole; + uint16_t part[2]; + } sum32 {0}; - // Iterate in short int steps. - for (uint16_t* i = buf; i < (buf + len / 2); ++i) - sum32.whole += *i; + // Iterate in short int steps. + for (uint16_t* i = buf; i < (buf + len / 2); ++i) + sum32.whole += *i; - // odd-length case - if (len & 1) { - sum32.whole += reinterpret_cast(buf)[len - 1]; - } - - return ~(sum32.part[0] + sum32.part[1]); + // odd-length case + if (len & 1) { + sum32.whole += reinterpret_cast(buf)[len - 1]; } + return ~(sum32.part[0] + sum32.part[1]); +} + } //< namespace net diff --git a/src/net/ip4.cpp b/src/net/ip4.cpp index ad962b5ba0..537e8da023 100644 --- a/src/net/ip4.cpp +++ b/src/net/ip4.cpp @@ -24,10 +24,10 @@ namespace net { - const IP4::addr IP4::INADDR_ANY {{0,0,0,0}}; - const IP4::addr IP4::INADDR_BCAST {{0xff,0xff,0xff,0xff}}; +const IP4::addr IP4::INADDR_ANY {{0,0,0,0}}; +const IP4::addr IP4::INADDR_BCAST {{0xff,0xff,0xff,0xff}}; - IP4::IP4(Inet& inet) noexcept: +IP4::IP4(Inet& inet) noexcept: stack_{inet} { // Default gateway is addr 1 in the subnet. @@ -35,79 +35,79 @@ namespace net { // gateway_.whole = (local_ip_.whole & netmask_.whole) | DEFAULT_GATEWAY; } - void IP4::bottom(Packet_ptr pckt) { - debug2(" got the data.\n"); +void IP4::bottom(Packet_ptr pckt) { + debug2(" got the data.\n"); - auto data = pckt->buffer(); - ip_header* hdr = &reinterpret_cast(data)->ip_hdr; + auto data = pckt->buffer(); + ip_header* hdr = &reinterpret_cast(data)->ip_hdr; - debug2("\t Source IP: %s Dest.IP: %s\n", - hdr->saddr.str().c_str(), hdr->daddr.str().c_str()); + debug2("\t Source IP: %s Dest.IP: %s\n", + hdr->saddr.str().c_str(), hdr->daddr.str().c_str()); - switch(hdr->protocol){ - case IP4_ICMP: - debug2("\t Type: ICMP\n"); - icmp_handler_(pckt); - break; - case IP4_UDP: - debug2("\t Type: UDP\n"); - udp_handler_(pckt); - break; - case IP4_TCP: - tcp_handler_(pckt); - debug2("\t Type: TCP\n"); - break; - default: - debug("\t Type: UNKNOWN %i\n", hdr->protocol); - break; - } + switch(hdr->protocol){ + case IP4_ICMP: + debug2("\t Type: ICMP\n"); + icmp_handler_(pckt); + break; + case IP4_UDP: + debug2("\t Type: UDP\n"); + udp_handler_(pckt); + break; + case IP4_TCP: + tcp_handler_(pckt); + debug2("\t Type: TCP\n"); + break; + default: + debug("\t Type: UNKNOWN %i\n", hdr->protocol); + break; } +} - uint16_t IP4::checksum(ip_header* hdr) { - return net::checksum(reinterpret_cast(hdr), sizeof(ip_header)); - } +uint16_t IP4::checksum(ip_header* hdr) { + return net::checksum(reinterpret_cast(hdr), sizeof(ip_header)); +} - void IP4::transmit(Packet_ptr pckt) { - assert(pckt->size() > sizeof(IP4::full_header)); +void IP4::transmit(Packet_ptr pckt) { + assert(pckt->size() > sizeof(IP4::full_header)); - full_header* full_hdr = reinterpret_cast(pckt->buffer()); - ip_header* hdr = &full_hdr->ip_hdr; + full_header* full_hdr = reinterpret_cast(pckt->buffer()); + ip_header* hdr = &full_hdr->ip_hdr; - auto ip4_pckt = std::static_pointer_cast(pckt); - ip4_pckt->make_flight_ready(); + auto ip4_pckt = std::static_pointer_cast(pckt); + ip4_pckt->make_flight_ready(); - // Create local and target subnets - addr target, local; - target.whole = hdr->daddr.whole & stack_.netmask().whole; - local.whole = stack_.ip_addr().whole & stack_.netmask().whole; + // Create local and target subnets + addr target, local; + target.whole = hdr->daddr.whole & stack_.netmask().whole; + local.whole = stack_.ip_addr().whole & stack_.netmask().whole; - // Compare subnets to know where to send packet - pckt->next_hop(target == local ? hdr->daddr : stack_.router()); + // Compare subnets to know where to send packet + pckt->next_hop(target == local ? hdr->daddr : stack_.router()); - debug(" Next hop for %s, (netmask %s, local IP: %s, gateway: %s) == %s\n", - hdr->daddr.str().c_str(), - stack_.netmask().str().c_str(), - stack_.ip_addr().str().c_str(), - stack_.router().str().c_str(), - target == local ? "DIRECT" : "GATEWAY"); + debug(" Next hop for %s, (netmask %s, local IP: %s, gateway: %s) == %s\n", + hdr->daddr.str().c_str(), + stack_.netmask().str().c_str(), + stack_.ip_addr().str().c_str(), + stack_.router().str().c_str(), + target == local ? "DIRECT" : "GATEWAY"); - debug(" my ip: %s, Next hop: %s, Packet size: %i IP4-size: %i\n", - stack_.ip_addr().str().c_str(), - pckt->next_hop().str().c_str(), - pckt->size(), - ip4_pckt->ip4_segment_size() - ); + debug(" my ip: %s, Next hop: %s, Packet size: %i IP4-size: %i\n", + stack_.ip_addr().str().c_str(), + pckt->next_hop().str().c_str(), + pckt->size(), + ip4_pckt->ip4_segment_size() + ); - linklayer_out_(pckt); - } + linklayer_out_(pckt); +} - // Empty handler for delegates initialization - void ignore_ip4_up(Packet_ptr UNUSED(pckt)) { - debug(" Empty handler. Ignoring.\n"); - } +// Empty handler for delegates initialization +void ignore_ip4_up(Packet_ptr UNUSED(pckt)) { + debug(" Empty handler. Ignoring.\n"); +} - void ignore_ip4_down(Packet_ptr UNUSED(pckt)) { - debug("Link layer> No handler - DROP!\n"); - } +void ignore_ip4_down(Packet_ptr UNUSED(pckt)) { + debug("Link layer> No handler - DROP!\n"); +} } //< namespace net diff --git a/src/net/ip4/icmpv4.cpp b/src/net/ip4/icmpv4.cpp index 3f9e897135..5a7b4a113f 100644 --- a/src/net/ip4/icmpv4.cpp +++ b/src/net/ip4/icmpv4.cpp @@ -24,68 +24,68 @@ namespace net { - ICMPv4::ICMPv4(Inet& inet) : - inet_{inet} +ICMPv4::ICMPv4(Inet& inet) : + inet_{inet} {} - void ICMPv4::bottom(Packet_ptr pckt) { - if (pckt->size() < sizeof(full_header)) // Drop if not a full header - return; +void ICMPv4::bottom(Packet_ptr pckt) { + if (pckt->size() < sizeof(full_header)) // Drop if not a full header + return; - full_header* full_hdr = reinterpret_cast(pckt->buffer()); - icmp_header* hdr = &full_hdr->icmp_hdr; + full_header* full_hdr = reinterpret_cast(pckt->buffer()); + icmp_header* hdr = &full_hdr->icmp_hdr; #ifdef DEBUG - auto ip_address = full_hdr->ip_hdr.saddr.str().c_str(); + auto ip_address = full_hdr->ip_hdr.saddr.str().c_str(); #endif - switch(hdr->type) { - case (ICMP_ECHO): - debug(" PING from %s\n", ip_address); - ping_reply(full_hdr, pckt->size()); - break; - case (ICMP_ECHO_REPLY): - debug(" PING Reply from %s\n", ip_address); - break; - } + switch(hdr->type) { + case (ICMP_ECHO): + debug(" PING from %s\n", ip_address); + ping_reply(full_hdr, pckt->size()); + break; + case (ICMP_ECHO_REPLY): + debug(" PING Reply from %s\n", ip_address); + break; } +} - void ICMPv4::ping_reply(full_header* full_hdr, uint16_t size) { - auto packet_ptr = inet_.createPacket(size); - auto buf = packet_ptr->buffer(); +void ICMPv4::ping_reply(full_header* full_hdr, uint16_t size) { + auto packet_ptr = inet_.createPacket(size); + auto buf = packet_ptr->buffer(); - icmp_header* hdr = &reinterpret_cast(buf)->icmp_hdr; - hdr->type = ICMP_ECHO_REPLY; - hdr->code = 0; - hdr->identifier = full_hdr->icmp_hdr.identifier; - hdr->sequence = full_hdr->icmp_hdr.sequence; + icmp_header* hdr = &reinterpret_cast(buf)->icmp_hdr; + hdr->type = ICMP_ECHO_REPLY; + hdr->code = 0; + hdr->identifier = full_hdr->icmp_hdr.identifier; + hdr->sequence = full_hdr->icmp_hdr.sequence; - debug(" Rest of header IN: 0x%lx OUT: 0x%lx\n", - full_hdr->icmp_hdr.rest, hdr->rest); + debug(" Rest of header IN: 0x%lx OUT: 0x%lx\n", + full_hdr->icmp_hdr.rest, hdr->rest); - debug(" Transmitting answer\n"); + debug(" Transmitting answer\n"); - // Populate response IP header - auto ip4_pckt = std::static_pointer_cast(packet_ptr); - ip4_pckt->init(); - ip4_pckt->set_src(full_hdr->ip_hdr.daddr); - ip4_pckt->set_dst(full_hdr->ip_hdr.saddr); - ip4_pckt->set_protocol(IP4::IP4_ICMP); + // Populate response IP header + auto ip4_pckt = std::static_pointer_cast(packet_ptr); + ip4_pckt->init(); + ip4_pckt->set_src(full_hdr->ip_hdr.daddr); + ip4_pckt->set_dst(full_hdr->ip_hdr.saddr); + ip4_pckt->set_protocol(IP4::IP4_ICMP); - // Copy payload from old to new packet - uint8_t* payload = reinterpret_cast(hdr) + sizeof(icmp_header); - uint8_t* source = reinterpret_cast(&full_hdr->icmp_hdr) + sizeof(icmp_header); - memcpy(payload, source, size - sizeof(full_header)); + // Copy payload from old to new packet + uint8_t* payload = reinterpret_cast(hdr) + sizeof(icmp_header); + uint8_t* source = reinterpret_cast(&full_hdr->icmp_hdr) + sizeof(icmp_header); + memcpy(payload, source, size - sizeof(full_header)); - hdr->checksum = 0; - hdr->checksum = net::checksum(reinterpret_cast(hdr), - size - sizeof(full_header) + sizeof(icmp_header)); + hdr->checksum = 0; + hdr->checksum = net::checksum(reinterpret_cast(hdr), + size - sizeof(full_header) + sizeof(icmp_header)); - network_layer_out_(packet_ptr); - } + network_layer_out_(packet_ptr); +} - void icmp_default_out(Packet_ptr UNUSED(pckt)) { - debug(" No handler. DROP!\n"); - } +void icmp_default_out(Packet_ptr UNUSED(pckt)) { + debug(" No handler. DROP!\n"); +} } //< namespace net diff --git a/src/net/ip4/udp.cpp b/src/net/ip4/udp.cpp index 9517873299..7ef9208f86 100644 --- a/src/net/ip4/udp.cpp +++ b/src/net/ip4/udp.cpp @@ -23,70 +23,70 @@ namespace net { - void UDP::bottom(Packet_ptr pckt) - { - debug(" Got data"); - std::shared_ptr udp = +void UDP::bottom(Packet_ptr pckt) +{ + debug(" Got data"); + std::shared_ptr udp = std::static_pointer_cast (pckt); - debug("\t Source port: %i, Dest. Port: %i Length: %i\n", - udp->src_port(), udp->dst_port(), udp->length()); - - auto it = ports_.find(udp->dst_port()); - if (it != ports_.end()) - { - debug(" Someone's listening to this port. Forwarding...\n"); - it->second.internal_read(udp); - } + debug("\t Source port: %i, Dest. Port: %i Length: %i\n", + udp->src_port(), udp->dst_port(), udp->length()); - debug(" Nobody's listening to this port. Drop!\n"); + auto it = ports_.find(udp->dst_port()); + if (it != ports_.end()) + { + debug(" Someone's listening to this port. Forwarding...\n"); + it->second.internal_read(udp); } + + debug(" Nobody's listening to this port. Drop!\n"); +} - UDP::Socket& UDP::bind(UDP::port_t port) - { - debug(" Binding to port %i\n", port); - /// ... !!! - auto it = ports_.find(port); - if (it == ports_.end()) { - // create new socket - auto res = ports_.emplace( - std::piecewise_construct, - std::forward_as_tuple(port), - std::forward_as_tuple(stack_, port)); - it = res.first; - } - return it->second; +UDP::Socket& UDP::bind(UDP::port_t port) +{ + debug(" Binding to port %i\n", port); + /// ... !!! + auto it = ports_.find(port); + if (it == ports_.end()) { + // create new socket + auto res = ports_.emplace( + std::piecewise_construct, + std::forward_as_tuple(port), + std::forward_as_tuple(stack_, port)); + it = res.first; } + return it->second; +} - UDP::Socket& UDP::bind() { +UDP::Socket& UDP::bind() { - if (ports_.size() >= 0xfc00) - panic("UPD Socket: All ports taken!"); + if (ports_.size() >= 0xfc00) + panic("UPD Socket: All ports taken!"); - debug("UDP finding free ephemeral port\n"); - while (ports_.find(++current_port_) != ports_.end()) - if (current_port_ == 0) current_port_ = 1025; // prevent automatic ports under 1024 + debug("UDP finding free ephemeral port\n"); + while (ports_.find(++current_port_) != ports_.end()) + if (current_port_ == 0) current_port_ = 1025; // prevent automatic ports under 1024 - debug("UDP binding to %i port\n", current_port_); - return bind(current_port_); - } + debug("UDP binding to %i port\n", current_port_); + return bind(current_port_); +} - void UDP::transmit(std::shared_ptr udp) { - debug2(" Transmitting %i bytes (seg=%i) from %s to %s:%i\n", - udp->length(), udp->ip4_segment_size(), - udp->src().str().c_str(), - udp->dst().str().c_str(), udp->dst_port()); +void UDP::transmit(std::shared_ptr udp) { + debug2(" Transmitting %i bytes (seg=%i) from %s to %s:%i\n", + udp->length(), udp->ip4_segment_size(), + udp->src().str().c_str(), + udp->dst().str().c_str(), udp->dst_port()); - assert(udp->length() >= sizeof(UDP::udp_header)); - assert(udp->protocol() == IP4::IP4_UDP); + assert(udp->length() >= sizeof(UDP::udp_header)); + assert(udp->protocol() == IP4::IP4_UDP); - Packet_ptr pckt = Packet::packet(udp); - network_layer_out_(pckt); - } + Packet_ptr pckt = Packet::packet(udp); + network_layer_out_(pckt); +} - void ignore_udp(Packet_ptr) - { - debug("Network> No handler - DROP!\n"); - } +void ignore_udp(Packet_ptr) +{ + debug("Network> No handler - DROP!\n"); +} } //< namespace net diff --git a/src/net/ip4/udp_socket.cpp b/src/net/ip4/udp_socket.cpp index a5eea02023..46ebfbc8fd 100644 --- a/src/net/ip4/udp_socket.cpp +++ b/src/net/ip4/udp_socket.cpp @@ -29,7 +29,7 @@ namespace net } void Socket::packet_init(std::shared_ptr p, - addr srcIP, addr destIP, port port, uint16_t length) + addr srcIP, addr destIP, port port, uint16_t length) { p->init(); p->header().sport = htons(this->l_port); @@ -42,7 +42,7 @@ namespace net } int Socket::internal_write(addr srcIP, addr destIP, - port port, const uint8_t* buffer, int length) + port port, const uint8_t* buffer, int length) { // the maximum we can write per packet: const int WRITE_MAX = stack.MTU() - PacketUDP::HEADERS_SIZE; @@ -50,47 +50,47 @@ namespace net int rem = length; while (rem >= WRITE_MAX) - { - // create some packet p (and convert it to PacketUDP) - auto p = stack.createPacket(stack.MTU()); - // fill buffer (at payload position) - memcpy(p->buffer() + PacketUDP::HEADERS_SIZE, buffer, WRITE_MAX); + { + // create some packet p (and convert it to PacketUDP) + auto p = stack.createPacket(stack.MTU()); + // fill buffer (at payload position) + memcpy(p->buffer() + PacketUDP::HEADERS_SIZE, buffer, WRITE_MAX); - // initialize packet with several infos - auto p2 = std::static_pointer_cast(p); - packet_init(p2, srcIP, destIP, port, WRITE_MAX); - // ship the packet - stack.udp().transmit(p2); + // initialize packet with several infos + auto p2 = std::static_pointer_cast(p); + packet_init(p2, srcIP, destIP, port, WRITE_MAX); + // ship the packet + stack.udp().transmit(p2); - // next buffer part - buffer += WRITE_MAX; rem -= WRITE_MAX; - } + // next buffer part + buffer += WRITE_MAX; rem -= WRITE_MAX; + } if (rem) - { - // copy remainder - size_t size = PacketUDP::HEADERS_SIZE + rem; + { + // copy remainder + size_t size = PacketUDP::HEADERS_SIZE + rem; - // create some packet p - auto p = stack.createPacket(size); - memcpy(p->buffer() + PacketUDP::HEADERS_SIZE, buffer, rem); + // create some packet p + auto p = stack.createPacket(size); + memcpy(p->buffer() + PacketUDP::HEADERS_SIZE, buffer, rem); - // initialize packet with several infos - auto p2 = std::static_pointer_cast(p); - packet_init(p2, srcIP, destIP, port, rem); - // ship the packet - stack.udp().transmit(p2); - } + // initialize packet with several infos + auto p2 = std::static_pointer_cast(p); + packet_init(p2, srcIP, destIP, port, rem); + // ship the packet + stack.udp().transmit(p2); + } return length; } // internal_write() int Socket::sendto(addr destIP, port port, - const void* buffer, int len) + const void* buffer, int len) { return internal_write(local_addr(), destIP, port, (const uint8_t*) buffer, len); } int Socket::bcast(addr srcIP, port port, - const void* buffer, int len) + const void* buffer, int len) { return internal_write(srcIP, IP4::INADDR_BCAST, port, (const uint8_t*) buffer, len); diff --git a/src/net/ip6/icmp6.cpp b/src/net/ip6/icmp6.cpp index f36c2e18da..b58907e3b1 100644 --- a/src/net/ip6/icmp6.cpp +++ b/src/net/ip6/icmp6.cpp @@ -44,92 +44,92 @@ namespace net std::string ICMPv6::code_string(uint8_t type, uint8_t code) { switch (type) + { + /// error codes /// + case 1: + /// delivery problems /// + switch (code) { - /// error codes /// + case 0: + return "No route to destination"; case 1: - /// delivery problems /// - switch (code) - { - case 0: - return "No route to destination"; - case 1: - return "Communication with dest administratively prohibited"; - case 2: - return "Beyond scope of source address"; - case 3: - return "Address unreachable"; - case 4: - return "Port unreachable"; - case 5: - return "Source address failed ingress/egress policy"; - case 6: - return "Reject route to destination"; - case 7: - return "Error in source routing header"; - default: - return "ERROR Invalid ICMP type"; - } + return "Communication with dest administratively prohibited"; case 2: - /// size problems /// - return "Packet too big"; - + return "Beyond scope of source address"; case 3: - /// time problems /// - switch (code) - { - case 0: - return "Hop limit exceeded in traffic"; - case 1: - return "Fragment reassembly time exceeded"; - default: - return "ERROR Invalid ICMP code"; - } + return "Address unreachable"; case 4: - /// parameter problems /// - switch (code) - { - case 0: - return "Erroneous header field"; - case 1: - return "Unrecognized next header"; - case 2: - return "Unrecognized IPv6 option"; - default: - return "ERROR Invalid ICMP code"; - } + return "Port unreachable"; + case 5: + return "Source address failed ingress/egress policy"; + case 6: + return "Reject route to destination"; + case 7: + return "Error in source routing header"; + default: + return "ERROR Invalid ICMP type"; + } + case 2: + /// size problems /// + return "Packet too big"; - /// echo feature /// - case ECHO_REQUEST: - return "Echo request"; - case ECHO_REPLY: - return "Echo reply"; + case 3: + /// time problems /// + switch (code) + { + case 0: + return "Hop limit exceeded in traffic"; + case 1: + return "Fragment reassembly time exceeded"; + default: + return "ERROR Invalid ICMP code"; + } + case 4: + /// parameter problems /// + switch (code) + { + case 0: + return "Erroneous header field"; + case 1: + return "Unrecognized next header"; + case 2: + return "Unrecognized IPv6 option"; + default: + return "ERROR Invalid ICMP code"; + } - /// multicast feature /// - case 130: - return "Multicast listener query"; - case 131: - return "Multicast listener report"; - case 132: - return "Multicast listener done"; + /// echo feature /// + case ECHO_REQUEST: + return "Echo request"; + case ECHO_REPLY: + return "Echo reply"; - /// neighbor discovery protocol /// - case ND_ROUTER_SOL: - return "NDP Router solicitation request"; - case ND_ROUTER_ADV: - return "NDP Router advertisement"; - case ND_NEIGHB_SOL: - return "NDP Neighbor solicitation request"; - case ND_NEIGHB_ADV: - return "NDP Neighbor advertisement"; - case ND_REDIRECT: - return "NDP Redirect message"; + /// multicast feature /// + case 130: + return "Multicast listener query"; + case 131: + return "Multicast listener report"; + case 132: + return "Multicast listener done"; - case 143: - return "Multicast Listener Discovery (MLDv2) reports (RFC 3810)"; + /// neighbor discovery protocol /// + case ND_ROUTER_SOL: + return "NDP Router solicitation request"; + case ND_ROUTER_ADV: + return "NDP Router advertisement"; + case ND_NEIGHB_SOL: + return "NDP Neighbor solicitation request"; + case ND_NEIGHB_ADV: + return "NDP Neighbor advertisement"; + case ND_REDIRECT: + return "NDP Redirect message"; - default: - return "Unknown type: " + std::to_string((int) type); - } + case 143: + return "Multicast Listener Discovery (MLDv2) reports (RFC 3810)"; + + default: + return "Unknown type: " + std::to_string((int) type); + } } int ICMPv6::bottom(Packet_ptr pckt) @@ -139,27 +139,27 @@ namespace net type_t type = icmp->type(); if (listeners.find(type) != listeners.end()) - { - return listeners[type](*this, icmp); - } + { + return listeners[type](*this, icmp); + } else - { - debug(">>> IPv6 -> ICMPv6 bottom (no handler installed)\n"); - debug("ICMPv6 type %d: %s\n", - (int) icmp->type(), code_string(icmp->type(), icmp->code()).c_str()); + { + debug(">>> IPv6 -> ICMPv6 bottom (no handler installed)\n"); + debug("ICMPv6 type %d: %s\n", + (int) icmp->type(), code_string(icmp->type(), icmp->code()).c_str()); - /* - // show correct checksum - intptr_t chksum = icmp->checksum(); - debug("ICMPv6 checksum: %p \n",(void*) chksum); + /* + // show correct checksum + intptr_t chksum = icmp->checksum(); + debug("ICMPv6 checksum: %p \n",(void*) chksum); - // show our recalculated checksum - icmp->header().checksum_ = 0; - chksum = checksum(icmp); - debug("ICMPv6 our estimate: %p \n", (void*) chksum ); - */ - return -1; - } + // show our recalculated checksum + icmp->header().checksum_ = 0; + chksum = checksum(icmp); + debug("ICMPv6 our estimate: %p \n", (void*) chksum ); + */ + return -1; + } } int ICMPv6::transmit(std::shared_ptr& pckt) { @@ -189,18 +189,18 @@ namespace net //assert(hdr.next() == 58); // ICMPv6 /** - RFC 4443 - 2.3. Message Checksum Calculation + RFC 4443 + 2.3. Message Checksum Calculation - The checksum is the 16-bit one's complement of the one's complement - sum of the entire ICMPv6 message, starting with the ICMPv6 message - type field, and prepended with a "pseudo-header" of IPv6 header - fields, as specified in [IPv6, Section 8.1]. The Next Header value - used in the pseudo-header is 58. (The inclusion of a pseudo-header - in the ICMPv6 checksum is a change from IPv4; see [IPv6] for the - rationale for this change.) + The checksum is the 16-bit one's complement of the one's complement + sum of the entire ICMPv6 message, starting with the ICMPv6 message + type field, and prepended with a "pseudo-header" of IPv6 header + fields, as specified in [IPv6, Section 8.1]. The Next Header value + used in the pseudo-header is 58. (The inclusion of a pseudo-header + in the ICMPv6 checksum is a change from IPv4; see [IPv6] for the + rationale for this change.) - For computing the checksum, the checksum field is first set to zero. + For computing the checksum, the checksum field is first set to zero. **/ union { @@ -214,7 +214,7 @@ namespace net uint16_t* it_end = it + sizeof(pseudo_header) / 2; while (it < it_end) - sum.whole += *(it++); + sum.whole += *(it++); // compute sum of data it = (uint16_t*) pckt->payload(); @@ -243,21 +243,21 @@ namespace net icmp->type = ICMPv6::ECHO_REPLY; if (pckt->dst().is_multicast()) - { - // We won't be changing source address for multicast ping - debug("Was multicast ping6: no change for source and dest\n"); - } + { + // We won't be changing source address for multicast ping + debug("Was multicast ping6: no change for source and dest\n"); + } else - { - printf("Normal ping6: source is us\n"); - printf("src is %s\n", pckt->src().str().c_str()); - printf("dst is %s\n", pckt->dst().str().c_str()); + { + printf("Normal ping6: source is us\n"); + printf("src is %s\n", pckt->src().str().c_str()); + printf("dst is %s\n", pckt->dst().str().c_str()); - printf("multicast is %s\n", IP6::addr::link_all_nodes.str().c_str()); - // normal ping: send packet to source, from us - pckt->set_dst(pckt->src()); - pckt->set_src(caller.local_ip()); - } + printf("multicast is %s\n", IP6::addr::link_all_nodes.str().c_str()); + // normal ping: send packet to source, from us + pckt->set_dst(pckt->src()); + pckt->set_src(caller.local_ip()); + } // calculate and set checksum // NOTE: do this after changing packet contents! icmp->checksum = 0; @@ -288,9 +288,9 @@ namespace net // ether-broadcast an IPv6 packet to all routers // IPv6mcast_02: 33:33:00:00:00:02 auto pckt = IP6::create( - IP6::PROTO_ICMPv6, - Ethernet::addr::IPv6mcast_02, - IP6::addr::link_unspecified); + IP6::PROTO_ICMPv6, + Ethernet::addr::IPv6mcast_02, + IP6::addr::link_unspecified); // RFC4861 4.1. Router Solicitation Message Format pckt->set_hoplimit(255); diff --git a/src/net/ip6/ip6.cpp b/src/net/ip6/ip6.cpp index 8ff9de8e1d..029f3657a3 100644 --- a/src/net/ip6/ip6.cpp +++ b/src/net/ip6/ip6.cpp @@ -47,35 +47,35 @@ namespace net uint8_t IP6::parse6(uint8_t*& reader, uint8_t next) { switch (next) - { - case PROTO_HOPOPT: - case PROTO_OPTSv6: - { - debug(">>> IPv6 options header %s", protocol_name(next).c_str()); + { + case PROTO_HOPOPT: + case PROTO_OPTSv6: + { + debug(">>> IPv6 options header %s", protocol_name(next).c_str()); - options_header& opts = *(options_header*) reader; - reader += opts.size(); + options_header& opts = *(options_header*) reader; + reader += opts.size(); - debug("OPTSv6 size: %d\n", opts.size()); - debug("OPTSv6 ext size: %d\n", opts.extended()); + debug("OPTSv6 size: %d\n", opts.size()); + debug("OPTSv6 ext size: %d\n", opts.extended()); - next = opts.next(); - debug("OPTSv6 next: %s\n", protocol_name(next).c_str()); - } break; - case PROTO_ICMPv6: - break; - case PROTO_UDP: - break; + next = opts.next(); + debug("OPTSv6 next: %s\n", protocol_name(next).c_str()); + } break; + case PROTO_ICMPv6: + break; + case PROTO_UDP: + break; - default: - debug("Not parsing: %s\n", protocol_name(next).c_str()); - } + default: + debug("Not parsing: %s\n", protocol_name(next).c_str()); + } return next; } - void IP6::bottom(Packet_ptr pckt) - { + void IP6::bottom(Packet_ptr pckt) + { debug(">>> IPv6 packet:"); @@ -92,20 +92,20 @@ namespace net uint8_t next = hdr.next(); while (next != PROTO_NoNext) + { + auto it = proto_handlers.find(next); + if (it != proto_handlers.end()) { - auto it = proto_handlers.find(next); - if (it != proto_handlers.end()) - { - // forward packet to handler - pckt->set_payload(reader); - it->second(pckt); - } - else - // just print information - next = parse6(reader, next); + // forward packet to handler + pckt->set_payload(reader); + it->second(pckt); } + else + // just print information + next = parse6(reader, next); + } - }; + }; static const std::string lut = "0123456789abcdef"; @@ -117,12 +117,12 @@ namespace net const uint8_t* octet = i8; for (int i = 0; i < 16; i++) - { - ret[counter++] = lut[(octet[i] & 0xF0) >> 4]; - ret[counter++] = lut[(octet[i] & 0x0F) >> 0]; - if (i & 1) - ret[counter++] = ':'; - } + { + ret[counter++] = lut[(octet[i] & 0xF0) >> 4]; + ret[counter++] = lut[(octet[i] & 0x0F) >> 0]; + if (i & 1) + ret[counter++] = ':'; + } ret.resize(counter-1); return ret; } @@ -138,7 +138,7 @@ namespace net } std::shared_ptr IP6::create(uint8_t proto, - Ethernet::addr ether_dest, const IP6::addr& ip6_dest) + Ethernet::addr ether_dest, const IP6::addr& ip6_dest) { // arbitrarily big buffer uint8_t* data = new uint8_t[1500]; diff --git a/src/net/ip6/udp6.cpp b/src/net/ip6/udp6.cpp index 550fa7aad4..e89aaf33dd 100644 --- a/src/net/ip6/udp6.cpp +++ b/src/net/ip6/udp6.cpp @@ -35,10 +35,10 @@ namespace net // check for listeners on dst port if (listeners.find(port) != listeners.end()) - { - // make the call to the listener on that port - return listeners[port](P6); - } + { + // make the call to the listener on that port + return listeners[port](P6); + } // was not forwarded, so just return -1 debug("... dumping packet, no listeners\n"); return -1; @@ -83,7 +83,7 @@ namespace net // normally we would start at &icmp_echo::type, but // it is after all the first element of the icmp message memcpy(data + sizeof(UDPv6::pseudo_header), this->payload(), - datalen - sizeof(UDPv6::pseudo_header)); + datalen - sizeof(UDPv6::pseudo_header)); // calculate csum and free data on return header().chksum = net::checksum(data, datalen); @@ -91,7 +91,7 @@ namespace net } std::shared_ptr UDPv6::create( - Ethernet::addr ether_dest, const IP6::addr& ip6_dest, UDPv6::port_t port) + Ethernet::addr ether_dest, const IP6::addr& ip6_dest, UDPv6::port_t port) { auto packet = IP6::create(IP6::PROTO_UDP, ether_dest, ip6_dest); auto udp_packet = view_packet_as (packet); diff --git a/src/net/tcp.cpp b/src/net/tcp.cpp index 96b0df8f81..adfe3165e5 100644 --- a/src/net/tcp.cpp +++ b/src/net/tcp.cpp @@ -24,218 +24,218 @@ using namespace net; TCP::TCP(IPStack& inet) : - inet_(inet), - listeners_(), - connections_(), - MAX_SEG_LIFETIME(30s) + inet_(inet), + listeners_(), + connections_(), + MAX_SEG_LIFETIME(30s) { } /* - Note: There is different approaches to how to handle listeners & connections. - Need to discuss and decide for the best one. + Note: There is different approaches to how to handle listeners & connections. + Need to discuss and decide for the best one. - Best solution(?): - Preallocate a pool with listening connections. - When threshold is reach, remove/add new ones, similar to TCP window. + Best solution(?): + Preallocate a pool with listening connections. + When threshold is reach, remove/add new ones, similar to TCP window. - Current solution: - Simple. + Current solution: + Simple. */ TCP::Connection& TCP::bind(Port port) { - auto listen_conn_it = listeners_.find(port); - // Already a listening socket. - if(listen_conn_it != listeners_.end()) { - throw TCPException{"Port is already taken."}; - } - auto& connection = (listeners_.emplace(port, Connection{*this, port})).first->second; - debug(" Bound to port %i \n", port); - connection.open(false); - return connection; + auto listen_conn_it = listeners_.find(port); + // Already a listening socket. + if(listen_conn_it != listeners_.end()) { + throw TCPException{"Port is already taken."}; + } + auto& connection = (listeners_.emplace(port, Connection{*this, port})).first->second; + debug(" Bound to port %i \n", port); + connection.open(false); + return connection; } /* - Active open a new connection to the given remote. + Active open a new connection to the given remote. - @WARNING: Callback is added when returned (TCP::connect(...).onSuccess(...)), - and open() is called before callback is added. + @WARNING: Callback is added when returned (TCP::connect(...).onSuccess(...)), + and open() is called before callback is added. */ TCP::Connection_ptr TCP::connect(Socket remote) { - std::shared_ptr connection = add_connection(free_port(), remote); - connection->open(true); - return connection; + std::shared_ptr connection = add_connection(free_port(), remote); + connection->open(true); + return connection; } /* - Active open a new connection to the given remote. + Active open a new connection to the given remote. */ void TCP::connect(Socket remote, Connection::ConnectCallback callback) { - auto connection = add_connection(free_port(), remote); - connection->onConnect(callback).open(true); + auto connection = add_connection(free_port(), remote); + connection->onConnect(callback).open(true); } TCP::Seq TCP::generate_iss() { - // Do something to get a iss. - return rand(); + // Do something to get a iss. + return rand(); } /* - TODO: Check if there is any ports free. + TODO: Check if there is any ports free. */ TCP::Port TCP::free_port() { - if(++current_ephemeral_ == 0) - current_ephemeral_ = 1025; - // Avoid giving a port that is bound to a service. - while(listeners_.find(current_ephemeral_) != listeners_.end()) - current_ephemeral_++; + if(++current_ephemeral_ == 0) + current_ephemeral_ = 1025; + // Avoid giving a port that is bound to a service. + while(listeners_.find(current_ephemeral_) != listeners_.end()) + current_ephemeral_++; - return current_ephemeral_; + return current_ephemeral_; } uint16_t TCP::checksum(TCP::Packet_ptr packet) { - // TCP header - TCP::Header* tcp_hdr = &(packet->header()); - // Pseudo header - TCP::Pseudo_header pseudo_hdr; - - int tcp_length = packet->tcp_length(); - - pseudo_hdr.saddr.whole = packet->src().whole; - pseudo_hdr.daddr.whole = packet->dst().whole; - pseudo_hdr.zero = 0; - pseudo_hdr.proto = IP4::IP4_TCP; - pseudo_hdr.tcp_length = htons(tcp_length); - - union { - uint32_t whole; - uint16_t part[2]; - } sum; - - sum.whole = 0; - - // Compute sum of pseudo header - for (uint16_t* it = (uint16_t*)&pseudo_hdr; it < (uint16_t*)&pseudo_hdr + sizeof(pseudo_hdr)/2; it++) - sum.whole += *it; - - // Compute sum sum the actual header and data - for (uint16_t* it = (uint16_t*)tcp_hdr; it < (uint16_t*)tcp_hdr + tcp_length/2; it++) - sum.whole+= *it; - - // The odd-numbered case - if (tcp_length & 1) { - debug(" ODD number of bytes. 0-pading \n"); - union { - uint16_t whole; - uint8_t part[2]; - } last_chunk; - last_chunk.part[0] = ((uint8_t*)tcp_hdr)[tcp_length - 1]; - last_chunk.part[1] = 0; - sum.whole += last_chunk.whole; - } - - debug2("header()); + // Pseudo header + TCP::Pseudo_header pseudo_hdr; + + int tcp_length = packet->tcp_length(); + + pseudo_hdr.saddr.whole = packet->src().whole; + pseudo_hdr.daddr.whole = packet->dst().whole; + pseudo_hdr.zero = 0; + pseudo_hdr.proto = IP4::IP4_TCP; + pseudo_hdr.tcp_length = htons(tcp_length); + + union { + uint32_t whole; + uint16_t part[2]; + } sum; + + sum.whole = 0; + + // Compute sum of pseudo header + for (uint16_t* it = (uint16_t*)&pseudo_hdr; it < (uint16_t*)&pseudo_hdr + sizeof(pseudo_hdr)/2; it++) + sum.whole += *it; + + // Compute sum sum the actual header and data + for (uint16_t* it = (uint16_t*)tcp_hdr; it < (uint16_t*)tcp_hdr + tcp_length/2; it++) + sum.whole+= *it; + + // The odd-numbered case + if (tcp_length & 1) { + debug(" ODD number of bytes. 0-pading \n"); + union { + uint16_t whole; + uint8_t part[2]; + } last_chunk; + last_chunk.part[0] = ((uint8_t*)tcp_hdr)[tcp_length - 1]; + last_chunk.part[1] = 0; + sum.whole += last_chunk.whole; + } + + debug2("(packet_ptr); - debug(" TCP Packet received - Source: %s, Destination: %s \n", - packet->source().to_string().c_str(), packet->destination().to_string().c_str()); + // Translate into a TCP::Packet. This will be used inside the TCP-scope. + auto packet = std::static_pointer_cast(packet_ptr); + debug(" TCP Packet received - Source: %s, Destination: %s \n", + packet->source().to_string().c_str(), packet->destination().to_string().c_str()); - // Do checksum - if(checksum(packet)) { - debug(" TCP Packet Checksum != 0 \n"); - } - - Connection::Tuple tuple { packet->dst_port(), packet->source() }; - - // Try to find the receiver - auto conn_it = connections_.find(tuple); - // Connection found - if(conn_it != connections_.end()) { - debug(" Connection found: %s \n", conn_it->second->to_string().c_str()); - conn_it->second->receive(packet); - } - // No connection found - else { - // Is there a listener? - auto listen_conn_it = listeners_.find(packet->dst_port()); - debug(" No connection found - looking for listener..\n"); - // Listener found => Create listening Connection - if(listen_conn_it != listeners_.end()) { - auto& listen_conn = listen_conn_it->second; - debug(" Listener found: %s ...\n", listen_conn.to_string().c_str()); - auto connection = (connections_.emplace(tuple, std::make_shared(listen_conn)).first->second); - // Set remote - connection->set_remote(packet->source()); - debug(" ... Creating connection: %s \n", connection->to_string().c_str()); + // Do checksum + if(checksum(packet)) { + debug(" TCP Packet Checksum != 0 \n"); + } + + Connection::Tuple tuple { packet->dst_port(), packet->source() }; + + // Try to find the receiver + auto conn_it = connections_.find(tuple); + // Connection found + if(conn_it != connections_.end()) { + debug(" Connection found: %s \n", conn_it->second->to_string().c_str()); + conn_it->second->receive(packet); + } + // No connection found + else { + // Is there a listener? + auto listen_conn_it = listeners_.find(packet->dst_port()); + debug(" No connection found - looking for listener..\n"); + // Listener found => Create listening Connection + if(listen_conn_it != listeners_.end()) { + auto& listen_conn = listen_conn_it->second; + debug(" Listener found: %s ...\n", listen_conn.to_string().c_str()); + auto connection = (connections_.emplace(tuple, std::make_shared(listen_conn)).first->second); + // Set remote + connection->set_remote(packet->source()); + debug(" ... Creating connection: %s \n", connection->to_string().c_str()); - connection->receive(packet); - } - // No listener found - else { - drop(packet); - } - } + connection->receive(packet); + } + // No listener found + else { + drop(packet); + } + } } /* - Show all connections for TCP as a string. + Show all connections for TCP as a string. - Format: - [Protocol][Recv][Send][Local][Remote][State] + Format: + [Protocol][Recv][Send][Local][Remote][State] - TODO: Make sure Recv, Send, In, Out is correct and add them to output. Also, alignment? + TODO: Make sure Recv, Send, In, Out is correct and add them to output. Also, alignment? */ string TCP::status() const { - // Write all connections in a cute list. - stringstream ss; - ss << "LISTENING SOCKETS:\n"; - for(auto listen_it : listeners_) { - ss << listen_it.second.to_string() << "\n"; - } - ss << "\nCONNECTIONS:\n" << "Proto\tRecv\tSend\tIn\tOut\tLocal\t\t\tRemote\t\t\tState\n"; - for(auto con_it : connections_) { - auto& c = *(con_it.second); - ss << "tcp4\t" - << " " << "\t" << " " << "\t" - << " " << "\t" << " " << "\t" - << c.local().to_string() << "\t\t" << c.remote().to_string() << "\t\t" - << c.state().to_string() << "\n"; - } - return ss.str(); + // Write all connections in a cute list. + stringstream ss; + ss << "LISTENING SOCKETS:\n"; + for(auto listen_it : listeners_) { + ss << listen_it.second.to_string() << "\n"; + } + ss << "\nCONNECTIONS:\n" << "Proto\tRecv\tSend\tIn\tOut\tLocal\t\t\tRemote\t\t\tState\n"; + for(auto con_it : connections_) { + auto& c = *(con_it.second); + ss << "tcp4\t" + << " " << "\t" << " " << "\t" + << " " << "\t" << " " << "\t" + << c.local().to_string() << "\t\t" << c.remote().to_string() << "\t\t" + << c.state().to_string() << "\n"; + } + return ss.str(); } /*TCP::Socket& TCP::add_listener(TCP::Socket&& socket) { - }*/ +}*/ TCP::Connection_ptr TCP::add_connection(Port local_port, TCP::Socket remote) { - return (connections_.emplace( - Connection::Tuple{ local_port, remote }, - std::make_shared(*this, local_port, remote)) - ).first->second; + return (connections_.emplace( + Connection::Tuple{ local_port, remote }, + std::make_shared(*this, local_port, remote)) + ).first->second; } void TCP::close_connection(TCP::Connection& conn) { - debug(" Closing connection: %s \n", conn.to_string().c_str()); - connections_.erase(conn.tuple()); - debug2(" TCP Status: \n%s \n", status().c_str()); + debug(" Closing connection: %s \n", conn.to_string().c_str()); + connections_.erase(conn.tuple()); + debug2(" TCP Status: \n%s \n", status().c_str()); } void TCP::drop(TCP::Packet_ptr) { - //debug(" Packet was dropped - no recipient: %s \n", packet->destination().to_string().c_str()); + //debug(" Packet was dropped - no recipient: %s \n", packet->destination().to_string().c_str()); } void TCP::transmit(TCP::Packet_ptr packet) { - // Translate into a net::Packet_ptr and send away. - // Generate checksum. - packet->set_checksum(TCP::checksum(packet)); - //packet->set_checksum(checksum(packet)); - _network_layer_out(packet); -} + // Translate into a net::Packet_ptr and send away. + // Generate checksum. + packet->set_checksum(TCP::checksum(packet)); + //packet->set_checksum(checksum(packet)); + _network_layer_out(packet); +} \ No newline at end of file diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index c0de3db285..c7fc2b70e6 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -26,416 +26,416 @@ using Connection = TCP::Connection; using namespace std; /* - This is most likely used in a ACTIVE open + This is most likely used in a ACTIVE open */ Connection::Connection(TCP& host, Port local_port, Socket remote) : - host_(host), - local_port_(local_port), - remote_(remote), - state_(&Connection::Closed::instance()), - prev_state_(state_), - control_block(), - receive_buffer_(host.buffer_limit()), - send_buffer_(host.buffer_limit()), - time_wait_started(0) + host_(host), + local_port_(local_port), + remote_(remote), + state_(&Connection::Closed::instance()), + prev_state_(state_), + control_block(), + receive_buffer_(host.buffer_limit()), + send_buffer_(host.buffer_limit()), + time_wait_started(0) { } /* - This is most likely used in a PASSIVE open + This is most likely used in a PASSIVE open */ Connection::Connection(TCP& host, Port local_port) : - host_(host), - local_port_(local_port), - remote_(TCP::Socket()), - state_(&Connection::Closed::instance()), - prev_state_(state_), - control_block(), - receive_buffer_(host.buffer_limit()), - send_buffer_(host.buffer_limit()), - time_wait_started(0) + host_(host), + local_port_(local_port), + remote_(TCP::Socket()), + state_(&Connection::Closed::instance()), + prev_state_(state_), + control_block(), + receive_buffer_(host.buffer_limit()), + send_buffer_(host.buffer_limit()), + time_wait_started(0) { } size_t Connection::read(char* buffer, size_t n) { - debug(" Reading %u bytes of data from RCV buffer. Total amount of packets stored: %u\n", - n, receive_buffer_.size()); - try { - return state_->receive(*this, buffer, n); - } catch(TCPException err) { - signal_error(err); - return 0; - } + debug(" Reading %u bytes of data from RCV buffer. Total amount of packets stored: %u\n", + n, receive_buffer_.size()); + try { + return state_->receive(*this, buffer, n); + } catch(TCPException err) { + signal_error(err); + return 0; + } } std::string Connection::read(size_t n) { - if(n == 0) { - // Read all data. - n = receive_buffer_.data_size(); - } - char buffer[n]; - size_t length = read(&buffer[0], n); - return {buffer, length}; + if(n == 0) { + // Read all data. + n = receive_buffer_.data_size(); + } + char buffer[n]; + size_t length = read(&buffer[0], n); + return {buffer, length}; } size_t Connection::read_from_receive_buffer(char* buffer, size_t n) { - size_t bytes_read = 0; - // Read data to buffer until either whole buffer is emptied, or the user got all the data requested. - while(!receive_buffer_.empty() and bytes_read < n) - { - // Packet in front - auto packet = receive_buffer_.front(); - // Where to begin reading - char* begin = packet->data()+receive_buffer_.data_offset(); - // Read this iteration - size_t total{0}; - // Remaining bytes to read. - size_t remaining = n - bytes_read; - // Trying to read over more than one packet - if( remaining >= (packet->data_length() - receive_buffer_.data_offset()) ) { - debug2(" Remaining >: %u Current p: %u\n", - remaining, packet->data_length() - receive_buffer_.data_offset()); - // Reading whole packet - total = packet->data_length(); - // Removing packet from receive buffer. - receive_buffer_.pop(); - // Next packet will start from beginning. - receive_buffer_.set_data_offset(0); - } - // Reading less than one packet. - else { - debug2(" Remaining <: %u\n", remaining); - total = remaining; - receive_buffer_.set_data_offset(packet->data_length() - remaining); - } - memcpy(buffer+bytes_read, begin, total); - bytes_read += total; - } - - return bytes_read; + size_t bytes_read = 0; + // Read data to buffer until either whole buffer is emptied, or the user got all the data requested. + while(!receive_buffer_.empty() and bytes_read < n) + { + // Packet in front + auto packet = receive_buffer_.front(); + // Where to begin reading + char* begin = packet->data()+receive_buffer_.data_offset(); + // Read this iteration + size_t total{0}; + // Remaining bytes to read. + size_t remaining = n - bytes_read; + // Trying to read over more than one packet + if( remaining >= (packet->data_length() - receive_buffer_.data_offset()) ) { + debug2(" Remaining >: %u Current p: %u\n", + remaining, packet->data_length() - receive_buffer_.data_offset()); + // Reading whole packet + total = packet->data_length(); + // Removing packet from receive buffer. + receive_buffer_.pop(); + // Next packet will start from beginning. + receive_buffer_.set_data_offset(0); + } + // Reading less than one packet. + else { + debug2(" Remaining <: %u\n", remaining); + total = remaining; + receive_buffer_.set_data_offset(packet->data_length() - remaining); + } + memcpy(buffer+bytes_read, begin, total); + bytes_read += total; + } + + return bytes_read; } bool Connection::add_to_receive_buffer(TCP::Packet_ptr packet) { - return receive_buffer_.add(packet); + return receive_buffer_.add(packet); } size_t Connection::write(const char* buffer, size_t n, bool PUSH) { - debug(" Asking to write %u bytes of data to SND buffer. \n", n); - try { - return state_->send(*this, buffer, n, PUSH); - } catch(TCPException err) { - signal_error(err); - return 0; - } + debug(" Asking to write %u bytes of data to SND buffer. \n", n); + try { + return state_->send(*this, buffer, n, PUSH); + } catch(TCPException err) { + signal_error(err); + return 0; + } } size_t Connection::write_to_send_buffer(const char* buffer, size_t n, bool PUSH) { - size_t bytes_written{0}; - size_t remaining{n}; - do { - auto packet = create_outgoing_packet(); - packet->set_seq(control_block.SND.NXT).set_ack(control_block.RCV.NXT).set_flag(ACK); - // calculate how much the packet can be filled with - auto packet_limit = (uint32_t)MSDS() - packet->header_size(); - size_t written = packet->fill(buffer + (n-remaining), std::min(packet_limit, remaining)); - bytes_written += written; - remaining -= written; + size_t bytes_written{0}; + size_t remaining{n}; + do { + auto packet = create_outgoing_packet(); + packet->set_seq(control_block.SND.NXT).set_ack(control_block.RCV.NXT).set_flag(ACK); + // calculate how much the packet can be filled with + auto packet_limit = (uint32_t)MSDS() - packet->header_size(); + size_t written = packet->fill(buffer + (n-remaining), std::min(packet_limit, remaining)); + bytes_written += written; + remaining -= written; - debug2(" Packet Limit: %u - Written: %u - Remaining: %u\n", - packet_limit, written, remaining); + debug2(" Packet Limit: %u - Written: %u - Remaining: %u\n", + packet_limit, written, remaining); - // If last packet, add PUSH. - if(!remaining and PUSH) - packet->set_flag(PSH); + // If last packet, add PUSH. + if(!remaining and PUSH) + packet->set_flag(PSH); - // Advance outgoing sequence number (SND.NXT) with the length of the data. - control_block.SND.NXT += packet->data_length(); - } while(remaining and !send_buffer_.full()); + // Advance outgoing sequence number (SND.NXT) with the length of the data. + control_block.SND.NXT += packet->data_length(); + } while(remaining and !send_buffer_.full()); - return bytes_written; + return bytes_written; } /* - If ACTIVE: - Need a remote Socket. + If ACTIVE: + Need a remote Socket. */ void Connection::open(bool active) { - try { - debug(" Trying to open Connection...\n"); - state_->open(*this, active); - } - // No remote host, or state isnt valid for opening. - catch (TCPException e) { - debug(" Cannot open Connection. \n"); - signal_error(e); - } + try { + debug(" Trying to open Connection...\n"); + state_->open(*this, active); + } + // No remote host, or state isnt valid for opening. + catch (TCPException e) { + debug(" Cannot open Connection. \n"); + signal_error(e); + } } void Connection::close() { - debug(" Active close on connection. \n"); - try { - state_->close(*this); - if(is_state(Closed::instance())) - signal_close(); - } catch(TCPException err) { - signal_error(err); - } + debug(" Active close on connection. \n"); + try { + state_->close(*this); + if(is_state(Closed::instance())) + signal_close(); + } catch(TCPException err) { + signal_error(err); + } } string Connection::to_string() const { - ostringstream os; - os << local().to_string() << "\t" << remote_.to_string() << "\t" << state_->to_string(); - return os.str(); + ostringstream os; + os << local().to_string() << "\t" << remote_.to_string() << "\t" << state_->to_string(); + return os.str(); } /* - Where the magic happens. + Where the magic happens. */ void Connection::receive(TCP::Packet_ptr incoming) { - signal_packet_received(incoming); - - if(incoming->has_options()) { - try { - parse_options(incoming); - } - catch(TCPBadOptionException err) { - printf(" %s \n", err.what()); - } - } - - // Change window accordingly. TODO: Not sure if this is how you do it. - control_block.SND.WND = incoming->win(); - - // Let state handle what to do when incoming packet arrives, and modify the outgoing packet. - switch(state_->handle(*this, incoming)) { - case State::OK: { - // Do nothing. - break; - } - case State::CLOSED: { - debug(" State handle finished with CLOSED. We're done, ask host() to delete the connection. \n"); - signal_close(); - break; - }; - case State::CLOSE: { - debug(" State handle finished with CLOSE. onDisconnect has been called, close the connection. \n"); - state_->close(*this); - break; - }; - } + signal_packet_received(incoming); + + if(incoming->has_options()) { + try { + parse_options(incoming); + } + catch(TCPBadOptionException err) { + printf(" %s \n", err.what()); + } + } + + // Change window accordingly. TODO: Not sure if this is how you do it. + control_block.SND.WND = incoming->win(); + + // Let state handle what to do when incoming packet arrives, and modify the outgoing packet. + switch(state_->handle(*this, incoming)) { + case State::OK: { + // Do nothing. + break; + } + case State::CLOSED: { + debug(" State handle finished with CLOSED. We're done, ask host() to delete the connection. \n"); + signal_close(); + break; + }; + case State::CLOSE: { + debug(" State handle finished with CLOSE. onDisconnect has been called, close the connection. \n"); + state_->close(*this); + break; + }; + } } bool Connection::is_listening() const { - return is_state(Listen::instance()); + return is_state(Listen::instance()); } bool Connection::is_connected() const { - return is_state(Established::instance()); + return is_state(Established::instance()); } bool Connection::is_closing() const { - return (is_state(Closing::instance()) or is_state(LastAck::instance()) or is_state(TimeWait::instance())); + return (is_state(Closing::instance()) or is_state(LastAck::instance()) or is_state(TimeWait::instance())); } bool Connection::is_writable() const { - return (is_connected() and (!send_buffer_.full())); + return (is_connected() and (!send_buffer_.full())); } Connection::~Connection() { - // Do all necessary clean up. - // Free up buffers etc. - debug2(" Bye bye... \n"); + // Do all necessary clean up. + // Free up buffers etc. + debug2(" Bye bye... \n"); } TCP::Packet_ptr Connection::create_outgoing_packet() { - auto packet = std::static_pointer_cast((host_.inet_).createPacket(TCP::Packet::HEADERS_SIZE)); + auto packet = std::static_pointer_cast((host_.inet_).createPacket(TCP::Packet::HEADERS_SIZE)); - packet->init(); - // Set Source (local == the current connection) - packet->set_source(local()); - // Set Destination (remote) - packet->set_destination(remote_); + packet->init(); + // Set Source (local == the current connection) + packet->set_source(local()); + // Set Destination (remote) + packet->set_destination(remote_); - packet->set_win_size(control_block.SND.WND); + packet->set_win_size(control_block.SND.WND); - // Set SEQ and ACK - I think this is OK.. - packet->set_seq(control_block.SND.NXT).set_ack(control_block.RCV.NXT); - debug(" Outgoing packet created: %s \n", packet->to_string().c_str()); + // Set SEQ and ACK - I think this is OK.. + packet->set_seq(control_block.SND.NXT).set_ack(control_block.RCV.NXT); + debug(" Outgoing packet created: %s \n", packet->to_string().c_str()); - // Will also add the packet to the back of the send queue. - send_buffer_.push(packet); + // Will also add the packet to the back of the send queue. + send_buffer_.push(packet); - return packet; + return packet; } void Connection::transmit() { - assert(! send_buffer_.empty() ); + assert(! send_buffer_.empty() ); - debug(" Transmitting: [ %i ] packets. \n", send_buffer_.size()); - while(! send_buffer_.empty() ) { - auto packet = send_buffer_.front(); - assert(! packet->destination().is_empty()); - transmit(packet); - send_buffer_.pop(); - } + debug(" Transmitting: [ %i ] packets. \n", send_buffer_.size()); + while(! send_buffer_.empty() ) { + auto packet = send_buffer_.front(); + assert(! packet->destination().is_empty()); + transmit(packet); + send_buffer_.pop(); + } } void Connection::transmit(TCP::Packet_ptr packet) { - debug(" Transmitting: %s \n", packet->to_string().c_str()); - host_.transmit(packet); - // Don't think we would like to retransmit reset packets..? - //if(!packet->isset(RST)) - // add_retransmission(packet); + debug(" Transmitting: %s \n", packet->to_string().c_str()); + host_.transmit(packet); + // Don't think we would like to retransmit reset packets..? + //if(!packet->isset(RST)) + // add_retransmission(packet); } TCP::Packet_ptr Connection::outgoing_packet() { - if(send_buffer_.empty()) - create_outgoing_packet(); - return send_buffer_.back(); + if(send_buffer_.empty()) + create_outgoing_packet(); + return send_buffer_.back(); } TCP::Seq Connection::generate_iss() { - return host_.generate_iss(); + return host_.generate_iss(); } void Connection::set_state(State& state) { - prev_state_ = state_; - state_ = &state; - debug(" %s => %s \n", - prev_state_->to_string().c_str(), state_->to_string().c_str()); + prev_state_ = state_; + state_ = &state; + debug(" %s => %s \n", + prev_state_->to_string().c_str(), state_->to_string().c_str()); } void Connection::add_retransmission(TCP::Packet_ptr packet) { - debug2(" Packet added to retransmission. \n"); - auto self = shared_from_this(); - hw::PIT::instance().onTimeout(RTO(), [packet, self] { - // Packet hasnt been ACKed. - if(packet->seq() > self->tcb().SND.UNA) { - debug(" Packet unacknowledge, retransmitting...\n"); - self->transmit(packet); - } else { - debug2(" Packet acknowledged %s \n", packet->to_string().c_str()); - // Signal user? - } - }); + debug2(" Packet added to retransmission. \n"); + auto self = shared_from_this(); + hw::PIT::instance().onTimeout(RTO(), [packet, self] { + // Packet hasnt been ACKed. + if(packet->seq() > self->tcb().SND.UNA) { + debug(" Packet unacknowledge, retransmitting...\n"); + self->transmit(packet); + } else { + debug2(" Packet acknowledged %s \n", packet->to_string().c_str()); + // Signal user? + } + }); } /* - Next compute a Smoothed Round Trip Time (SRTT) as: + Next compute a Smoothed Round Trip Time (SRTT) as: - SRTT = ( ALPHA * SRTT ) + ((1-ALPHA) * RTT) + SRTT = ( ALPHA * SRTT ) + ((1-ALPHA) * RTT) - and based on this, compute the retransmission timeout (RTO) as: + and based on this, compute the retransmission timeout (RTO) as: - RTO = min[UBOUND,max[LBOUND,(BETA*SRTT)]] + RTO = min[UBOUND,max[LBOUND,(BETA*SRTT)]] - where UBOUND is an upper bound on the timeout (e.g., 1 minute), - LBOUND is a lower bound on the timeout (e.g., 1 second), ALPHA is - a smoothing factor (e.g., .8 to .9), and BETA is a delay variance - factor (e.g., 1.3 to 2.0). + where UBOUND is an upper bound on the timeout (e.g., 1 minute), + LBOUND is a lower bound on the timeout (e.g., 1 second), ALPHA is + a smoothing factor (e.g., .8 to .9), and BETA is a delay variance + factor (e.g., 1.3 to 2.0). */ std::chrono::milliseconds Connection::RTO() const { - return 1s; + return 1s; } void Connection::start_time_wait_timeout() { - debug2(" Time Wait timer started. \n"); - time_wait_started = OS::cycles_since_boot(); - auto timeout = 2 * host().MSL(); // 60 seconds - // Passing "this"..? - hw::PIT::instance().onTimeout(timeout,[this, timeout] { - // The timer hasnt been updated - if( OS::cycles_since_boot() >= (time_wait_started + timeout.count()) ) { - signal_close(); - } else { - debug2(" time_wait_started has been updated. \n"); - } - }); + debug2(" Time Wait timer started. \n"); + time_wait_started = OS::cycles_since_boot(); + auto timeout = 2 * host().MSL(); // 60 seconds + // Passing "this"..? + hw::PIT::instance().onTimeout(timeout,[this, timeout] { + // The timer hasnt been updated + if( OS::cycles_since_boot() >= (time_wait_started + timeout.count()) ) { + signal_close(); + } else { + debug2(" time_wait_started has been updated. \n"); + } + }); } void Connection::signal_close() { - debug(" It's time to delete this connection. \n"); - host_.close_connection(*this); + debug(" It's time to delete this connection. \n"); + host_.close_connection(*this); } std::string Connection::TCB::to_string() const { - ostringstream os; - os << "SND" - << " .UNA = " << SND.UNA - << " .NXT = " << SND.NXT - << " .WND = " << SND.WND - << " .UP = " << SND.UP - << " .WL1 = " << SND.WL1 - << " .WL2 = " << SND.WL2 - << " ISS = " << ISS - << "\n RCV" - << " .NXT = " << RCV.NXT - << " .WND = " << RCV.WND - << " .UP = " << RCV.UP - << " IRS = " << IRS; - return os.str(); + ostringstream os; + os << "SND" + << " .UNA = " << SND.UNA + << " .NXT = " << SND.NXT + << " .WND = " << SND.WND + << " .UP = " << SND.UP + << " .WL1 = " << SND.WL1 + << " .WL2 = " << SND.WL2 + << " ISS = " << ISS + << "\n RCV" + << " .NXT = " << RCV.NXT + << " .WND = " << RCV.WND + << " .UP = " << RCV.UP + << " IRS = " << IRS; + return os.str(); } void Connection::parse_options(TCP::Packet_ptr packet) { - assert(packet->has_options()); - debug(" Parsing options. Offset: %u, Options: %u \n", - packet->offset(), packet->options_length()); + assert(packet->has_options()); + debug(" Parsing options. Offset: %u, Options: %u \n", + packet->offset(), packet->options_length()); - auto* opt = packet->options(); + auto* opt = packet->options(); - while((char*)opt < packet->data()) { + while((char*)opt < packet->data()) { - auto* option = (TCP::Option*)opt; + auto* option = (TCP::Option*)opt; - switch(option->kind) { - - case Option::END: { - return; - } - - case Option::NOP: { - opt++; - break; - } - - case Option::MSS: { - // unlikely - if(option->length != 4) - throw TCPBadOptionException{Option::MSS, "length != 4"}; - // unlikely - if(!packet->isset(SYN)) - throw TCPBadOptionException{Option::MSS, "Non-SYN packet"}; + switch(option->kind) { + + case Option::END: { + return; + } + + case Option::NOP: { + opt++; + break; + } + + case Option::MSS: { + // unlikely + if(option->length != 4) + throw TCPBadOptionException{Option::MSS, "length != 4"}; + // unlikely + if(!packet->isset(SYN)) + throw TCPBadOptionException{Option::MSS, "Non-SYN packet"}; - auto* opt_mss = (Option::opt_mss*)option; - uint16_t mss = ntohs(opt_mss->mss); - control_block.SND.MSS = mss; - debug2(" MSS: %u \n", mss); - opt += option->length; - break; - } - - default: - return; - } - } + auto* opt_mss = (Option::opt_mss*)option; + uint16_t mss = ntohs(opt_mss->mss); + control_block.SND.MSS = mss; + debug2(" MSS: %u \n", mss); + opt += option->length; + break; + } + + default: + return; + } + } } void Connection::add_option(TCP::Option::Kind kind, TCP::Packet_ptr packet) { - switch(kind) { - - case Option::MSS: { - packet->add_option(host_.MSS()); - debug2(" Packet: %s - MSS: %u\n", - packet->to_string().c_str(), ntohs(*(uint16_t*)(packet->options()+2))); - break; - } - default: - break; - } + switch(kind) { + + case Option::MSS: { + packet->add_option(host_.MSS()); + debug2(" Packet: %s - MSS: %u\n", + packet->to_string().c_str(), ntohs(*(uint16_t*)(packet->options()+2))); + break; + } + default: + break; + } } diff --git a/src/net/tcp_connection_states.cpp b/src/net/tcp_connection_states.cpp index 86916b22a0..1df39c391b 100644 --- a/src/net/tcp_connection_states.cpp +++ b/src/net/tcp_connection_states.cpp @@ -22,311 +22,311 @@ using namespace std; ///////////////////////////////////////////////////////////////////// /* - COMMON STATE FUNCTIONS + COMMON STATE FUNCTIONS */ ///////////////////////////////////////////////////////////////////// /* - 1. Check Sequence + 1. Check Sequence */ /* - SYN-RECEIVED STATE - ESTABLISHED STATE - FIN-WAIT-1 STATE - FIN-WAIT-2 STATE - CLOSE-WAIT STATE - CLOSING STATE - LAST-ACK STATE - TIME-WAIT STATE + SYN-RECEIVED STATE + ESTABLISHED STATE + FIN-WAIT-1 STATE + FIN-WAIT-2 STATE + CLOSE-WAIT STATE + CLOSING STATE + LAST-ACK STATE + TIME-WAIT STATE - Segments are processed in sequence. Initial tests on arrival - are used to discard old duplicates, but further processing is - done in SEG.SEQ order. If a segment's contents straddle the - boundary between old and new, only the new parts should be - processed. + Segments are processed in sequence. Initial tests on arrival + are used to discard old duplicates, but further processing is + done in SEG.SEQ order. If a segment's contents straddle the + boundary between old and new, only the new parts should be + processed. - There are four cases for the acceptability test for an incoming - segment: + There are four cases for the acceptability test for an incoming + segment: - Segment Receive Test - Length Window - ------- ------- ------------------------------------------- + Segment Receive Test + Length Window + ------- ------- ------------------------------------------- - 0 0 SEG.SEQ = RCV.NXT + 0 0 SEG.SEQ = RCV.NXT - 0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND + 0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND - >0 0 not acceptable + >0 0 not acceptable - >0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND - or RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND + >0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND + or RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND - If the RCV.WND is zero, no segments will be acceptable, but - special allowance should be made to accept valid ACKs, URGs and - RSTs. + If the RCV.WND is zero, no segments will be acceptable, but + special allowance should be made to accept valid ACKs, URGs and + RSTs. - If an incoming segment is not acceptable, an acknowledgment - should be sent in reply (unless the RST bit is set, if so drop - the segment and return): + If an incoming segment is not acceptable, an acknowledgment + should be sent in reply (unless the RST bit is set, if so drop + the segment and return): - + - After sending the acknowledgment, drop the unacceptable segment - and return. + After sending the acknowledgment, drop the unacceptable segment + and return. - In the following it is assumed that the segment is the idealized - segment that begins at RCV.NXT and does not exceed the window. - One could tailor actual segments to fit this assumption by - trimming off any portions that lie outside the window (including - SYN and FIN), and only processing further if the segment then - begins at RCV.NXT. Segments with higher begining sequence - numbers may be held for later processing. + In the following it is assumed that the segment is the idealized + segment that begins at RCV.NXT and does not exceed the window. + One could tailor actual segments to fit this assumption by + trimming off any portions that lie outside the window (including + SYN and FIN), and only processing further if the segment then + begins at RCV.NXT. Segments with higher begining sequence + numbers may be held for later processing. */ /* - TODO: Optimize this one. It checks for the same things. + TODO: Optimize this one. It checks for the same things. */ bool Connection::State::check_seq(Connection& tcp, TCP::Packet_ptr in) { - auto& tcb = tcp.tcb(); - bool acceptable = false; - debug2(" TCB: %s \n",tcb.to_string().c_str()); - // #1 - if( in->seq() == tcb.RCV.NXT ) { - acceptable = true; - } - // #2 - else if( tcb.RCV.NXT <= in->seq() and in->seq() < tcb.RCV.NXT + tcb.RCV.WND ) { - acceptable = true; - } - // #3 (INVALID) - else if( in->seq() + in->data_length()-1 > tcb.RCV.NXT+tcb.RCV.WND ) { - acceptable = false; - } - // #4 - else if( (tcb.RCV.NXT <= in->seq() and in->seq() < tcb.RCV.NXT + tcb.RCV.WND) - or ( tcb.RCV.NXT <= in->seq()+in->data_length()-1 and in->seq()+in->data_length()-1 < tcb.RCV.NXT+tcb.RCV.WND ) ) { - acceptable = true; - } - /* - If an incoming segment is not acceptable, an acknowledgment - should be sent in reply (unless the RST bit is set, if so drop - the segment and return): - - - - After sending the acknowledgment, drop the unacceptable segment - and return. - */ - if(!acceptable) { - if(!in->isset(RST)) { - tcp.outgoing_packet()->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); - tcp.transmit(); - } - tcp.drop(in, "Unacceptable SEQ."); - return false; - } - debug2(" Acceptable SEQ: %u \n", in->seq()); - // is acceptable. - return true; + auto& tcb = tcp.tcb(); + bool acceptable = false; + debug2(" TCB: %s \n",tcb.to_string().c_str()); + // #1 + if( in->seq() == tcb.RCV.NXT ) { + acceptable = true; + } + // #2 + else if( tcb.RCV.NXT <= in->seq() and in->seq() < tcb.RCV.NXT + tcb.RCV.WND ) { + acceptable = true; + } + // #3 (INVALID) + else if( in->seq() + in->data_length()-1 > tcb.RCV.NXT+tcb.RCV.WND ) { + acceptable = false; + } + // #4 + else if( (tcb.RCV.NXT <= in->seq() and in->seq() < tcb.RCV.NXT + tcb.RCV.WND) + or ( tcb.RCV.NXT <= in->seq()+in->data_length()-1 and in->seq()+in->data_length()-1 < tcb.RCV.NXT+tcb.RCV.WND ) ) { + acceptable = true; + } + /* + If an incoming segment is not acceptable, an acknowledgment + should be sent in reply (unless the RST bit is set, if so drop + the segment and return): + + + + After sending the acknowledgment, drop the unacceptable segment + and return. + */ + if(!acceptable) { + if(!in->isset(RST)) { + tcp.outgoing_packet()->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); + tcp.transmit(); + } + tcp.drop(in, "Unacceptable SEQ."); + return false; + } + debug2(" Acceptable SEQ: %u \n", in->seq()); + // is acceptable. + return true; } /* - 4. Check SYN + 4. Check SYN */ /* - SYN-RECEIVED - ESTABLISHED STATE - FIN-WAIT STATE-1 - FIN-WAIT STATE-2 - CLOSE-WAIT STATE - CLOSING STATE - LAST-ACK STATE - TIME-WAIT STATE - - If the SYN is in the window it is an error, send a reset, any - outstanding RECEIVEs and SEND should receive "reset" responses, - all segment queues should be flushed, the user should also - receive an unsolicited general "connection reset" signal, enter - the CLOSED state, delete the TCB, and return. - - If the SYN is not in the window this step would not be reached - and an ack would have been sent in the first step (sequence - number check). + SYN-RECEIVED + ESTABLISHED STATE + FIN-WAIT STATE-1 + FIN-WAIT STATE-2 + CLOSE-WAIT STATE + CLOSING STATE + LAST-ACK STATE + TIME-WAIT STATE + + If the SYN is in the window it is an error, send a reset, any + outstanding RECEIVEs and SEND should receive "reset" responses, + all segment queues should be flushed, the user should also + receive an unsolicited general "connection reset" signal, enter + the CLOSED state, delete the TCB, and return. + + If the SYN is not in the window this step would not be reached + and an ack would have been sent in the first step (sequence + number check). */ void Connection::State::unallowed_syn_reset_connection(Connection& tcp, TCP::Packet_ptr in) { - assert(in->isset(SYN)); - debug(" Unallowed SYN for STATE: %s, reseting connection.\n", - tcp.state().to_string().c_str()); - // Not sure if this is the correct way to send a "reset response" - tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); - tcp.transmit(); - tcp.signal_disconnect(Disconnect::RESET); + assert(in->isset(SYN)); + debug(" Unallowed SYN for STATE: %s, reseting connection.\n", + tcp.state().to_string().c_str()); + // Not sure if this is the correct way to send a "reset response" + tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); + tcp.transmit(); + tcp.signal_disconnect(Disconnect::RESET); } /* - 5. Check ACK + 5. Check ACK */ bool Connection::State::check_ack(Connection& tcp, TCP::Packet_ptr in) { - // 5. ACK bit - debug2(" Checking for ACK in STATE: %s \n", tcp.state().to_string().c_str()); - if( in->isset(ACK) ) { - auto& tcb = tcp.tcb(); - /* - If SND.UNA < SEG.ACK =< SND.NXT then, set SND.UNA <- SEG.ACK. - Any segments on the retransmission queue which are thereby - entirely acknowledged are removed. Users should receive - positive acknowledgments for buffers which have been SENT and - fully acknowledged (i.e., SEND buffer should be returned with - "ok" response). If the ACK is a duplicate - (SEG.ACK < SND.UNA), it can be ignored. If the ACK acks - something not yet sent (SEG.ACK > SND.NXT) then send an ACK, - drop the segment, and return. - */ - if( tcb.SND.UNA < in->ack() and in->ack() <= tcb.SND.NXT ) { - tcb.SND.UNA = in->ack(); - // tcp.signal_sent(); - // return that buffer has been SENT - currently no support to receipt sent buffer. - - /* - If SND.UNA < SEG.ACK =< SND.NXT, the send window should be - updated. If (SND.WL1 < SEG.SEQ or (SND.WL1 = SEG.SEQ and - SND.WL2 =< SEG.ACK)), set SND.WND <- SEG.WND, set - SND.WL1 <- SEG.SEQ, and set SND.WL2 <- SEG.ACK. - */ - if( tcb.SND.WL1 < in->seq() or ( tcb.SND.WL1 = in->seq() and tcb.SND.WL2 <= in->ack() ) ) { - tcb.SND.WND = in->win(); - tcb.SND.WL1 = in->seq(); - tcb.SND.WL2 = in->ack(); - } - /* - Note that SND.WND is an offset from SND.UNA, that SND.WL1 - records the sequence number of the last segment used to update - SND.WND, and that SND.WL2 records the acknowledgment number of - the last segment used to update SND.WND. The check here - prevents using old segments to update the window. - */ - + // 5. ACK bit + debug2(" Checking for ACK in STATE: %s \n", tcp.state().to_string().c_str()); + if( in->isset(ACK) ) { + auto& tcb = tcp.tcb(); + /* + If SND.UNA < SEG.ACK =< SND.NXT then, set SND.UNA <- SEG.ACK. + Any segments on the retransmission queue which are thereby + entirely acknowledged are removed. Users should receive + positive acknowledgments for buffers which have been SENT and + fully acknowledged (i.e., SEND buffer should be returned with + "ok" response). If the ACK is a duplicate + (SEG.ACK < SND.UNA), it can be ignored. If the ACK acks + something not yet sent (SEG.ACK > SND.NXT) then send an ACK, + drop the segment, and return. + */ + if( tcb.SND.UNA < in->ack() and in->ack() <= tcb.SND.NXT ) { + tcb.SND.UNA = in->ack(); + // tcp.signal_sent(); + // return that buffer has been SENT - currently no support to receipt sent buffer. + + /* + If SND.UNA < SEG.ACK =< SND.NXT, the send window should be + updated. If (SND.WL1 < SEG.SEQ or (SND.WL1 = SEG.SEQ and + SND.WL2 =< SEG.ACK)), set SND.WND <- SEG.WND, set + SND.WL1 <- SEG.SEQ, and set SND.WL2 <- SEG.ACK. + */ + if( tcb.SND.WL1 < in->seq() or ( tcb.SND.WL1 = in->seq() and tcb.SND.WL2 <= in->ack() ) ) { + tcb.SND.WND = in->win(); + tcb.SND.WL1 = in->seq(); + tcb.SND.WL2 = in->ack(); + } + /* + Note that SND.WND is an offset from SND.UNA, that SND.WL1 + records the sequence number of the last segment used to update + SND.WND, and that SND.WL2 records the acknowledgment number of + the last segment used to update SND.WND. The check here + prevents using old segments to update the window. + */ + + } + /* If the ACK acks something not yet sent (SEG.ACK > SND.NXT) then send an ACK, drop the segment, and return. */ + else if( in->ack() > tcb.SND.NXT ) { + tcp.outgoing_packet()->set_flag(ACK); + tcp.transmit(); + tcp.drop(in, "ACK > SND.NXT"); + return false; + } + /* If the ACK is a duplicate (SEG.ACK < SND.UNA), it can be ignored. */ + /*else if( in->ack() < tcb.SND.UNA ) { + // ignore. + }*/ + return true; } - /* If the ACK acks something not yet sent (SEG.ACK > SND.NXT) then send an ACK, drop the segment, and return. */ - else if( in->ack() > tcb.SND.NXT ) { - tcp.outgoing_packet()->set_flag(ACK); - tcp.transmit(); - tcp.drop(in, "ACK > SND.NXT"); - return false; + // ACK not set. + else { + tcp.drop(in, "!ACK"); + return false; } - /* If the ACK is a duplicate (SEG.ACK < SND.UNA), it can be ignored. */ - /*else if( in->ack() < tcb.SND.UNA ) { - // ignore. - }*/ - return true; - } - // ACK not set. - else { - tcp.drop(in, "!ACK"); - return false; - } } /* - 7. Process the segment text + 7. Process the segment text */ /* - Once in the ESTABLISHED state, it is possible to deliver segment - text to user RECEIVE buffers. Text from segments can be moved - into buffers until either the buffer is full or the segment is - empty. If the segment empties and carries an PUSH flag, then - the user is informed, when the buffer is returned, that a PUSH - has been received. + Once in the ESTABLISHED state, it is possible to deliver segment + text to user RECEIVE buffers. Text from segments can be moved + into buffers until either the buffer is full or the segment is + empty. If the segment empties and carries an PUSH flag, then + the user is informed, when the buffer is returned, that a PUSH + has been received. - When the TCP takes responsibility for delivering the data to the - user it must also acknowledge the receipt of the data. + When the TCP takes responsibility for delivering the data to the + user it must also acknowledge the receipt of the data. - Once the TCP takes responsibility for the data it advances - RCV.NXT over the data accepted, and adjusts RCV.WND as - apporopriate to the current buffer availability. The total of - RCV.NXT and RCV.WND should not be reduced. + Once the TCP takes responsibility for the data it advances + RCV.NXT over the data accepted, and adjusts RCV.WND as + apporopriate to the current buffer availability. The total of + RCV.NXT and RCV.WND should not be reduced. - Please note the window management suggestions in section 3.7. + Please note the window management suggestions in section 3.7. - Send an acknowledgment of the form: + Send an acknowledgment of the form: - + - This acknowledgment should be piggybacked on a segment being - transmitted if possible without incurring undue delay. + This acknowledgment should be piggybacked on a segment being + transmitted if possible without incurring undue delay. */ void Connection::State::process_segment(Connection& tcp, TCP::Packet_ptr in) { - assert(in->has_data()); - - auto& tcb = tcp.tcb(); - int length = in->data_length(); - debug(" Received packet with DATA-LENGTH: %i. Add to receive buffer. \n", length); - if(!tcp.add_to_receive_buffer(in)) { - tcp.signal_error({"Receive buffer is full!"}); // Redo to BufferException? - return; // Don't ACK, sender need to resend. - } - tcb.RCV.NXT += length; - auto snd_nxt = tcb.SND.NXT; - debug2(" Advanced RCV.NXT: %u. SND.NXT = %u \n", tcb.RCV.NXT, snd_nxt); - if(in->isset(PSH)) { - debug(" Packet carries PUSH. Notify user.\n"); - tcp.signal_receive(true); - } else if(tcp.receive_buffer().full()) { - // Buffer is now full - debug(" Receive buffer is full. Notify user. \n"); - tcp.signal_receive(false); - } - /* - Once the TCP takes responsibility for the data it advances - RCV.NXT over the data accepted, and adjusts RCV.WND as - apporopriate to the current buffer availability. The total of - RCV.NXT and RCV.WND should not be reduced. - */ - if(tcb.SND.NXT == snd_nxt) { - tcp.outgoing_packet()->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); - tcp.transmit(); - } else { - debug2(" SND.NXT > snd_nxt, this packet has already been acknowledged. \n"); - } + assert(in->has_data()); + + auto& tcb = tcp.tcb(); + int length = in->data_length(); + debug(" Received packet with DATA-LENGTH: %i. Add to receive buffer. \n", length); + if(!tcp.add_to_receive_buffer(in)) { + tcp.signal_error({"Receive buffer is full!"}); // Redo to BufferException? + return; // Don't ACK, sender need to resend. + } + tcb.RCV.NXT += length; + auto snd_nxt = tcb.SND.NXT; + debug2(" Advanced RCV.NXT: %u. SND.NXT = %u \n", tcb.RCV.NXT, snd_nxt); + if(in->isset(PSH)) { + debug(" Packet carries PUSH. Notify user.\n"); + tcp.signal_receive(true); + } else if(tcp.receive_buffer().full()) { + // Buffer is now full + debug(" Receive buffer is full. Notify user. \n"); + tcp.signal_receive(false); + } + /* + Once the TCP takes responsibility for the data it advances + RCV.NXT over the data accepted, and adjusts RCV.WND as + apporopriate to the current buffer availability. The total of + RCV.NXT and RCV.WND should not be reduced. + */ + if(tcb.SND.NXT == snd_nxt) { + tcp.outgoing_packet()->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); + tcp.transmit(); + } else { + debug2(" SND.NXT > snd_nxt, this packet has already been acknowledged. \n"); + } } /* - 8. Check FIN + 8. Check FIN */ /* - If the FIN bit is set, signal the user "connection closing" and - return any pending RECEIVEs with same message, advance RCV.NXT - over the FIN, and send an acknowledgment for the FIN. Note that - FIN implies PUSH for any segment text not yet delivered to the - user. + If the FIN bit is set, signal the user "connection closing" and + return any pending RECEIVEs with same message, advance RCV.NXT + over the FIN, and send an acknowledgment for the FIN. Note that + FIN implies PUSH for any segment text not yet delivered to the + user. */ void Connection::State::process_fin(Connection& tcp, TCP::Packet_ptr in) { - debug(" Processing FIN bit in STATE: %s \n", tcp.state().to_string().c_str()); - assert(in->isset(FIN)); - auto& tcb = tcp.tcb(); - tcp.signal_disconnect(Disconnect::CLOSING); - // Advance RCV.NXT over the FIN? - tcb.RCV.NXT++; - //auto fin = in->data_length(); - //tcb.RCV.NXT += fin; - tcp.outgoing_packet()->set_ack(tcb.RCV.NXT).set_flag(ACK); - tcp.transmit(); - if(!tcp.receive_buffer().empty()) { - tcp.signal_receive(true); - } + debug(" Processing FIN bit in STATE: %s \n", tcp.state().to_string().c_str()); + assert(in->isset(FIN)); + auto& tcb = tcp.tcb(); + tcp.signal_disconnect(Disconnect::CLOSING); + // Advance RCV.NXT over the FIN? + tcb.RCV.NXT++; + //auto fin = in->data_length(); + //tcb.RCV.NXT += fin; + tcp.outgoing_packet()->set_ack(tcb.RCV.NXT).set_flag(ACK); + tcp.transmit(); + if(!tcp.receive_buffer().empty()) { + tcp.signal_receive(true); + } } /* - Send a reset segment: + Send a reset segment: - + All queued SENDs and RECEIVEs should be given "connection reset" notification; all segments queued for transmission (except for the @@ -334,546 +334,546 @@ void Connection::State::process_fin(Connection& tcp, TCP::Packet_ptr in) { TCB, enter CLOSED state, and return. */ void Connection::State::send_reset(Connection& tcp) { - tcp.send_buffer_.clear(); - tcp.outgoing_packet()->set_seq(tcp.tcb().SND.NXT).set_ack(0).set_flag(RST); - tcp.transmit(); + tcp.send_buffer_.clear(); + tcp.outgoing_packet()->set_seq(tcp.tcb().SND.NXT).set_ack(0).set_flag(RST); + tcp.transmit(); } /* - Fallback. + Fallback. */ void Connection::State::open(Connection&, bool) { - throw TCPException{"Connection already exists."}; + throw TCPException{"Connection already exists."}; } size_t Connection::State::send(Connection&, const char*, size_t, bool) { - throw TCPException{"Connection closing."}; + throw TCPException{"Connection closing."}; } size_t Connection::State::receive(Connection&, char*, size_t) { - throw TCPException{"Connection closing."}; + throw TCPException{"Connection closing."}; } void Connection::State::close(Connection&) { - throw TCPException{"Connection closing."}; + throw TCPException{"Connection closing."}; } void Connection::State::abort(Connection&) { - // Do nothing. + // Do nothing. } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /* - CLOSED + CLOSED */ ///////////////////////////////////////////////////////////////////// void Connection::Closed::open(Connection& tcp, bool active) { - if(active) { - // There is a remote host - if(!tcp.remote().is_empty()) { - auto& tcb = tcp.tcb(); - tcb.ISS = tcp.generate_iss(); - auto packet = tcp.outgoing_packet(); - packet->set_seq(tcb.ISS).set_flag(SYN); + if(active) { + // There is a remote host + if(!tcp.remote().is_empty()) { + auto& tcb = tcp.tcb(); + tcb.ISS = tcp.generate_iss(); + auto packet = tcp.outgoing_packet(); + packet->set_seq(tcb.ISS).set_flag(SYN); - /* - Add MSS option. - */ - tcp.add_option(Option::MSS, packet); - - tcb.SND.UNA = tcb.ISS; - tcb.SND.NXT = tcb.ISS+1; - tcp.transmit(); - tcp.set_state(SynSent::instance()); - } else { - throw TCPException{"No remote host set."}; - } - } else { - tcp.set_state(Connection::Listen::instance()); - } + /* + Add MSS option. + */ + tcp.add_option(Option::MSS, packet); + + tcb.SND.UNA = tcb.ISS; + tcb.SND.NXT = tcb.ISS+1; + tcp.transmit(); + tcp.set_state(SynSent::instance()); + } else { + throw TCPException{"No remote host set."}; + } + } else { + tcp.set_state(Connection::Listen::instance()); + } } size_t Connection::Closed::send(Connection&, const char*, size_t, bool) { - throw TCPException{"Connection does not exist."}; + throw TCPException{"Connection does not exist."}; } State::Result Connection::Closed::handle(Connection& tcp, TCP::Packet_ptr in) { - if(in->isset(RST)) { - return OK; - } - if(!in->isset(ACK)) { - tcp.outgoing_packet()->set_seq(0).set_ack(in->seq() + in->data_length()).set_flags(RST | ACK); - } else { - tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); - } - tcp.transmit(); - return OK; + if(in->isset(RST)) { + return OK; + } + if(!in->isset(ACK)) { + tcp.outgoing_packet()->set_seq(0).set_ack(in->seq() + in->data_length()).set_flags(RST | ACK); + } else { + tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); + } + tcp.transmit(); + return OK; } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /* - LISTEN + LISTEN */ ///////////////////////////////////////////////////////////////////// void Connection::Listen::open(Connection& tcp, bool) { - if(!tcp.remote().is_empty()) { - auto& tcb = tcp.tcb(); - tcb.ISS = tcp.generate_iss(); - tcp.outgoing_packet()->set_seq(tcb.ISS).set_flag(SYN); - tcb.SND.UNA = tcb.ISS; - tcb.SND.NXT = tcb.ISS+1; - tcp.transmit(); - tcp.set_state(SynSent::instance()); - } else { - throw TCPException{"No remote host set."}; - } + if(!tcp.remote().is_empty()) { + auto& tcb = tcp.tcb(); + tcb.ISS = tcp.generate_iss(); + tcp.outgoing_packet()->set_seq(tcb.ISS).set_flag(SYN); + tcb.SND.UNA = tcb.ISS; + tcb.SND.NXT = tcb.ISS+1; + tcp.transmit(); + tcp.set_state(SynSent::instance()); + } else { + throw TCPException{"No remote host set."}; + } } size_t Connection::Listen::send(Connection&, const char*, size_t, bool) { - // TODO: Skip this? - /* - If the foreign socket is specified, then change the connection - from passive to active, select an ISS. Send a SYN segment, set - SND.UNA to ISS, SND.NXT to ISS+1. Enter SYN-SENT state. Data - associated with SEND may be sent with SYN segment or queued for - transmission after entering ESTABLISHED state. The urgent bit if - requested in the command must be sent with the data segments sent - as a result of this command. If there is no room to queue the - request, respond with "error: insufficient resources". If - Foreign socket was not specified, then return "error: foreign - socket unspecified". - */ - - return 0; + // TODO: Skip this? + /* + If the foreign socket is specified, then change the connection + from passive to active, select an ISS. Send a SYN segment, set + SND.UNA to ISS, SND.NXT to ISS+1. Enter SYN-SENT state. Data + associated with SEND may be sent with SYN segment or queued for + transmission after entering ESTABLISHED state. The urgent bit if + requested in the command must be sent with the data segments sent + as a result of this command. If there is no room to queue the + request, respond with "error: insufficient resources". If + Foreign socket was not specified, then return "error: foreign + socket unspecified". + */ + + return 0; } void Connection::Listen::close(Connection& tcp) { - /* - Any outstanding RECEIVEs are returned with "error: closing" - responses. Delete TCB, enter CLOSED state, and return. - */ + /* + Any outstanding RECEIVEs are returned with "error: closing" + responses. Delete TCB, enter CLOSED state, and return. + */ - // tcp.signal_disconnect("Closing") - tcp.set_state(Closed::instance()); + // tcp.signal_disconnect("Closing") + tcp.set_state(Closed::instance()); } State::Result Connection::Listen::handle(Connection& tcp, TCP::Packet_ptr in) { - if(in->isset(RST)) { - // ignore - return OK; - } - if(in->isset(ACK)) { - tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); - tcp.transmit(); - return OK; - } - if(in->isset(SYN)) { - if(!tcp.signal_accept()) { - // TODO: Reject more gracefully? - return CLOSED; - } - auto& tcb = tcp.tcb(); - tcb.RCV.NXT = in->seq()+1; - tcb.IRS = in->seq(); - tcb.ISS = tcp.generate_iss(); - tcb.SND.NXT = tcb.ISS+1; - tcb.SND.UNA = tcb.ISS; - debug(" Received SYN Packet: %s TCB Updated:\n %s \n", - in->to_string().c_str(), tcp.tcb().to_string().c_str()); - - auto packet = tcp.outgoing_packet(); - packet->set_seq(tcb.ISS).set_ack(tcb.RCV.NXT).set_flags(SYN | ACK); + if(in->isset(RST)) { + // ignore + return OK; + } + if(in->isset(ACK)) { + tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); + tcp.transmit(); + return OK; + } + if(in->isset(SYN)) { + if(!tcp.signal_accept()) { + // TODO: Reject more gracefully? + return CLOSED; + } + auto& tcb = tcp.tcb(); + tcb.RCV.NXT = in->seq()+1; + tcb.IRS = in->seq(); + tcb.ISS = tcp.generate_iss(); + tcb.SND.NXT = tcb.ISS+1; + tcb.SND.UNA = tcb.ISS; + debug(" Received SYN Packet: %s TCB Updated:\n %s \n", + in->to_string().c_str(), tcp.tcb().to_string().c_str()); + + auto packet = tcp.outgoing_packet(); + packet->set_seq(tcb.ISS).set_ack(tcb.RCV.NXT).set_flags(SYN | ACK); - /* - Add MSS option. - TODO: Send even if we havent received MSS option? - */ - tcp.add_option(Option::MSS, packet); + /* + Add MSS option. + TODO: Send even if we havent received MSS option? + */ + tcp.add_option(Option::MSS, packet); - tcp.transmit(); - tcp.set_state(SynReceived::instance()); + tcp.transmit(); + tcp.set_state(SynReceived::instance()); - return OK; - } - return OK; + return OK; + } + return OK; } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /* - SYN-SENT + SYN-SENT */ ///////////////////////////////////////////////////////////////////// size_t Connection::SynSent::send(Connection& tcp, const char* buffer, size_t n, bool push) { - /* - Queue the data for transmission after entering ESTABLISHED state. - If no space to queue, respond with "error: insufficient - resources". - */ - return tcp.write_to_send_buffer(buffer, n, push); + /* + Queue the data for transmission after entering ESTABLISHED state. + If no space to queue, respond with "error: insufficient + resources". + */ + return tcp.write_to_send_buffer(buffer, n, push); } void Connection::SynSent::close(Connection& tcp) { - /* - Delete the TCB and return "error: closing" responses to any - queued SENDs, or RECEIVEs. - */ + /* + Delete the TCB and return "error: closing" responses to any + queued SENDs, or RECEIVEs. + */ - // tcp.signal_disconnect("Closing") - tcp.set_state(Closed::instance()); + // tcp.signal_disconnect("Closing") + tcp.set_state(Closed::instance()); } State::Result Connection::SynSent::handle(Connection& tcp, TCP::Packet_ptr in) { - auto& tcb = tcp.tcb(); - // 1. check ACK - if(in->isset(ACK)) { - // If SEG.ACK =< ISS, or SEG.ACK > SND.NXT - if(in->ack() <= tcb.ISS or in->ack() > tcb.SND.NXT) { - // send a reset - if(!in->isset(RST)) { - tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); - tcp.transmit(); - return OK; - } - // (unless the RST bit is set, if so drop the segment and return) - else { - tcp.drop(in, "RST"); - return OK; - } - // If SND.UNA =< SEG.ACK =< SND.NXT then the ACK is acceptable. - } - } - // 2. check RST - if(in->isset(RST)) { - if(in->isset(ACK)) { - tcp.signal_error(TCPException{"Connection reset."}); - tcp.drop(in, "RST with acceptable ACK"); - return CLOSED; - } else { - tcp.drop(in, "RST"); - return OK; - } + auto& tcb = tcp.tcb(); + // 1. check ACK + if(in->isset(ACK)) { + // If SEG.ACK =< ISS, or SEG.ACK > SND.NXT + if(in->ack() <= tcb.ISS or in->ack() > tcb.SND.NXT) { + // send a reset + if(!in->isset(RST)) { + tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); + tcp.transmit(); + return OK; + } + // (unless the RST bit is set, if so drop the segment and return) + else { + tcp.drop(in, "RST"); + return OK; + } + // If SND.UNA =< SEG.ACK =< SND.NXT then the ACK is acceptable. + } + } + // 2. check RST + if(in->isset(RST)) { + if(in->isset(ACK)) { + tcp.signal_error(TCPException{"Connection reset."}); + tcp.drop(in, "RST with acceptable ACK"); + return CLOSED; + } else { + tcp.drop(in, "RST"); + return OK; + } + /* + If the ACK was acceptable then signal the user "error: + connection reset", drop the segment, enter CLOSED state, + delete TCB, and return. Otherwise (no ACK) drop the segment + and return. + */ + + } + // 3. Check security + + // 4. check SYN + /* + This step should be reached only if the ACK is ok, or there is + no ACK, and it the segment did not contain a RST. + + If the SYN bit is on and the security/compartment and precedence + are acceptable then, RCV.NXT is set to SEG.SEQ+1, IRS is set to + SEG.SEQ. SND.UNA should be advanced to equal SEG.ACK (if there + is an ACK), and any segments on the retransmission queue which + are thereby acknowledged should be removed. + + If SND.UNA > ISS (our SYN has been ACKed), change the connection + state to ESTABLISHED, form an ACK segment + + + + and send it. Data or controls which were queued for + transmission may be included. If there are other controls or + text in the segment then continue processing at the sixth step + below where the URG bit is checked, otherwise return. + + Otherwise enter SYN-RECEIVED, form a SYN,ACK segment + + + + and send it. If there are other controls or text in the + segment, queue them for processing after the ESTABLISHED state + has been reached, return. + */ /* - If the ACK was acceptable then signal the user "error: - connection reset", drop the segment, enter CLOSED state, - delete TCB, and return. Otherwise (no ACK) drop the segment - and return. + TODO: Fix this one according to the text above. */ - - } - // 3. Check security - - // 4. check SYN - /* - This step should be reached only if the ACK is ok, or there is - no ACK, and it the segment did not contain a RST. - - If the SYN bit is on and the security/compartment and precedence - are acceptable then, RCV.NXT is set to SEG.SEQ+1, IRS is set to - SEG.SEQ. SND.UNA should be advanced to equal SEG.ACK (if there - is an ACK), and any segments on the retransmission queue which - are thereby acknowledged should be removed. - - If SND.UNA > ISS (our SYN has been ACKed), change the connection - state to ESTABLISHED, form an ACK segment - - - - and send it. Data or controls which were queued for - transmission may be included. If there are other controls or - text in the segment then continue processing at the sixth step - below where the URG bit is checked, otherwise return. - - Otherwise enter SYN-RECEIVED, form a SYN,ACK segment - - - - and send it. If there are other controls or text in the - segment, queue them for processing after the ESTABLISHED state - has been reached, return. - */ - /* - TODO: Fix this one according to the text above. - */ - if(in->isset(SYN)) { - tcb.RCV.NXT = in->seq()+1; - tcb.IRS = in->seq(); - tcb.SND.UNA = in->ack(); + if(in->isset(SYN)) { + tcb.RCV.NXT = in->seq()+1; + tcb.IRS = in->seq(); + tcb.SND.UNA = in->ack(); - // (our SYN has been ACKed) - if(tcb.SND.UNA > tcb.ISS) { - tcp.set_state(Connection::Established::instance()); - TCP::Seq snd_nxt = tcb.SND.NXT; - tcp.signal_connect(); // NOTE: User callback - if(tcb.SND.NXT == snd_nxt) { - tcp.outgoing_packet()->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); - tcp.transmit(); - } - // State is now ESTABLISHED. - // Experimental, also makes unessecary process. - //in->clear_flag(SYN); - //tcp.state().handle(tcp, in); + // (our SYN has been ACKed) + if(tcb.SND.UNA > tcb.ISS) { + tcp.set_state(Connection::Established::instance()); + TCP::Seq snd_nxt = tcb.SND.NXT; + tcp.signal_connect(); // NOTE: User callback + if(tcb.SND.NXT == snd_nxt) { + tcp.outgoing_packet()->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); + tcp.transmit(); + } + // State is now ESTABLISHED. + // Experimental, also makes unessecary process. + //in->clear_flag(SYN); + //tcp.state().handle(tcp, in); - // 7. process segment text - if(in->has_data()) { - process_segment(tcp, in); - } - - // 8. check FIN bit - if(in->isset(FIN)) { - process_fin(tcp, in); - tcp.set_state(Connection::CloseWait::instance()); - return OK; - } - return OK; + // 7. process segment text + if(in->has_data()) { + process_segment(tcp, in); + } + + // 8. check FIN bit + if(in->isset(FIN)) { + process_fin(tcp, in); + tcp.set_state(Connection::CloseWait::instance()); + return OK; + } + return OK; + } + // Otherwise enter SYN-RECEIVED, form a SYN,ACK segment + else { + tcp.outgoing_packet()->set_seq(tcb.ISS).set_ack(tcb.RCV.NXT).set_flags(SYN | ACK); + tcp.transmit(); + tcp.set_state(Connection::SynReceived::instance()); + if(in->has_data()) { + tcp.add_to_receive_buffer(in); + // Advance RCV.NXT ?? + tcb.RCV.NXT += in->data_length(); + } + return OK; + /* + If there are other controls or text in the + segment, queue them for processing after the ESTABLISHED state + has been reached, return. + + HOW? return tcp.receive(in); ? + */ + } } - // Otherwise enter SYN-RECEIVED, form a SYN,ACK segment - else { - tcp.outgoing_packet()->set_seq(tcb.ISS).set_ack(tcb.RCV.NXT).set_flags(SYN | ACK); - tcp.transmit(); - tcp.set_state(Connection::SynReceived::instance()); - if(in->has_data()) { - tcp.add_to_receive_buffer(in); - // Advance RCV.NXT ?? - tcb.RCV.NXT += in->data_length(); - } - return OK; - /* - If there are other controls or text in the - segment, queue them for processing after the ESTABLISHED state - has been reached, return. - - HOW? return tcp.receive(in); ? - */ - } - } - tcp.drop(in); - return OK; + tcp.drop(in); + return OK; } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /* - SYN-RECEIVED + SYN-RECEIVED */ ///////////////////////////////////////////////////////////////////// size_t Connection::SynReceived::send(Connection& tcp, const char* buffer, size_t n, bool push) { - /* - Queue the data for transmission after entering ESTABLISHED state. - If no space to queue, respond with "error: insufficient - resources". - */ - return tcp.write_to_send_buffer(buffer, n, push); + /* + Queue the data for transmission after entering ESTABLISHED state. + If no space to queue, respond with "error: insufficient + resources". + */ + return tcp.write_to_send_buffer(buffer, n, push); } void Connection::SynReceived::close(Connection& tcp) { - /* - If no SENDs have been issued and there is no pending data to send, - then form a FIN segment and send it, and enter FIN-WAIT-1 state; - otherwise queue for processing after entering ESTABLISHED state. - */ - // Dont know how to queue for close for processing... - auto& tcb = tcp.tcb(); - tcp.outgoing_packet()->set_seq(tcb.SND.NXT++).set_ack(tcb.RCV.NXT).set_flags(ACK | FIN); - tcp.transmit(); - tcp.set_state(Connection::FinWait1::instance()); + /* + If no SENDs have been issued and there is no pending data to send, + then form a FIN segment and send it, and enter FIN-WAIT-1 state; + otherwise queue for processing after entering ESTABLISHED state. + */ + // Dont know how to queue for close for processing... + auto& tcb = tcp.tcb(); + tcp.outgoing_packet()->set_seq(tcb.SND.NXT++).set_ack(tcb.RCV.NXT).set_flags(ACK | FIN); + tcp.transmit(); + tcp.set_state(Connection::FinWait1::instance()); } void Connection::SynReceived::abort(Connection& tcp) { - send_reset(tcp); + send_reset(tcp); } State::Result Connection::SynReceived::handle(Connection& tcp, TCP::Packet_ptr in) { - // 1. check sequence - if(! check_seq(tcp, in) ) { - return OK; - } - // 2. check RST - if(in->isset(RST)) { - /* - If this connection was initiated with a passive OPEN (i.e., - came from the LISTEN state), then return this connection to - LISTEN state and return. The user need not be informed. If - this connection was initiated with an active OPEN (i.e., came - from SYN-SENT state) then the connection was refused, signal - the user "connection refused". In either case, all segments - on the retransmission queue should be removed. And in the - active OPEN case, enter the CLOSED state and delete the TCB, - and return. - */ - // Since we create a new connection when it starts listening, we don't wanna do this, but just delete it. - - if(tcp.prev_state().to_string() == Connection::SynSent::instance().to_string()) { - tcp.signal_disconnect(Disconnect::REFUSED); - } - - return CLOSED; - } - // 3. check security - - // 4. check SYN - if( in->isset(SYN) ) { - unallowed_syn_reset_connection(tcp, in); - return CLOSED; - } - - // 5. check ACK - if(in->isset(ACK)) { - auto& tcb = tcp.tcb(); - /* - If SND.UNA =< SEG.ACK =< SND.NXT then enter ESTABLISHED state - and continue processing. - */ - if(tcb.SND.UNA <= in->ack() and in->ack() <= tcb.SND.NXT) { - debug(" SND.UNA =< SEG.ACK =< SND.NXT, continue in ESTABLISHED. \n"); - tcp.set_state(Connection::Established::instance()); - tcp.signal_connect(); // NOTE: User callback - return tcp.state().handle(tcp,in); // TODO: Fix. This is kinda bad, need to make the above steps again. - } - /* - If the segment acknowledgment is not acceptable, form a - reset segment, and send it. - */ - else { - tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); - tcp.transmit(); - } - } - // ACK is missing - else { - tcp.drop(in, "SYN-RCV: !ACK"); - return OK; - } - - // 8. check FIN - if(in->isset(FIN)) { - process_fin(tcp, in); - tcp.set_state(Connection::CloseWait::instance()); - return OK; - } - return OK; + // 1. check sequence + if(! check_seq(tcp, in) ) { + return OK; + } + // 2. check RST + if(in->isset(RST)) { + /* + If this connection was initiated with a passive OPEN (i.e., + came from the LISTEN state), then return this connection to + LISTEN state and return. The user need not be informed. If + this connection was initiated with an active OPEN (i.e., came + from SYN-SENT state) then the connection was refused, signal + the user "connection refused". In either case, all segments + on the retransmission queue should be removed. And in the + active OPEN case, enter the CLOSED state and delete the TCB, + and return. + */ + // Since we create a new connection when it starts listening, we don't wanna do this, but just delete it. + + if(tcp.prev_state().to_string() == Connection::SynSent::instance().to_string()) { + tcp.signal_disconnect(Disconnect::REFUSED); + } + + return CLOSED; + } + // 3. check security + + // 4. check SYN + if( in->isset(SYN) ) { + unallowed_syn_reset_connection(tcp, in); + return CLOSED; + } + + // 5. check ACK + if(in->isset(ACK)) { + auto& tcb = tcp.tcb(); + /* + If SND.UNA =< SEG.ACK =< SND.NXT then enter ESTABLISHED state + and continue processing. + */ + if(tcb.SND.UNA <= in->ack() and in->ack() <= tcb.SND.NXT) { + debug(" SND.UNA =< SEG.ACK =< SND.NXT, continue in ESTABLISHED. \n"); + tcp.set_state(Connection::Established::instance()); + tcp.signal_connect(); // NOTE: User callback + return tcp.state().handle(tcp,in); // TODO: Fix. This is kinda bad, need to make the above steps again. + } + /* + If the segment acknowledgment is not acceptable, form a + reset segment, and send it. + */ + else { + tcp.outgoing_packet()->set_seq(in->ack()).set_flag(RST); + tcp.transmit(); + } + } + // ACK is missing + else { + tcp.drop(in, "SYN-RCV: !ACK"); + return OK; + } + + // 8. check FIN + if(in->isset(FIN)) { + process_fin(tcp, in); + tcp.set_state(Connection::CloseWait::instance()); + return OK; + } + return OK; } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /* - ESTABLISHED + ESTABLISHED */ ///////////////////////////////////////////////////////////////////// /* - Segmentize the buffer and send it with a piggybacked - acknowledgment (acknowledgment value = RCV.NXT). If there is - insufficient space to remember this buffer, simply return "error: - insufficient resources". + Segmentize the buffer and send it with a piggybacked + acknowledgment (acknowledgment value = RCV.NXT). If there is + insufficient space to remember this buffer, simply return "error: + insufficient resources". - If the urgent flag is set, then SND.UP <- SND.NXT-1 and set the - urgent pointer in the outgoing segments. + If the urgent flag is set, then SND.UP <- SND.NXT-1 and set the + urgent pointer in the outgoing segments. */ size_t Connection::Established::send(Connection& tcp, const char* buffer, size_t n, bool push) { - debug(" Sending data with the length of %u. PUSH: %d \n", n, push); - auto bytes_written = tcp.write_to_send_buffer(buffer, n, push); - tcp.transmit(); - return bytes_written; - /* - 3.7 Data Communication - The sender of data keeps track of the next sequence number to use in - the variable SND.NXT. The receiver of data keeps track of the next - sequence number to expect in the variable RCV.NXT. The sender of data - keeps track of the oldest unacknowledged sequence number in the - variable SND.UNA. If the data flow is momentarily idle and all data - sent has been acknowledged then the three variables will be equal. - - When the sender creates a segment and transmits it the sender advances - SND.NXT. When the receiver accepts a segment it advances RCV.NXT and - sends an acknowledgment. When the data sender receives an - acknowledgment it advances SND.UNA. The extent to which the values of - these variables differ is a measure of the delay in the communication. - The amount by which the variables are advanced is the length of the - data in the segment. Note that once in the ESTABLISHED state all - segments must carry current acknowledgment information. - */ + debug(" Sending data with the length of %u. PUSH: %d \n", n, push); + auto bytes_written = tcp.write_to_send_buffer(buffer, n, push); + tcp.transmit(); + return bytes_written; + /* + 3.7 Data Communication + The sender of data keeps track of the next sequence number to use in + the variable SND.NXT. The receiver of data keeps track of the next + sequence number to expect in the variable RCV.NXT. The sender of data + keeps track of the oldest unacknowledged sequence number in the + variable SND.UNA. If the data flow is momentarily idle and all data + sent has been acknowledged then the three variables will be equal. + + When the sender creates a segment and transmits it the sender advances + SND.NXT. When the receiver accepts a segment it advances RCV.NXT and + sends an acknowledgment. When the data sender receives an + acknowledgment it advances SND.UNA. The extent to which the values of + these variables differ is a measure of the delay in the communication. + The amount by which the variables are advanced is the length of the + data in the segment. Note that once in the ESTABLISHED state all + segments must carry current acknowledgment information. + */ } size_t Connection::Established::receive(Connection& tcp, char* buffer, size_t n) { - return tcp.read_from_receive_buffer(buffer, n); + return tcp.read_from_receive_buffer(buffer, n); } void Connection::Established::close(Connection& tcp) { - auto& tcb = tcp.tcb(); - tcp.outgoing_packet()->set_seq(tcb.SND.NXT++).set_ack(tcb.RCV.NXT).set_flags(ACK | FIN); - tcp.transmit(); - tcp.set_state(Connection::FinWait1::instance()); + auto& tcb = tcp.tcb(); + tcp.outgoing_packet()->set_seq(tcb.SND.NXT++).set_ack(tcb.RCV.NXT).set_flags(ACK | FIN); + tcp.transmit(); + tcp.set_state(Connection::FinWait1::instance()); } void Connection::Established::abort(Connection& tcp) { - send_reset(tcp); + send_reset(tcp); } State::Result Connection::Established::handle(Connection& tcp, TCP::Packet_ptr in) { - // 1. check SEQ - if(! check_seq(tcp, in) ) { - return OK; - } + // 1. check SEQ + if(! check_seq(tcp, in) ) { + return OK; + } - // 2. check RST - if( in->isset(RST) ) { - tcp.signal_disconnect(Disconnect::RESET); - return CLOSED; // close - } + // 2. check RST + if( in->isset(RST) ) { + tcp.signal_disconnect(Disconnect::RESET); + return CLOSED; // close + } - // 3. check security + // 3. check security - // 4. check SYN - if( in->isset(SYN) ) { - unallowed_syn_reset_connection(tcp, in); - return CLOSED; - } + // 4. check SYN + if( in->isset(SYN) ) { + unallowed_syn_reset_connection(tcp, in); + return CLOSED; + } - // 5. check ACK - if( ! check_ack(tcp, in) ) { - return OK; - } - // 6. check URG - DEPRECATED - - // 7. proccess the segment text - if(in->has_data()) { - process_segment(tcp, in); - } - - // 8. check FIN bit - if(in->isset(FIN)) { - process_fin(tcp, in); - tcp.set_state(Connection::CloseWait::instance()); - return CLOSE; - } - return OK; + // 5. check ACK + if( ! check_ack(tcp, in) ) { + return OK; + } + // 6. check URG - DEPRECATED + + // 7. proccess the segment text + if(in->has_data()) { + process_segment(tcp, in); + } + + // 8. check FIN bit + if(in->isset(FIN)) { + process_fin(tcp, in); + tcp.set_state(Connection::CloseWait::instance()); + return CLOSE; + } + return OK; } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /* - FIN-WAIT-1 + FIN-WAIT-1 */ ///////////////////////////////////////////////////////////////////// size_t Connection::FinWait1::receive(Connection& tcp, char* buffer, size_t n) { - return tcp.read_from_receive_buffer(buffer, n); + return tcp.read_from_receive_buffer(buffer, n); } void Connection::FinWait1::close(Connection&) { @@ -881,78 +881,78 @@ void Connection::FinWait1::close(Connection&) { } void Connection::FinWait1::abort(Connection& tcp) { - send_reset(tcp); + send_reset(tcp); } State::Result Connection::FinWait1::handle(Connection& tcp, TCP::Packet_ptr in) { - // 1. Check sequence number - if(! check_seq(tcp, in) ) { - return OK; - } - - // 2. check RST - if( in->isset(RST) ) { - tcp.signal_disconnect(Disconnect::RESET); - return CLOSED; // close - } - - // 4. check SYN - if( in->isset(SYN) ) { - unallowed_syn_reset_connection(tcp, in); - return CLOSED; - } - - // 5. check ACK - if( ! check_ack(tcp, in) ) { - return OK; - } - /* - In addition to the processing for the ESTABLISHED state, if - our FIN is now acknowledged then enter FIN-WAIT-2 and continue - processing in that state. - */ - debug2(" Current TCB:\n %s \n", tcp.tcb().to_string().c_str()); - if(in->ack() == tcp.tcb().SND.NXT) { - // TODO: I guess or FIN is ACK'ed..? - tcp.set_state(Connection::FinWait2::instance()); - return tcp.state().handle(tcp, in); // TODO: Is this OK? - } - - // 7. proccess the segment text - if(in->has_data()) { - process_segment(tcp, in); - } - - // 8. check FIN - if(in->isset(FIN)) { - process_fin(tcp, in); - debug2(" FIN isset. TCB:\n %s \n", tcp.tcb().to_string().c_str()); + // 1. Check sequence number + if(! check_seq(tcp, in) ) { + return OK; + } + + // 2. check RST + if( in->isset(RST) ) { + tcp.signal_disconnect(Disconnect::RESET); + return CLOSED; // close + } + + // 4. check SYN + if( in->isset(SYN) ) { + unallowed_syn_reset_connection(tcp, in); + return CLOSED; + } + + // 5. check ACK + if( ! check_ack(tcp, in) ) { + return OK; + } /* - If our FIN has been ACKed (perhaps in this segment), then - enter TIME-WAIT, start the time-wait timer, turn off the other - timers; otherwise enter the CLOSING state. + In addition to the processing for the ESTABLISHED state, if + our FIN is now acknowledged then enter FIN-WAIT-2 and continue + processing in that state. */ + debug2(" Current TCB:\n %s \n", tcp.tcb().to_string().c_str()); if(in->ack() == tcp.tcb().SND.NXT) { - // TODO: I guess or FIN is ACK'ed..? - tcp.set_state(TimeWait::instance()); - tcp.start_time_wait_timeout(); - } else { - tcp.set_state(Closing::instance()); + // TODO: I guess or FIN is ACK'ed..? + tcp.set_state(Connection::FinWait2::instance()); + return tcp.state().handle(tcp, in); // TODO: Is this OK? } - } - return OK; + + // 7. proccess the segment text + if(in->has_data()) { + process_segment(tcp, in); + } + + // 8. check FIN + if(in->isset(FIN)) { + process_fin(tcp, in); + debug2(" FIN isset. TCB:\n %s \n", tcp.tcb().to_string().c_str()); + /* + If our FIN has been ACKed (perhaps in this segment), then + enter TIME-WAIT, start the time-wait timer, turn off the other + timers; otherwise enter the CLOSING state. + */ + if(in->ack() == tcp.tcb().SND.NXT) { + // TODO: I guess or FIN is ACK'ed..? + tcp.set_state(TimeWait::instance()); + tcp.start_time_wait_timeout(); + } else { + tcp.set_state(Closing::instance()); + } + } + return OK; } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /* - FIN-WAIT-2 + FIN-WAIT-2 */ ///////////////////////////////////////////////////////////////////// size_t Connection::FinWait2::receive(Connection& tcp, char* buffer, size_t n) { - return tcp.read_from_receive_buffer(buffer, n); + return tcp.read_from_receive_buffer(buffer, n); } void Connection::FinWait2::close(Connection&) { @@ -960,247 +960,247 @@ void Connection::FinWait2::close(Connection&) { } void Connection::FinWait2::abort(Connection& tcp) { - send_reset(tcp); + send_reset(tcp); } State::Result Connection::FinWait2::handle(Connection& tcp, TCP::Packet_ptr in) { - // 1. check SEQ - if(! check_seq(tcp, in) ) { - return OK; - } - - // 2. check RST - if( in->isset(RST) ) { - tcp.signal_disconnect(Disconnect::RESET); - return CLOSED; // close - } - - // 4. check SYN - if( in->isset(SYN) ) { - unallowed_syn_reset_connection(tcp, in); - return CLOSED; - } - - // 5. check ACK - if( ! check_ack(tcp, in) ) { - return OK; - } + // 1. check SEQ + if(! check_seq(tcp, in) ) { + return OK; + } - // 7. proccess the segment text - if(in->has_data()) { - process_segment(tcp, in); - } + // 2. check RST + if( in->isset(RST) ) { + tcp.signal_disconnect(Disconnect::RESET); + return CLOSED; // close + } - // 8. check FIN - if(in->isset(FIN)) { - process_fin(tcp, in); - /* - Enter the TIME-WAIT state. Start the time-wait timer, turn off the other timers. - */ - tcp.set_state(Connection::TimeWait::instance()); - tcp.start_time_wait_timeout(); - } - return OK; + // 4. check SYN + if( in->isset(SYN) ) { + unallowed_syn_reset_connection(tcp, in); + return CLOSED; + } + + // 5. check ACK + if( ! check_ack(tcp, in) ) { + return OK; + } + + // 7. proccess the segment text + if(in->has_data()) { + process_segment(tcp, in); + } + + // 8. check FIN + if(in->isset(FIN)) { + process_fin(tcp, in); + /* + Enter the TIME-WAIT state. Start the time-wait timer, turn off the other timers. + */ + tcp.set_state(Connection::TimeWait::instance()); + tcp.start_time_wait_timeout(); + } + return OK; } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /* - CLOSE-WAIT + CLOSE-WAIT */ ///////////////////////////////////////////////////////////////////// size_t Connection::CloseWait::send(Connection& tcp, const char* buffer, size_t n, bool push) { - debug(" Sending data with the length of %u. PUSH: %d \n", n, push); - auto bytes_written = tcp.write_to_send_buffer(buffer, n, push); - tcp.transmit(); - return bytes_written; + debug(" Sending data with the length of %u. PUSH: %d \n", n, push); + auto bytes_written = tcp.write_to_send_buffer(buffer, n, push); + tcp.transmit(); + return bytes_written; } size_t Connection::CloseWait::receive(Connection& tcp, char* buffer, size_t n) { - return tcp.read_from_receive_buffer(buffer, n); + return tcp.read_from_receive_buffer(buffer, n); } void Connection::CloseWait::close(Connection& tcp) { - /* - Queue this request until all preceding SENDs have been - segmentized; then send a FIN segment, enter CLOSING state. - */ - auto& tcb = tcp.tcb(); - tcp.outgoing_packet()->set_seq(tcb.SND.NXT++).set_ack(tcb.RCV.NXT).set_flags(ACK | FIN); - tcp.transmit(); - tcp.set_state(Connection::Closing::instance()); + /* + Queue this request until all preceding SENDs have been + segmentized; then send a FIN segment, enter CLOSING state. + */ + auto& tcb = tcp.tcb(); + tcp.outgoing_packet()->set_seq(tcb.SND.NXT++).set_ack(tcb.RCV.NXT).set_flags(ACK | FIN); + tcp.transmit(); + tcp.set_state(Connection::Closing::instance()); } void Connection::CloseWait::abort(Connection& tcp) { - send_reset(tcp); + send_reset(tcp); } State::Result Connection::CloseWait::handle(Connection& tcp, TCP::Packet_ptr in) { - // 1. check SEQ - if(! check_seq(tcp, in) ) { - return OK; - } - - // 2. check RST - if( in->isset(RST) ) { - tcp.signal_disconnect(Disconnect::RESET); - return CLOSED; // close - } - - // 4. check SYN - if( in->isset(SYN) ) { - unallowed_syn_reset_connection(tcp, in); - return CLOSED; - } - - // 5. check ACK - if( ! check_ack(tcp, in) ) { - return OK; - } + // 1. check SEQ + if(! check_seq(tcp, in) ) { + return OK; + } + + // 2. check RST + if( in->isset(RST) ) { + tcp.signal_disconnect(Disconnect::RESET); + return CLOSED; // close + } - // 7. proccess the segment text - // This should not occur, since a FIN has been received from the remote side. Ignore the segment text. + // 4. check SYN + if( in->isset(SYN) ) { + unallowed_syn_reset_connection(tcp, in); + return CLOSED; + } - // 8. check FIN - if(in->isset(FIN)) { - process_fin(tcp, in); - // Remain in state + // 5. check ACK + if( ! check_ack(tcp, in) ) { + return OK; + } + + // 7. proccess the segment text + // This should not occur, since a FIN has been received from the remote side. Ignore the segment text. + + // 8. check FIN + if(in->isset(FIN)) { + process_fin(tcp, in); + // Remain in state + return OK; + } return OK; - } - return OK; } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /* - CLOSING + CLOSING */ ///////////////////////////////////////////////////////////////////// State::Result Connection::Closing::handle(Connection& tcp, TCP::Packet_ptr in) { - // 1. Check sequence number - if(! check_seq(tcp, in) ) { - return OK; - } - - // 2. check RST - if( in->isset(RST) ) { - return CLOSED; // close - } - - // 4. check SYN - if( in->isset(SYN) ) { - unallowed_syn_reset_connection(tcp, in); - return CLOSED; - } - - // 5. check ACK - if( ! check_ack(tcp, in)) { - return CLOSED; - } - /* - In addition to the processing for the ESTABLISHED state, if - the ACK acknowledges our FIN then enter the TIME-WAIT state, - otherwise ignore the segment. - */ - if(in->ack() == tcp.tcb().SND.NXT) { - // TODO: I guess or FIN is ACK'ed..? - tcp.set_state(TimeWait::instance()); - tcp.start_time_wait_timeout(); - } - - - // 7. proccess the segment text - // This should not occur, since a FIN has been received from the remote side. Ignore the segment text. - - // 8. check FIN - if(in->isset(FIN)) { - process_fin(tcp, in); - // Remain in state + // 1. Check sequence number + if(! check_seq(tcp, in) ) { + return OK; + } + + // 2. check RST + if( in->isset(RST) ) { + return CLOSED; // close + } + + // 4. check SYN + if( in->isset(SYN) ) { + unallowed_syn_reset_connection(tcp, in); + return CLOSED; + } + + // 5. check ACK + if( ! check_ack(tcp, in)) { + return CLOSED; + } + /* + In addition to the processing for the ESTABLISHED state, if + the ACK acknowledges our FIN then enter the TIME-WAIT state, + otherwise ignore the segment. + */ + if(in->ack() == tcp.tcb().SND.NXT) { + // TODO: I guess or FIN is ACK'ed..? + tcp.set_state(TimeWait::instance()); + tcp.start_time_wait_timeout(); + } + + + // 7. proccess the segment text + // This should not occur, since a FIN has been received from the remote side. Ignore the segment text. + + // 8. check FIN + if(in->isset(FIN)) { + process_fin(tcp, in); + // Remain in state + return OK; + } return OK; - } - return OK; } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /* - LAST-ACK + LAST-ACK */ ///////////////////////////////////////////////////////////////////// State::Result Connection::LastAck::handle(Connection& tcp, TCP::Packet_ptr in) { - // 1. Check sequence number - if(! check_seq(tcp, in) ) { - return OK; - } - - // 2. check RST - if( in->isset(RST) ) { - return CLOSED; // close - } - - // 4. check SYN - if( in->isset(SYN) ) { - unallowed_syn_reset_connection(tcp, in); - return CLOSED; - } - - if( ! check_ack(tcp, in)) { - return CLOSED; - } - - // 7. proccess the segment text - // This should not occur, since a FIN has been received from the remote side. Ignore the segment text. - - // 8. check FIN - if(in->isset(FIN)) { - process_fin(tcp, in); - // Remain in state + // 1. Check sequence number + if(! check_seq(tcp, in) ) { + return OK; + } + + // 2. check RST + if( in->isset(RST) ) { + return CLOSED; // close + } + + // 4. check SYN + if( in->isset(SYN) ) { + unallowed_syn_reset_connection(tcp, in); + return CLOSED; + } + + if( ! check_ack(tcp, in)) { + return CLOSED; + } + + // 7. proccess the segment text + // This should not occur, since a FIN has been received from the remote side. Ignore the segment text. + + // 8. check FIN + if(in->isset(FIN)) { + process_fin(tcp, in); + // Remain in state + return OK; + } return OK; - } - return OK; } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /* - TIME-WAIT + TIME-WAIT */ ///////////////////////////////////////////////////////////////////// State::Result Connection::TimeWait::handle(Connection& tcp, TCP::Packet_ptr in) { - // 1. Check sequence number - if(! check_seq(tcp, in) ) { - return OK; - } - - // 2. check RST - if( in->isset(RST) ) { - return CLOSED; // close - } - - // 4. check SYN - if( in->isset(SYN) ) { - unallowed_syn_reset_connection(tcp, in); - return CLOSED; - } - - // 7. proccess the segment text - // This should not occur, since a FIN has been received from the remote side. Ignore the segment text. - - // 8. check FIN - if(in->isset(FIN)) { - process_fin(tcp, in); - // Remain in state - tcp.start_time_wait_timeout(); + // 1. Check sequence number + if(! check_seq(tcp, in) ) { + return OK; + } + + // 2. check RST + if( in->isset(RST) ) { + return CLOSED; // close + } + + // 4. check SYN + if( in->isset(SYN) ) { + unallowed_syn_reset_connection(tcp, in); + return CLOSED; + } + + // 7. proccess the segment text + // This should not occur, since a FIN has been received from the remote side. Ignore the segment text. + + // 8. check FIN + if(in->isset(FIN)) { + process_fin(tcp, in); + // Remain in state + tcp.start_time_wait_timeout(); + return OK; + } return OK; - } - return OK; } ///////////////////////////////////////////////////////////////////// diff --git a/src/virtio/block.cpp b/src/virtio/block.cpp index 6c42fff3b7..534d1665bd 100644 --- a/src/virtio/block.cpp +++ b/src/virtio/block.cpp @@ -29,41 +29,41 @@ #define FEAT(x) (1 << x) VirtioBlk::VirtioBlk(hw::PCI_Device& d) -: Virtio(d), - req(queue_size(0), 0, iobase()), - request_counter(0) + : Virtio(d), + req(queue_size(0), 0, iobase()), + request_counter(0) { INFO("VirtioBlk", "Driver initializing"); uint32_t needed_features = - FEAT(VIRTIO_BLK_F_BLK_SIZE); + FEAT(VIRTIO_BLK_F_BLK_SIZE); negotiate_features(needed_features); CHECK(features() & FEAT(VIRTIO_BLK_F_BARRIER), - "Barrier is enabled"); + "Barrier is enabled"); CHECK(features() & FEAT(VIRTIO_BLK_F_SIZE_MAX), - "Size-max is known"); + "Size-max is known"); CHECK(features() & FEAT(VIRTIO_BLK_F_SEG_MAX), - "Seg-max is known"); + "Seg-max is known"); CHECK(features() & FEAT(VIRTIO_BLK_F_GEOMETRY), - "Geometry structure is used"); + "Geometry structure is used"); CHECK(features() & FEAT(VIRTIO_BLK_F_RO), - "Device is read-only"); + "Device is read-only"); CHECK(features() & FEAT(VIRTIO_BLK_F_BLK_SIZE), - "Block-size is known"); + "Block-size is known"); CHECK(features() & FEAT(VIRTIO_BLK_F_SCSI), - "SCSI is enabled :("); + "SCSI is enabled :("); CHECK(features() & FEAT(VIRTIO_BLK_F_FLUSH), - "Flush enabled"); + "Flush enabled"); CHECK ((features() & needed_features) == needed_features, - "Negotiated needed features"); + "Negotiated needed features"); // Step 1 - Initialize REQ queue auto success = assign_queue(0, (uint32_t) req.queue_desc()); CHECK(success, "Request queue assigned (0x%x) to device", - (uint32_t) req.queue_desc()); + (uint32_t) req.queue_desc()); // Step 3 - Fill receive queue with buffers // DEBUG: Disable @@ -84,7 +84,7 @@ VirtioBlk::VirtioBlk(hw::PCI_Device& d) // Done INFO("VirtioBlk", "Block device with %llu sectors capacity", - config.capacity); + config.capacity); //CHECK(config.status == VIRTIO_BLK_S_OK, "Link up\n"); req.kick(); } @@ -105,21 +105,21 @@ void VirtioBlk::irq_handler() // Step 2. A) - one of the queues have changed if (isr & 1) - { - // This now means service RX & TX interchangeably - service_RX(); - } + { + // This now means service RX & TX interchangeably + service_RX(); + } // Step 2. B) if (isr & 2) - { - debug("\t Configuration change:\n"); + { + debug("\t Configuration change:\n"); - // Getting the MAC + status - //debug("\t Old status: 0x%x\n", config.status); - get_config(); - //debug("\t New status: 0x%x \n", config.status); - } + // Getting the MAC + status + //debug("\t Old status: 0x%x\n", config.status); + get_config(); + //debug("\t New status: 0x%x \n", config.status); + } IRQ_manager::eoi(irq()); } @@ -134,28 +134,28 @@ void VirtioBlk::service_RX() //printf("service_RX() reading from VirtioBlk device\n"); while ((hdr = (request_t*) req.dequeue(len)) != nullptr) - { - printf("service_RX() received %u bytes for sector %llu\n", - len, hdr->hdr.sector); - vbr = &hdr->data; + { + printf("service_RX() received %u bytes for sector %llu\n", + len, hdr->hdr.sector); + vbr = &hdr->data; - printf("service_RX() received %u bytes data response\n", len); - printf("Received handler: %p\n", vbr->handler); + printf("service_RX() received %u bytes data response\n", len); + printf("Received handler: %p\n", vbr->handler); - uint8_t* copy = new uint8_t[SECTOR_SIZE]; - memcpy(copy, vbr->sector, SECTOR_SIZE); - auto buf = buffer_t(copy, std::default_delete()); + uint8_t* copy = new uint8_t[SECTOR_SIZE]; + memcpy(copy, vbr->sector, SECTOR_SIZE); + auto buf = buffer_t(copy, std::default_delete()); - printf("Calling handler: %p\n", vbr->handler); - (*vbr->handler)(buf); - delete vbr->handler; + printf("Calling handler: %p\n", vbr->handler); + (*vbr->handler)(buf); + delete vbr->handler; - received++; - } + received++; + } if (received == 0) - { - //printf("service_RX() error processing requests\n"); - } + { + //printf("service_RX() error processing requests\n"); + } req.enable_interrupts(); } diff --git a/src/virtio/console.cpp b/src/virtio/console.cpp index 1d73459d21..480ec1bf54 100644 --- a/src/virtio/console.cpp +++ b/src/virtio/console.cpp @@ -26,58 +26,58 @@ extern "C" #define FEAT(x) (1 << x) VirtioCon::VirtioCon(hw::PCI_Device& d) -: Virtio(d), - rx(queue_size(0), 0, iobase()), - tx(queue_size(1), 1, iobase()), - ctl_rx(queue_size(2), 2, iobase()), - ctl_tx(queue_size(3), 3, iobase()) + : Virtio(d), + rx(queue_size(0), 0, iobase()), + tx(queue_size(1), 1, iobase()), + ctl_rx(queue_size(2), 2, iobase()), + ctl_tx(queue_size(3), 3, iobase()) { INFO("VirtioCon", "Driver initializing"); uint32_t needed_features = - FEAT(VIRTIO_CONSOLE_F_MULTIPORT); + FEAT(VIRTIO_CONSOLE_F_MULTIPORT); negotiate_features(needed_features); CHECK(features() & FEAT(VIRTIO_CONSOLE_F_SIZE), - "Valid console dimensions"); + "Valid console dimensions"); CHECK(features() & FEAT(VIRTIO_CONSOLE_F_MULTIPORT), - "Multiple ports support"); + "Multiple ports support"); CHECK(features() & FEAT(VIRTIO_CONSOLE_F_EMERG_WRITE), - "Emergency write support"); + "Emergency write support"); CHECK ((features() & needed_features) == needed_features, - "Negotiated needed features"); + "Negotiated needed features"); // Step 1 - Initialize queues auto success = assign_queue(0, (uint32_t) rx.queue_desc()); CHECK(success, "Receive queue assigned (0x%x) to device", - (uint32_t) rx.queue_desc()); + (uint32_t) rx.queue_desc()); success = assign_queue(1, (uint32_t) tx.queue_desc()); CHECK(success, "Transmit queue assigned (0x%x) to device", - (uint32_t) tx.queue_desc()); + (uint32_t) tx.queue_desc()); success = assign_queue(2, (uint32_t) ctl_rx.queue_desc()); CHECK(success, "Control rx queue assigned (0x%x) to device", - (uint32_t) ctl_rx.queue_desc()); + (uint32_t) ctl_rx.queue_desc()); success = assign_queue(3, (uint32_t) ctl_tx.queue_desc()); CHECK(success, "Control tx queue assigned (0x%x) to device", - (uint32_t) ctl_tx.queue_desc()); + (uint32_t) ctl_tx.queue_desc()); /* - success = assign_queue(4, (uint32_t) rx1.queue_desc()); - CHECK(success, "rx1 queue assigned (0x%x) to device", + success = assign_queue(4, (uint32_t) rx1.queue_desc()); + CHECK(success, "rx1 queue assigned (0x%x) to device", (uint32_t) rx1.queue_desc()); - success = assign_queue(5, (uint32_t) tx1.queue_desc()); - CHECK(success, "tx1 queue assigned (0x%x) to device", + success = assign_queue(5, (uint32_t) tx1.queue_desc()); + CHECK(success, "tx1 queue assigned (0x%x) to device", (uint32_t) tx1.queue_desc()); */ // Step 3 - Fill receive queue with buffers INFO("VirtioCon", "Queue size rx: %d tx: %d\n", - rx.size(), tx.size()); + rx.size(), tx.size()); // Get device configuration get_config(); @@ -93,7 +93,7 @@ VirtioCon::VirtioCon(hw::PCI_Device& d) // Done INFO("VirtioCon", "Console with size (%u, %u), %u ports", - config.cols, config.rows, config.max_nr_ports); + config.cols, config.rows, config.max_nr_ports); rx.kick(); } @@ -113,20 +113,20 @@ void VirtioCon::irq_handler() // Step 2. A) - one of the queues have changed if (isr & 1) - { - // This now means service RX & TX interchangeably - service_RX(); - } + { + // This now means service RX & TX interchangeably + service_RX(); + } // Step 2. B) if (isr & 2) - { - debug("\t Configuration change:\n"); + { + debug("\t Configuration change:\n"); - //debug("\t Old status: 0x%x\n", config.status); - get_config(); - //debug("\t New status: 0x%x \n", config.status); - } + //debug("\t Old status: 0x%x\n", config.status); + get_config(); + //debug("\t New status: 0x%x \n", config.status); + } IRQ_manager::eoi(irq()); } @@ -135,32 +135,32 @@ void VirtioCon::service_RX() rx.disable_interrupts(); while (rx.new_incoming()) - { - uint32_t len = 0; - char* condata = (char*) rx.dequeue(&len); + { + uint32_t len = 0; + char* condata = (char*) rx.dequeue(&len); - uint32_t dontcare; - rx.dequeue(&dontcare); + uint32_t dontcare; + rx.dequeue(&dontcare); - if (condata) - { - //printf("service_RX() received %u bytes from virtio console\n", len); - //printf("Data: %s\n", condata); - //vbr->handler(0, vbr->sector); - } - else - { - // acknowledgement - //printf("No data, just len = %d\n", len); - } + if (condata) + { + //printf("service_RX() received %u bytes from virtio console\n", len); + //printf("Data: %s\n", condata); + //vbr->handler(0, vbr->sector); + } + else + { + // acknowledgement + //printf("No data, just len = %d\n", len); } + } rx.enable_interrupts(); } void VirtioCon::write ( - const void* data, - size_t len) + const void* data, + size_t len) { char* heapdata = new char[len]; memcpy(heapdata, data, len); diff --git a/src/virtio/virtio.cpp b/src/virtio/virtio.cpp index db78c0e026..50cbe5c438 100644 --- a/src/virtio/virtio.cpp +++ b/src/virtio/virtio.cpp @@ -85,9 +85,9 @@ Virtio::Virtio(hw::PCI_Device& dev) // 3. Set DRIVER status bit hw::outp(_iobase + VIRTIO_PCI_STATUS, - hw::inp(_iobase + VIRTIO_PCI_STATUS) | - VIRTIO_CONFIG_S_ACKNOWLEDGE | - VIRTIO_CONFIG_S_DRIVER); + hw::inp(_iobase + VIRTIO_PCI_STATUS) | + VIRTIO_CONFIG_S_ACKNOWLEDGE | + VIRTIO_CONFIG_S_DRIVER); // THE REMAINING STEPS MUST BE DONE IN A SUBCLASS @@ -119,8 +119,8 @@ Virtio::Virtio(hw::PCI_Device& dev) // uint32_t queue_size = hw::inpd(_iobase + 0x0C); /* printf(queue_size > 0 and queue_size != PCI_WTF ? - "\t [x] Queue Size : 0x%lx \n" : - "\t [ ] No qeuue Size? : 0x%lx \n" ,queue_size); */ + "\t [x] Queue Size : 0x%lx \n" : + "\t [ ] No qeuue Size? : 0x%lx \n" ,queue_size); */ } @@ -200,13 +200,13 @@ void Virtio::enable_irq_handler(){ } /** void Virtio::enable_irq_handler(IRQ_manager::irq_delegate d){ - //_irq=0; //Works only if IRQ2INTR(_irq), since 0 overlaps an exception. - //IRQ_manager::set_handler(IRQ2INTR(_irq), irq_virtio_entry); + //_irq=0; //Works only if IRQ2INTR(_irq), since 0 overlaps an exception. + //IRQ_manager::set_handler(IRQ2INTR(_irq), irq_virtio_entry); - IRQ_manager::subscribe(_irq,d); + IRQ_manager::subscribe(_irq,d); - IRQ_manager::enable_irq(_irq); - }*/ + IRQ_manager::enable_irq(_irq); + }*/ diff --git a/src/virtio/virtionet.cpp b/src/virtio/virtionet.cpp index d957d94a62..c21b35decf 100644 --- a/src/virtio/virtionet.cpp +++ b/src/virtio/virtionet.cpp @@ -300,9 +300,9 @@ void VirtioNet::service_queues(){ void VirtioNet::add_to_tx_buffer(net::Packet_ptr pckt){ if (transmit_queue_) - transmit_queue_->chain(pckt); - else - transmit_queue_ = pckt; + transmit_queue_->chain(pckt); + else + transmit_queue_ = pckt; #ifdef DEBUG size_t chain_length = 1; diff --git a/test/IDE/service.cpp b/test/IDE/service.cpp index 8d184015d5..e607b2acb8 100644 --- a/test/IDE/service.cpp +++ b/test/IDE/service.cpp @@ -36,12 +36,12 @@ void Service::start() printf("MAGIC sig: 0x%x\n\n", mbr->magic); ide.read(0, 3, [] (hw::IDE::buffer_t data) { - static int i = 0; - uint8_t* buf = (uint8_t*)data.get(); - printf("Async read, Block %d:\n", i); - for (int i = 0; i < 512; i++) - printf("%x ", buf[i]); - printf("\n"); - i++; - }); + static int i = 0; + uint8_t* buf = (uint8_t*)data.get(); + printf("Async read, Block %d:\n", i); + for (int i = 0; i < 512; i++) + printf("%x ", buf[i]); + printf("\n"); + i++; + }); } diff --git a/test/IRQ_PIC/service.cpp b/test/IRQ_PIC/service.cpp index a0b33a05b2..47740ca8b8 100644 --- a/test/IRQ_PIC/service.cpp +++ b/test/IRQ_PIC/service.cpp @@ -35,7 +35,7 @@ std::unique_ptr > inet; We're going to use the network- and keyboard interrupts for now, using UDP to trigger the NIC irq. -**/ + **/ void Service::start() { @@ -111,10 +111,10 @@ void Service::start() /** - A custom IRQ-handler for the serial port - It doesn't send eoi, but it should work anyway - since we're using auto-EOI-mode for IRQ < 8 (master) - */ + A custom IRQ-handler for the serial port + It doesn't send eoi, but it should work anyway + since we're using auto-EOI-mode for IRQ < 8 (master) + */ IRQ_manager::subscribe(4, [](){ uint16_t serial_port1 = 0x3F8; //IRQ_manager::eoi(4); @@ -127,11 +127,11 @@ void Service::start() /* - IRQ_manager::subscribe(11,[](){ - // Calling eoi here will turn the IRQ line on and loop forever. - IRQ_manager::eoi(11); - INFO("IRQ","Network IRQ\n"); - });*/ + IRQ_manager::subscribe(11,[](){ + // Calling eoi here will turn the IRQ line on and loop forever. + IRQ_manager::eoi(11); + INFO("IRQ","Network IRQ\n"); + });*/ // Enabling a timer causes freeze in debug mode, for some reason diff --git a/test/STL/service.cpp b/test/STL/service.cpp index d08d5b3c3f..b64d21b0cd 100644 --- a/test/STL/service.cpp +++ b/test/STL/service.cpp @@ -19,7 +19,7 @@ A very superficial test to verify that basic STL is working This is useful when we mess with / replace STL implementations -**/ + **/ #include @@ -41,60 +41,60 @@ int clock_gettime(clockid_t clk_id, struct timespec *tp){ using namespace std; const lest::test specification[] = +{ { + SCENARIO( "vectors can be sized and resized" "[vector]" ) { - SCENARIO( "vectors can be sized and resized" "[vector]" ) - { - - GIVEN( "A vector with some items" ) { - std::vector v( 5 ); - - EXPECT( v.size() == 5u ); - EXPECT( v.capacity() >= 5u ); - - WHEN( "the size is increased" ) { - v.resize( 10 ); - - THEN( "the size and capacity change" ) { - EXPECT( v.size() == 10u); - EXPECT( v.capacity() >= 10u ); - } - } - WHEN( "the size is reduced" ) { - v.resize( 0 ); - - THEN( "the size changes but not capacity" ) { - EXPECT( v.size() == 0u ); - EXPECT( v.capacity() >= 5u ); - } - } - WHEN( "more capacity is reserved" ) { - v.reserve( 10 ); - - THEN( "the capacity changes but not the size" ) { - EXPECT( v.size() == 5u ); - EXPECT( v.capacity() >= 10u ); - } - WHEN( "less capacity is reserved again" ) { - v.reserve( 7 ); - - THEN( "capacity remains unchanged" ) { - EXPECT( v.capacity() >= 10u ); - } - } - } - WHEN( "less capacity is reserved" ) { - v.reserve( 0 ); - - THEN( "neither size nor capacity are changed" ) { - EXPECT( v.size() == 5u ); - EXPECT( v.capacity() >= 5u ); - } - } - } + + GIVEN( "A vector with some items" ) { + std::vector v( 5 ); + + EXPECT( v.size() == 5u ); + EXPECT( v.capacity() >= 5u ); + + WHEN( "the size is increased" ) { + v.resize( 10 ); + + THEN( "the size and capacity change" ) { + EXPECT( v.size() == 10u); + EXPECT( v.capacity() >= 10u ); + } + } + WHEN( "the size is reduced" ) { + v.resize( 0 ); + + THEN( "the size changes but not capacity" ) { + EXPECT( v.size() == 0u ); + EXPECT( v.capacity() >= 5u ); + } + } + WHEN( "more capacity is reserved" ) { + v.reserve( 10 ); + + THEN( "the capacity changes but not the size" ) { + EXPECT( v.size() == 5u ); + EXPECT( v.capacity() >= 10u ); + } + WHEN( "less capacity is reserved again" ) { + v.reserve( 7 ); + + THEN( "capacity remains unchanged" ) { + EXPECT( v.capacity() >= 10u ); + } + } + } + WHEN( "less capacity is reserved" ) { + v.reserve( 0 ); + + THEN( "neither size nor capacity are changed" ) { + EXPECT( v.size() == 5u ); + EXPECT( v.capacity() >= 5u ); + } + } } } - }; + } +}; #define MYINFO(X,...) INFO("Test STL",X,##__VA_ARGS__) diff --git a/test/bufstore/service.cpp b/test/bufstore/service.cpp index 2643e76d7a..272875e72f 100644 --- a/test/bufstore/service.cpp +++ b/test/bufstore/service.cpp @@ -64,7 +64,7 @@ void Service::start() // Reinitialize the first packet packet = std::make_shared(bufstore_.get_offset_buffer(), - bufstore_.offset_bufsize(), 1500, release); + bufstore_.offset_bufsize(), 1500, release); CHECKSERT(bufstore_.buffers_available() == bufcount_ - 1, "Bufcount is now %i", bufcount_ -1); @@ -84,8 +84,8 @@ void Service::start() while(tail && i < bufcount_ - 1 ) { tail = tail->detach_tail(); CHECKSERT(bufstore_.buffers_available() == i, - "Bufcount is now %i == %i", i, - bufstore_.buffers_available()); + "Bufcount is now %i == %i", i, + bufstore_.buffers_available()); i++; } diff --git a/test/fat/fat16.cpp b/test/fat/fat16.cpp index cd5b386a04..a912a85432 100644 --- a/test/fat/fat16.cpp +++ b/test/fat/fat16.cpp @@ -37,48 +37,48 @@ void Service::start() // auto-mount filesystem disk->mount( - [disk] (fs::error_t err) - { - CHECK(!err, "Filesystem auto-mounted"); - assert(!err); + [disk] (fs::error_t err) + { + CHECK(!err, "Filesystem auto-mounted"); + assert(!err); - auto& fs = disk->fs(); - printf("\t\t%s filesystem\n", fs.name().c_str()); + auto& fs = disk->fs(); + printf("\t\t%s filesystem\n", fs.name().c_str()); - auto vec = fs::new_shared_vector(); - err = fs.ls("/", vec); - CHECK(!err, "List root directory"); - assert(!err); + auto vec = fs::new_shared_vector(); + err = fs.ls("/", vec); + CHECK(!err, "List root directory"); + assert(!err); - CHECK(vec->size() == 1, "Exactly one ent in root dir"); - assert(vec->size() == 1); + CHECK(vec->size() == 1, "Exactly one ent in root dir"); + assert(vec->size() == 1); - auto& e = vec->at(0); - CHECK(e.is_file(), "Ent is a file"); - CHECK(e.name() == "banana.txt", "Ent is 'banana.txt'"); + auto& e = vec->at(0); + CHECK(e.is_file(), "Ent is a file"); + CHECK(e.name() == "banana.txt", "Ent is 'banana.txt'"); - }); + }); // re-mount on VBR1 disk->mount(disk->VBR1, - [disk] (fs::error_t err) - { - CHECK(!err, "Filesystem mounted on VBR1"); - assert(!err); + [disk] (fs::error_t err) + { + CHECK(!err, "Filesystem mounted on VBR1"); + assert(!err); - // verify that we can read file - auto& fs = disk->fs(); - auto ent = fs.stat("/banana.txt"); - CHECK(ent.is_valid(), "Stat file in root dir"); - CHECK(ent.is_file(), "Entity is file"); - CHECK(!ent.is_dir(), "Entity is not directory"); - CHECK(ent.name() == "banana.txt", "Name is 'banana.txt'"); + // verify that we can read file + auto& fs = disk->fs(); + auto ent = fs.stat("/banana.txt"); + CHECK(ent.is_valid(), "Stat file in root dir"); + CHECK(ent.is_file(), "Entity is file"); + CHECK(!ent.is_dir(), "Entity is not directory"); + CHECK(ent.name() == "banana.txt", "Name is 'banana.txt'"); - // try reading banana-file - auto buf = fs.read(ent, 0, ent.size); - std::string banana((char*) buf.buffer.get(), buf.len); + // try reading banana-file + auto buf = fs.read(ent, 0, ent.size); + std::string banana((char*) buf.buffer.get(), buf.len); - std::string internal_banana = - R"( ____ ___ + std::string internal_banana = + R"( ____ ___ | _ \ ___ _ _.' _ `. _ | [_) )' _ `._ _ ___ ! \ | | (_) | _ |:;.| _ <| (_) | \ | |' _ `| \| | _ | .:;| @@ -87,11 +87,11 @@ void Service::start() !::, `-!_| | | |\ | | | | | \ !_!.' ':;! !::; ":;:!.!.\_!_!_!.!-'-':;:'' '''! ';:' `::;::;' '' ., . - `: .,. `' .::... . .::;::;' - `..:;::;:.. ::;::;:;:;, :;::;' + `: .,. `' .::... . .::;::;' + `..:;::;:.. ::;::;:;:;, :;::;' "-:;::;:;: ':;::;:'' ;.-' ""`---...________...---'"" - )"; +)"; printf("%s\n", internal_banana.c_str()); CHECK(banana == internal_banana, "Correct banana #1"); diff --git a/test/fat/fat32.cpp b/test/fat/fat32.cpp index bceb0eac6a..972652e3bf 100644 --- a/test/fat/fat32.cpp +++ b/test/fat/fat32.cpp @@ -24,7 +24,7 @@ std::shared_ptr disk; std::string internal_banana = - R"( ____ ___ + R"( ____ ___ | _ \ ___ _ _.' _ `. _ | [_) )' _ `._ _ ___ ! \ | | (_) | _ |:;.| _ <| (_) | \ | |' _ `| \| | _ | .:;| @@ -33,11 +33,11 @@ std::string internal_banana = !::, `-!_| | | |\ | | | | | \ !_!.' ':;! !::; ":;:!.!.\_!_!_!.!-'-':;:'' '''! ';:' `::;::;' '' ., . - `: .,. `' .::... . .::;::;' - `..:;::;:.. ::;::;:;:;, :;::;' + `: .,. `' .::... . .::;::;' + `..:;::;:.. ::;::;:;:;, :;::;' "-:;::;:;: ':;::;:'' ;.-' ""`---...________...---'"" - )"; +)"; void Service::start() { diff --git a/test/memdisk/bigdisk.cpp b/test/memdisk/bigdisk.cpp index 3d76c9f528..d04b021d5e 100644 --- a/test/memdisk/bigdisk.cpp +++ b/test/memdisk/bigdisk.cpp @@ -38,9 +38,9 @@ void Service::start() // verify nothing bad happened CHECK(!!(buf), "Buffer for sector 0 is valid"); if (!buf) - { - panic("Failed to read sector 0 on memdisk device\n"); - } + { + panic("Failed to read sector 0 on memdisk device\n"); + } // verify MBR has signature const uint8_t* mbr = buf.get(); assert(mbr[0x1FE] == 0x55); diff --git a/test/memdisk/twosector.cpp b/test/memdisk/twosector.cpp index 1c2694f9c2..a0e3357bb4 100644 --- a/test/memdisk/twosector.cpp +++ b/test/memdisk/twosector.cpp @@ -38,9 +38,9 @@ void Service::start() // verify nothing bad happened CHECK(!!(buf), "Buffer for sector 0 is valid"); if (!buf) - { - panic("Failed to read sector 0 on memdisk device\n"); - } + { + panic("Failed to read sector 0 on memdisk device\n"); + } // convert to text std::string text((const char*) buf.get(), disk->dev().block_size()); // verify that the sector contents matches the test string @@ -53,7 +53,7 @@ void Service::start() // verify that reading outside of disk returns a 0x0 pointer buf = disk->dev().read_sync(disk->dev().size()); CHECK(!buf, "Buffer outside of disk range (sector=%llu) is 0x0", - disk->dev().size()); + disk->dev().size()); assert(!buf); INFO("MemDisk", "SUCCESS"); diff --git a/test/tcp/service.cpp b/test/tcp/service.cpp index d15d78232c..4ac4564be8 100644 --- a/test/tcp/service.cpp +++ b/test/tcp/service.cpp @@ -29,23 +29,23 @@ std::unique_ptr> inet; std::shared_ptr client; /* - TEST VARIABLES + TEST VARIABLES */ TCP::Port -TEST1{8081}, TEST2{8082}, TEST3{8083}, TEST4{8084}, TEST5{8085}; + TEST1{8081}, TEST2{8082}, TEST3{8083}, TEST4{8084}, TEST5{8085}; using HostAddress = std::pair; HostAddress -TEST_ADDR_TIME{"india.colorado.edu", 13}; + TEST_ADDR_TIME{"india.colorado.edu", 13}; std::string -small, big, huge; + small, big, huge; int -S{150}, B{1500}, H{15000}; + S{150}, B{1500}, H{15000}; std::string -TEST_STR {"1337"}; + TEST_STR {"1337"}; size_t bufstore_capacity{0}; @@ -54,83 +54,83 @@ size_t bufstore_capacity{0}; milliseconds MSL_TEST = 5s; /* - TEST: Release of resources/clean up. + TEST: Release of resources/clean up. */ void FINISH_TEST() { - INFO("TEST", "Started 3 x MSL timeout."); - hw::PIT::instance().onTimeout(3 * MSL_TEST, [] { - INFO("TEST", "Verify release of resources"); - CHECK(inet->tcp().activeConnections() == 0, "tcp.activeConnections() == 0"); - CHECK(inet->available_capacity() == bufstore_capacity, - "inet.available_capacity() == bufstore_capacity"); - printf("# TEST DONE #\n"); - }); + INFO("TEST", "Started 3 x MSL timeout."); + hw::PIT::instance().onTimeout(3 * MSL_TEST, [] { + INFO("TEST", "Verify release of resources"); + CHECK(inet->tcp().activeConnections() == 0, "tcp.activeConnections() == 0"); + CHECK(inet->available_capacity() == bufstore_capacity, + "inet.available_capacity() == bufstore_capacity"); + printf("# TEST DONE #\n"); + }); } /* - TEST: Outgoing Internet Connection + TEST: Outgoing Internet Connection */ void OUTGOING_TEST_INTERNET(const HostAddress& address) { - auto port = address.second; - INFO("TEST", "Outgoing Internet Connection (%s:%u)", address.first.c_str(), address.second); - inet->resolve(address.first, [port](auto&, auto&, auto ip_address) { - CHECK(ip_address != 0, "Resolved host"); + auto port = address.second; + INFO("TEST", "Outgoing Internet Connection (%s:%u)", address.first.c_str(), address.second); + inet->resolve(address.first, [port](auto&, auto&, auto ip_address) { + CHECK(ip_address != 0, "Resolved host"); - if(ip_address != 0) { - inet->tcp().connect(ip_address, port) - ->onConnect([](Connection_ptr) { - CHECK(true, "Connected"); - }) - .onReceive([](Connection_ptr conn, bool) { - CHECK(true, "Received data: %s", conn->read().c_str()); - }) - .onError([](Connection_ptr, TCP::TCPException err) { - CHECK(false, "Error occured: %s", err.what()); - }); - } - }); + if(ip_address != 0) { + inet->tcp().connect(ip_address, port) + ->onConnect([](Connection_ptr) { + CHECK(true, "Connected"); + }) + .onReceive([](Connection_ptr conn, bool) { + CHECK(true, "Received data: %s", conn->read().c_str()); + }) + .onError([](Connection_ptr, TCP::TCPException err) { + CHECK(false, "Error occured: %s", err.what()); + }); + } + }); } /* - TEST: Outgoing Connection to Host + TEST: Outgoing Connection to Host */ void OUTGOING_TEST(TCP::Socket outgoing) { - INFO("TEST", "Outgoing Connection (%s)", outgoing.to_string().c_str()); - inet->tcp().connect(outgoing) - ->onConnect([](Connection_ptr conn) { - conn->write(small); - }) - .onReceive([](Connection_ptr conn, bool) { - CHECK(conn->read() == small, "conn->read() == small"); - }) - .onDisconnect([](Connection_ptr, TCP::Connection::Disconnect) { - CHECK(true, "Connection closed by server"); + INFO("TEST", "Outgoing Connection (%s)", outgoing.to_string().c_str()); + inet->tcp().connect(outgoing) + ->onConnect([](Connection_ptr conn) { + conn->write(small); + }) + .onReceive([](Connection_ptr conn, bool) { + CHECK(conn->read() == small, "conn->read() == small"); + }) + .onDisconnect([](Connection_ptr, TCP::Connection::Disconnect) { + CHECK(true, "Connection closed by server"); - OUTGOING_TEST_INTERNET(TEST_ADDR_TIME); - }); + OUTGOING_TEST_INTERNET(TEST_ADDR_TIME); + }); } // Used to send big data struct Buffer { - size_t written, read; - char* data; - const size_t size; + size_t written, read; + char* data; + const size_t size; - Buffer(size_t length) : - written(0), read(0), data(new char[length]), size(length) {} + Buffer(size_t length) : + written(0), read(0), data(new char[length]), size(length) {} - ~Buffer() { delete[] data; } + ~Buffer() { delete[] data; } - std::string str() { return {data, size};} + std::string str() { return {data, size};} }; void Service::start() { - for(int i = 0; i < S; i++) small += TEST_STR; - for(int i = 0; i < B; i++) big += TEST_STR; - for(int i = 0; i < H; i++) huge += TEST_STR; + for(int i = 0; i < S; i++) small += TEST_STR; + for(int i = 0; i < B; i++) big += TEST_STR; + for(int i = 0; i < H; i++) huge += TEST_STR; - hw::Nic& eth0 = hw::Dev::eth<0,VirtioNet>(); + hw::Nic& eth0 = hw::Dev::eth<0,VirtioNet>(); inet = std::make_unique>(eth0); inet->network_config( {{ 10,0,0,42 }}, // IP @@ -138,113 +138,113 @@ void Service::start() {{ 10,0,0,1 }}, // Gateway {{ 8,8,8,8 }} ); // DNS - bufstore_capacity = inet->available_capacity(); - auto& tcp = inet->tcp(); - // this is default - tcp.set_buffer_limit(10); - // reduce test duration - tcp.set_MSL(MSL_TEST); + bufstore_capacity = inet->available_capacity(); + auto& tcp = inet->tcp(); + // this is default + tcp.set_buffer_limit(10); + // reduce test duration + tcp.set_MSL(MSL_TEST); - /* - TEST: Send and receive small string. - */ - INFO("TEST", "Listeners and connections allocation."); - - /* - TEST: Nothing should be allocated. - */ - CHECK(tcp.openPorts() == 0, "tcp.openPorts() == 0"); - CHECK(tcp.activeConnections() == 0, "tcp.activeConnections() == 0"); + /* + TEST: Send and receive small string. + */ + INFO("TEST", "Listeners and connections allocation."); + + /* + TEST: Nothing should be allocated. + */ + CHECK(tcp.openPorts() == 0, "tcp.openPorts() == 0"); + CHECK(tcp.activeConnections() == 0, "tcp.activeConnections() == 0"); - tcp.bind(TEST1).onConnect([](Connection_ptr conn) { - INFO("TEST", "SMALL string (%u)", small.size()); - conn->onReceive([](Connection_ptr conn, bool) { - CHECK(conn->read() == small, "conn.read() == small"); - conn->close(); + tcp.bind(TEST1).onConnect([](Connection_ptr conn) { + INFO("TEST", "SMALL string (%u)", small.size()); + conn->onReceive([](Connection_ptr conn, bool) { + CHECK(conn->read() == small, "conn.read() == small"); + conn->close(); + }); + conn->write(small); }); - conn->write(small); - }); - /* - TEST: Server should be bound. - */ - CHECK(tcp.openPorts() == 1, "tcp.openPorts() == 1"); + /* + TEST: Server should be bound. + */ + CHECK(tcp.openPorts() == 1, "tcp.openPorts() == 1"); - /* - TEST: Send and receive big string. - */ - tcp.bind(TEST2).onConnect([](Connection_ptr conn) { - INFO("TEST", "BIG string (%u)", big.size()); - auto response = std::make_shared(); - conn->onReceive([response](Connection_ptr conn, bool) { - *response += conn->read(); - if(response->size() == big.size()) { - bool OK = (*response == big); - CHECK(OK, "conn.read() == big"); - conn->close(); - } + /* + TEST: Send and receive big string. + */ + tcp.bind(TEST2).onConnect([](Connection_ptr conn) { + INFO("TEST", "BIG string (%u)", big.size()); + auto response = std::make_shared(); + conn->onReceive([response](Connection_ptr conn, bool) { + *response += conn->read(); + if(response->size() == big.size()) { + bool OK = (*response == big); + CHECK(OK, "conn.read() == big"); + conn->close(); + } + }); + conn->write(big); }); - conn->write(big); - }); - - /* - TEST: Send and receive huge string. - */ - tcp.bind(TEST3).onConnect([](Connection_ptr conn) { - INFO("TEST", "HUGE string (%u)", huge.size()); - auto buffer = std::make_shared(huge.size()); - conn->onReceive([buffer](Connection_ptr conn, bool) { - // if not all expected data is read - if(buffer->read < huge.size()) - buffer->read += conn->read(buffer->data+buffer->read, conn->receive_buffer().data_size()); - // if not all expected data is written - if(buffer->written < huge.size()) { - buffer->written += conn->write(huge.data()+buffer->written, huge.size() - buffer->written); - } - // when all expected data is read - if(buffer->read == huge.size()) { - bool OK = (buffer->str() == huge); - CHECK(OK, "conn.read() == huge"); - conn->close(); - } + + /* + TEST: Send and receive huge string. + */ + tcp.bind(TEST3).onConnect([](Connection_ptr conn) { + INFO("TEST", "HUGE string (%u)", huge.size()); + auto buffer = std::make_shared(huge.size()); + conn->onReceive([buffer](Connection_ptr conn, bool) { + // if not all expected data is read + if(buffer->read < huge.size()) + buffer->read += conn->read(buffer->data+buffer->read, conn->receive_buffer().data_size()); + // if not all expected data is written + if(buffer->written < huge.size()) { + buffer->written += conn->write(huge.data()+buffer->written, huge.size() - buffer->written); + } + // when all expected data is read + if(buffer->read == huge.size()) { + bool OK = (buffer->str() == huge); + CHECK(OK, "conn.read() == huge"); + conn->close(); + } + }); + buffer->written += conn->write(huge.data(), huge.size()); }); - buffer->written += conn->write(huge.data(), huge.size()); - }); - - /* - TEST: More servers should be bound. - */ - CHECK(tcp.openPorts() == 3, "tcp.openPorts() == 3"); - - /* - TEST: Connection (Status etc.) and Active Close - */ - tcp.bind(TEST4).onConnect([](Connection_ptr conn) { - INFO("TEST","Connection"); - // There should be at least one connection. - CHECK(inet->tcp().activeConnections() > 0, "tcp.activeConnections() > 0"); - // Test if connected. - CHECK(conn->is_connected(), "conn.is_connected()"); - // Test if writable. - CHECK(conn->is_writable(), "conn.is_writable()"); - // Test if state is ESTABLISHED. - CHECK(conn->is_state({"ESTABLISHED"}), "conn.is_state(ESTABLISHED)"); - - INFO("TEST", "Active close"); - // Test for active close. - conn->close(); - CHECK(!conn->is_writable(), "!conn->is_writable()"); - CHECK(conn->is_state({"FIN-WAIT-1"}), "conn.is_state(FIN-WAIT-1)"); - }) - .onDisconnect([](Connection_ptr conn, TCP::Connection::Disconnect) { - CHECK(conn->is_state({"FIN-WAIT-2"}), "conn.is_state(FIN-WAIT-2)"); - hw::PIT::instance().onTimeout(1s,[conn]{ - CHECK(conn->is_state({"TIME-WAIT"}), "conn.is_state(TIME-WAIT)"); + + /* + TEST: More servers should be bound. + */ + CHECK(tcp.openPorts() == 3, "tcp.openPorts() == 3"); + + /* + TEST: Connection (Status etc.) and Active Close + */ + tcp.bind(TEST4).onConnect([](Connection_ptr conn) { + INFO("TEST","Connection"); + // There should be at least one connection. + CHECK(inet->tcp().activeConnections() > 0, "tcp.activeConnections() > 0"); + // Test if connected. + CHECK(conn->is_connected(), "conn.is_connected()"); + // Test if writable. + CHECK(conn->is_writable(), "conn.is_writable()"); + // Test if state is ESTABLISHED. + CHECK(conn->is_state({"ESTABLISHED"}), "conn.is_state(ESTABLISHED)"); + + INFO("TEST", "Active close"); + // Test for active close. + conn->close(); + CHECK(!conn->is_writable(), "!conn->is_writable()"); + CHECK(conn->is_state({"FIN-WAIT-1"}), "conn.is_state(FIN-WAIT-1)"); + }) + .onDisconnect([](Connection_ptr conn, TCP::Connection::Disconnect) { + CHECK(conn->is_state({"FIN-WAIT-2"}), "conn.is_state(FIN-WAIT-2)"); + hw::PIT::instance().onTimeout(1s,[conn]{ + CHECK(conn->is_state({"TIME-WAIT"}), "conn.is_state(TIME-WAIT)"); - OUTGOING_TEST({inet->router(), TEST5}); - }); + OUTGOING_TEST({inet->router(), TEST5}); + }); - hw::PIT::instance().onTimeout(5s, [] { FINISH_TEST(); }); - }); + hw::PIT::instance().onTimeout(5s, [] { FINISH_TEST(); }); + }); } diff --git a/test/term/term.cpp b/test/term/term.cpp index 88380528db..58fb7db560 100644 --- a/test/term/term.cpp +++ b/test/term/term.cpp @@ -33,10 +33,10 @@ void Service::start() hw::Nic& eth0 = hw::Dev::eth<0,VirtioNet>(); inet = std::make_unique >(eth0); inet->network_config( - {{ 10,0,0,42 }}, // IP - {{ 255,255,255,0 }}, // Netmask - {{ 10,0,0,1 }}, // Gateway - {{ 8,8,8,8 }} ); // DNS + {{ 10,0,0,42 }}, // IP + {{ 255,255,255,0 }}, // Netmask + {{ 10,0,0,1 }}, // Gateway + {{ 8,8,8,8 }} ); // DNS INFO("TERM", "Running tests for Terminal"); auto disk = fs::new_shared_memdisk(); @@ -44,24 +44,24 @@ void Service::start() // auto-mount filesystem disk->mount( - [disk] (fs::error_t err) - { - assert(!err); + [disk] (fs::error_t err) + { + assert(!err); - /// terminal /// -#define SERVICE_TELNET 23 - auto& tcp = inet->tcp(); - auto& server = tcp.bind(SERVICE_TELNET); - server.onConnect( - [disk] (auto client) - { - // create terminal with open TCP connection - term = std::make_unique (client); - term->add_disk_commands(disk); - }); + /// terminal /// + #define SERVICE_TELNET 23 + auto& tcp = inet->tcp(); + auto& server = tcp.bind(SERVICE_TELNET); + server.onConnect( + [disk] (auto client) + { + // create terminal with open TCP connection + term = std::make_unique (client); + term->add_disk_commands(disk); + }); - INFO("TERM", "Connect to terminal with $ telnet %s ", - inet->ip_addr().str().c_str()); - /// terminal /// - }); + INFO("TERM", "Connect to terminal with $ telnet %s ", + inet->ip_addr().str().c_str()); + /// terminal /// + }); } diff --git a/test/transmit/service.cpp b/test/transmit/service.cpp index 66c8dca086..9992ab4442 100644 --- a/test/transmit/service.cpp +++ b/test/transmit/service.cpp @@ -48,7 +48,7 @@ void Service::start() auto& sock = inet->udp().bind(port); sock.onRead([&] (UDP::Socket& conn, UDP::addr_t addr, UDP::port_t port, - const char* data, int len) -> int { + const char* data, int len) -> int { string received = std::string(data,len-1); INFO("Test 2","Starting UDP-test (got UDP data from %s: %i: '%s')", addr.str().c_str(), port, received.c_str()); diff --git a/test/vga/vga.cpp b/test/vga/vga.cpp index 6e61dffdac..5de0de44a7 100644 --- a/test/vga/vga.cpp +++ b/test/vga/vga.cpp @@ -67,22 +67,22 @@ void Service::start() auto test1_1 = [] () -> bool - { - if ( c >= '4') { - hw::PIT::instance().onRepeatedTimeout(100ms, [] { - vga.newline(); - iterations++; - if (iterations == 24) - write_goodbye(); + { + if ( c >= '4') { + hw::PIT::instance().onRepeatedTimeout(100ms, [] { + vga.newline(); + iterations++; + if (iterations == 24) + write_goodbye(); - }, + }, - [] { - return iterations < 36; - }); - } - return c < '4'; - }; + [] { + return iterations < 36; + }); + } + return c < '4'; + }; auto test2 = [](){ diff --git a/vmbuild/vmbuild.cpp b/vmbuild/vmbuild.cpp index 9e5fd7cb82..564c77549a 100644 --- a/vmbuild/vmbuild.cpp +++ b/vmbuild/vmbuild.cpp @@ -107,13 +107,13 @@ int main(int argc, char** argv) { // Bochs requires old-school disk specifications. // sectors=cyls*heads*spt (sectors per track) /* - const int spt = 63; - auto disk_tracks = - (img_size_sect % spt) == 0 ? - (img_size_sect / spt) : // Sector count is a multiple of 63 - (img_size_sect / spt) + 1; // There's a remainder, so we add one track + const int spt = 63; + auto disk_tracks = + (img_size_sect % spt) == 0 ? + (img_size_sect / spt) : // Sector count is a multiple of 63 + (img_size_sect / spt) + 1; // There's a remainder, so we add one track - const decltype(img_size_sect) disksize {disk_tracks * spt * SECT_SIZE}; + const decltype(img_size_sect) disksize {disk_tracks * spt * SECT_SIZE}; */ const auto disksize = (img_size_sect + extra_sectors) * SECT_SIZE; @@ -127,9 +127,9 @@ int main(int argc, char** argv) { } cout << "Creating disk of size: " - //<< "Cyls: " << cylinders << "\n" - //<< "Heads: " << heads << "\n" - //<< "Sec/Tr: " << spt << "\n" + //<< "Cyls: " << cylinders << "\n" + //<< "Heads: " << heads << "\n" + //<< "Sec/Tr: " << spt << "\n" << "=> " << (disksize / SECT_SIZE) << " sectors\n" << "=> " << disksize << " bytes\n"; @@ -154,7 +154,7 @@ int main(int argc, char** argv) { cout << "Signature: "; for(int i {0}; i < EI_NIDENT; ++i) { - cout << elf_header->e_ident[i]; + cout << elf_header->e_ident[i]; } cout << "\nType: " << ((elf_header->e_type == ET_EXEC) ? " ELF Executable\n" : "Non-executable\n"); From dc742749635697a00bc379c202cde8f583b41918 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sat, 2 Apr 2016 12:27:16 +0200 Subject: [PATCH 090/311] Editorconfig batch-script --- etc/batch_apply_editorconfig.sh | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 etc/batch_apply_editorconfig.sh diff --git a/etc/batch_apply_editorconfig.sh b/etc/batch_apply_editorconfig.sh new file mode 100644 index 0000000000..e0fa4ebdef --- /dev/null +++ b/etc/batch_apply_editorconfig.sh @@ -0,0 +1,9 @@ +#! /bin/bash + +SRC=$1 + +for file in `find $SRC \( -not -path "*/cxxabi/*" -not -path "*/STREAM/*" -not -path "*/lest/*" -not -path "*/mod/*" \) -type f \( -name *.cpp -or -name *.hpp -or -name *.inc \)` +do + echo -e "\n >> Formatting $file" + emacs $file -batch --eval '(indent-region (point-min) (point-max) nil)' -f save-buffer +done From 94a35d83fdbfd8d3c60754a2181d9d23a1847817 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sat, 2 Apr 2016 12:32:21 +0200 Subject: [PATCH 091/311] Editorconfig NUKE --- api/fs/common.hpp | 10 +- api/fs/disk.hpp | 124 +- api/fs/ext4.hpp | 20 +- api/fs/fat.hpp | 20 +- api/fs/filesystem.hpp | 168 +- api/fs/mbr.hpp | 84 +- api/fs/memdisk.hpp | 42 +- api/fs/path.hpp | 108 +- api/fs/vbr.hpp | 4 +- api/hw/dev.hpp | 94 +- api/hw/disk.hpp | 82 +- api/hw/disk_device.hpp | 52 +- api/hw/ide.hpp | 84 +- api/hw/pci.hpp | 88 +- api/hw/pci_device.hpp | 396 ++--- api/hw/pic.hpp | 22 +- api/hw/pit.hpp | 274 +-- api/kernel/irq_manager.hpp | 20 +- api/kernel/os.hpp | 4 +- api/kernel/service.hpp | 2 +- api/kernel/terminal.hpp | 20 +- api/net/arp.hpp | 210 +-- api/net/buffer_store.hpp | 148 +- api/net/dns/client.hpp | 4 +- api/net/dns/dns.hpp | 42 +- api/net/inet.hpp | 68 +- api/net/inet4.hpp | 2 +- api/net/inet64.hpp | 14 +- api/net/ip4.hpp | 226 +-- api/net/ip4/icmpv4.hpp | 60 +- api/net/ip4/packet_ip4.hpp | 100 +- api/net/ip4/udp.hpp | 108 +- api/net/ip6/icmp6.hpp | 2 +- api/net/ip6/ip6.hpp | 86 +- api/net/ip6/udp6.hpp | 4 +- api/net/tcp.hpp | 2412 +++++++++++++------------- api/net/tcp_connection_states.hpp | 328 ++-- api/net/util.hpp | 48 +- api/utility/async_loop.hpp | 26 +- api/utility/delegate.hpp | 74 +- api/utility/membitmap.hpp | 20 +- api/utility/ringbuffer.hpp | 174 +- api/utility/signal.hpp | 52 +- api/virtio/console.hpp | 4 +- api/virtio/virtio.hpp | 56 +- etc/batch_apply_editorconfig.sh | 0 examples/demo_service/service.cpp | 80 +- examples/tcp/service.cpp | 90 +- src/crt/cxx_abi.cpp | 2 +- src/crt/mman.cpp | 28 +- src/debug/ircd.cpp | 188 +- src/debug/ircsplit.hpp | 60 +- src/debug/test_disk.cpp | 200 +-- src/debug/test_ipv6.cpp | 56 +- src/debug/test_service.cpp | 48 +- src/debug/test_tcp.cpp | 20 +- src/fs/disk.cpp | 204 +-- src/fs/ext4.cpp | 22 +- src/fs/fat.cpp | 280 +-- src/fs/fat_async.cpp | 308 ++-- src/fs/fat_sync.cpp | 158 +- src/fs/mbr.cpp | 136 +- src/fs/memdisk.cpp | 74 +- src/fs/path.cpp | 174 +- src/hw/cpu_freq_sampling.cpp | 108 +- src/hw/ide.cpp | 276 +-- src/hw/nic.cpp | 24 +- src/hw/pci_device.cpp | 264 +-- src/hw/pit.cpp | 344 ++-- src/include/hw/cpu_freq_sampling.hpp | 18 +- src/kernel/cpuid.cpp | 24 +- src/kernel/irq_manager.cpp | 116 +- src/kernel/os.cpp | 16 +- src/kernel/pci_manager.cpp | 10 +- src/kernel/rdrand.cpp | 12 +- src/kernel/syscalls.cpp | 2 +- src/kernel/terminal.cpp | 308 ++-- src/kernel/terminal_disk.cpp | 198 +-- src/kernel/vga.cpp | 4 +- src/net/arp.cpp | 316 ++-- src/net/buffer_store.cpp | 118 +- src/net/dhcp/dh4client.cpp | 148 +- src/net/dns/client.cpp | 16 +- src/net/dns/dns.cpp | 214 +-- src/net/ethernet.cpp | 134 +- src/net/inet.cpp | 8 +- src/net/inet_common.cpp | 34 +- src/net/ip4.cpp | 124 +- src/net/ip4/icmpv4.cpp | 92 +- src/net/ip4/udp.cpp | 102 +- src/net/ip4/udp_socket.cpp | 58 +- src/net/ip6/icmp6.cpp | 242 +-- src/net/ip6/ip6.cpp | 78 +- src/net/ip6/udp6.cpp | 12 +- src/net/tcp.cpp | 306 ++-- src/net/tcp_connection.cpp | 394 ++--- src/net/tcp_connection_states.cpp | 438 ++--- src/virtio/block.cpp | 86 +- src/virtio/console.cpp | 96 +- src/virtio/virtio.cpp | 20 +- src/virtio/virtionet.cpp | 6 +- test/IDE/service.cpp | 28 +- test/IRQ_PIC/service.cpp | 20 +- test/STL/service.cpp | 102 +- test/bufstore/service.cpp | 6 +- test/fat/fat16.cpp | 62 +- test/fat/fat32.cpp | 8 +- test/memdisk/bigdisk.cpp | 6 +- test/memdisk/twosector.cpp | 8 +- test/tcp/service.cpp | 326 ++-- test/term/term.cpp | 44 +- test/transmit/service.cpp | 2 +- test/vga/vga.cpp | 28 +- vmbuild/vmbuild.cpp | 20 +- 114 files changed, 6770 insertions(+), 6770 deletions(-) mode change 100644 => 100755 etc/batch_apply_editorconfig.sh diff --git a/api/fs/common.hpp b/api/fs/common.hpp index c09fb25c96..6ef7dc11c3 100644 --- a/api/fs/common.hpp +++ b/api/fs/common.hpp @@ -23,13 +23,13 @@ namespace fs { -typedef std::shared_ptr buffer_t; + typedef std::shared_ptr buffer_t; -// TODO: transform this into a class with a bool operator -using error_t = bool; + // TODO: transform this into a class with a bool operator + using error_t = bool; -/** @var no_error: Always returns boolean false when used in expressions */ -extern error_t no_error; + /** @var no_error: Always returns boolean false when used in expressions */ + extern error_t no_error; } //< namespace fs diff --git a/api/fs/disk.hpp b/api/fs/disk.hpp index d49137cde8..72ad7f7757 100644 --- a/api/fs/disk.hpp +++ b/api/fs/disk.hpp @@ -29,87 +29,87 @@ namespace fs { -class Disk { -public: - struct Partition; //< Representation of a disk partition + class Disk { + public: + struct Partition; //< Representation of a disk partition - /** Callbacks */ - using on_parts_func = std::function&)>; - using on_mount_func = std::function; + /** Callbacks */ + using on_parts_func = std::function&)>; + using on_mount_func = std::function; - /** Constructor */ - explicit Disk(hw::IDiskDevice&); + /** Constructor */ + explicit Disk(hw::IDiskDevice&); - enum partition_t { - MBR = 0, //< Master Boot Record (0) - /** extended partitions (1-4) */ - VBR1, - VBR2, - VBR3, - VBR4, + enum partition_t { + MBR = 0, //< Master Boot Record (0) + /** extended partitions (1-4) */ + VBR1, + VBR2, + VBR3, + VBR4, - INVALID - }; //< enum partition_t + INVALID + }; //< enum partition_t - struct Partition { - explicit Partition(const uint8_t fl, const uint8_t Id, - const uint32_t LBA, const uint32_t sz) noexcept : - flags {fl}, - id {Id}, - lba_begin {LBA}, - sectors {sz} - {} + struct Partition { + explicit Partition(const uint8_t fl, const uint8_t Id, + const uint32_t LBA, const uint32_t sz) noexcept : + flags {fl}, + id {Id}, + lba_begin {LBA}, + sectors {sz} + {} - uint8_t flags; - uint8_t id; - uint32_t lba_begin; - uint32_t sectors; + uint8_t flags; + uint8_t id; + uint32_t lba_begin; + uint32_t sectors; - // true if the partition has boot code / is bootable - bool is_boot() const noexcept - { return flags & 0x1; } + // true if the partition has boot code / is bootable + bool is_boot() const noexcept + { return flags & 0x1; } - // human-readable name of partition id - std::string name() const; + // human-readable name of partition id + std::string name() const; - // logical block address of beginning of partition - uint32_t lba() const - { return lba_begin; } + // logical block address of beginning of partition + uint32_t lba() const + { return lba_begin; } - }; //< struct Partition + }; //< struct Partition - /** Return a reference to the specified filesystem */ - FileSystem& fs() noexcept - { return *filesys; } + /** Return a reference to the specified filesystem */ + FileSystem& fs() noexcept + { return *filesys; } - //************** disk functions **************// + //************** disk functions **************// - hw::IDiskDevice& dev() noexcept - { return device; } + hw::IDiskDevice& dev() noexcept + { return device; } - // Returns true if the disk has no sectors - bool empty() const noexcept - { return device.size() == 0; } + // Returns true if the disk has no sectors + bool empty() const noexcept + { return device.size() == 0; } - // Mounts the first partition detected (MBR -> VBR1-4 -> ext) - void mount(on_mount_func func); + // Mounts the first partition detected (MBR -> VBR1-4 -> ext) + void mount(on_mount_func func); - // Mount partition @part as the filesystem FS - void mount(partition_t part, on_mount_func func); + // Mount partition @part as the filesystem FS + void mount(partition_t part, on_mount_func func); - /** - * Returns a vector of the partitions on a disk - * - * The disk does not need to be mounted beforehand - */ - void partitions(on_parts_func func); + /** + * Returns a vector of the partitions on a disk + * + * The disk does not need to be mounted beforehand + */ + void partitions(on_parts_func func); -private: - hw::IDiskDevice& device; - std::unique_ptr filesys; -}; //< class Disk + private: + hw::IDiskDevice& device; + std::unique_ptr filesys; + }; //< class Disk -using Disk_ptr = std::shared_ptr; + using Disk_ptr = std::shared_ptr; } //< namespace fs diff --git a/api/fs/ext4.hpp b/api/fs/ext4.hpp index d6f73782e5..ca289b95d0 100644 --- a/api/fs/ext4.hpp +++ b/api/fs/ext4.hpp @@ -32,16 +32,16 @@ namespace fs struct EXT4 : public FileSystem { /** - Blocks 2^32 2^32 2^32 2^32 - Inodes 2^32 2^32 2^32 2^32 - File System Size 4TiB 8TiB 16TiB 256PiB - Blocks Per Block Group 8,192 16,384 32,768 524,288 - Inodes Per Block Group 8,192 16,384 32,768 524,288 - Block Group Size 8MiB 32MiB 128MiB 32GiB - Blocks Per File, Extents 2^32 2^32 2^32 2^32 - Blocks Per File, Block Maps 16,843,020 134,480,396 1,074,791,436 4,398,314,962,956 - File Size, Extents 4TiB 8TiB 16TiB 256TiB - File Size, Block Maps 16GiB 256GiB 4TiB 256PiB + Blocks 2^32 2^32 2^32 2^32 + Inodes 2^32 2^32 2^32 2^32 + File System Size 4TiB 8TiB 16TiB 256PiB + Blocks Per Block Group 8,192 16,384 32,768 524,288 + Inodes Per Block Group 8,192 16,384 32,768 524,288 + Block Group Size 8MiB 32MiB 128MiB 32GiB + Blocks Per File, Extents 2^32 2^32 2^32 2^32 + Blocks Per File, Block Maps 16,843,020 134,480,396 1,074,791,436 4,398,314,962,956 + File Size, Extents 4TiB 8TiB 16TiB 256TiB + File Size, Block Maps 16GiB 256GiB 4TiB 256PiB **/ // 0 = Mount MBR diff --git a/api/fs/fat.hpp b/api/fs/fat.hpp index 132426d3d5..06e00ae9ab 100644 --- a/api/fs/fat.hpp +++ b/api/fs/fat.hpp @@ -54,14 +54,14 @@ namespace fs virtual std::string name() const override { switch (this->fat_type) - { - case T_FAT12: + { + case T_FAT12: return "FAT12"; - case T_FAT16: + case T_FAT16: return "FAT16"; - case T_FAT32: + case T_FAT32: return "FAT32"; - } + } return "Invalid fat type"; } /// ----------------------------------------------------- /// @@ -121,7 +121,7 @@ namespace fs uint32_t size() const { - return filesize; + return filesize; } } __attribute__((packed)); @@ -162,16 +162,16 @@ namespace fs uint16_t cl_to_entry_offset(uint32_t cl) { if (fat_type == T_FAT16) - return (cl * 2) % sector_size; + return (cl * 2) % sector_size; else // T_FAT32 - return (cl * 4) % sector_size; + return (cl * 4) % sector_size; } uint16_t cl_to_entry_sector(uint32_t cl) { if (fat_type == T_FAT16) - return reserved + (cl * 2 / sector_size); + return reserved + (cl * 2 / sector_size); else // T_FAT32 - return reserved + (cl * 4 / sector_size); + return reserved + (cl * 4 / sector_size); } // initialize filesystem by providing base sector diff --git a/api/fs/filesystem.hpp b/api/fs/filesystem.hpp index 215e0cb9b2..498f642f74 100644 --- a/api/fs/filesystem.hpp +++ b/api/fs/filesystem.hpp @@ -28,99 +28,99 @@ namespace fs { -class FileSystem { -public: - struct Dirent; //< Generic structure for directory entries + class FileSystem { + public: + struct Dirent; //< Generic structure for directory entries - using dirvector = std::vector; - using dirvec_t = std::shared_ptr; - using buffer_t = std::shared_ptr; + using dirvector = std::vector; + using dirvec_t = std::shared_ptr; + using buffer_t = std::shared_ptr; - using on_mount_func = std::function; - using on_ls_func = std::function; - using on_read_func = std::function; - using on_stat_func = std::function; + using on_mount_func = std::function; + using on_ls_func = std::function; + using on_read_func = std::function; + using on_stat_func = std::function; - struct Buffer - { - error_t err; - buffer_t buffer; - uint64_t len; + struct Buffer + { + error_t err; + buffer_t buffer; + uint64_t len; - Buffer(error_t e, buffer_t b, size_t l) - : err(e), buffer(b), len(l) {} - }; + Buffer(error_t e, buffer_t b, size_t l) + : err(e), buffer(b), len(l) {} + }; - enum Enttype { - FILE, - DIR, - /** FAT puts disk labels in the root directory, hence: */ - VOLUME_ID, - SYM_LINK, + enum Enttype { + FILE, + DIR, + /** FAT puts disk labels in the root directory, hence: */ + VOLUME_ID, + SYM_LINK, - INVALID_ENTITY - }; //< enum Enttype + INVALID_ENTITY + }; //< enum Enttype - /** Generic structure for directory entries */ - struct Dirent { - /** Default constructor */ - explicit Dirent(const Enttype t = INVALID_ENTITY, const std::string& n = "", - const uint64_t blk = 0U, const uint64_t pr = 0U, - const uint64_t sz = 0U, const uint32_t attr = 0U) : - ftype {t}, - fname {n}, - block {blk}, - parent {pr}, - size {sz}, - attrib {attr}, - timestamp {0} - {} + /** Generic structure for directory entries */ + struct Dirent { + /** Default constructor */ + explicit Dirent(const Enttype t = INVALID_ENTITY, const std::string& n = "", + const uint64_t blk = 0U, const uint64_t pr = 0U, + const uint64_t sz = 0U, const uint32_t attr = 0U) : + ftype {t}, + fname {n}, + block {blk}, + parent {pr}, + size {sz}, + attrib {attr}, + timestamp {0} + {} - Enttype ftype; - std::string fname; - uint64_t block; - uint64_t parent; //< Parent's block# - uint64_t size; - uint32_t attrib; - int64_t timestamp; + Enttype ftype; + std::string fname; + uint64_t block; + uint64_t parent; //< Parent's block# + uint64_t size; + uint32_t attrib; + int64_t timestamp; - Enttype type() const noexcept - { return ftype; } + Enttype type() const noexcept + { return ftype; } - // true if this dirent is valid - // if not, it means don't read any values from the Dirent as they are not - bool is_valid() const - { return ftype != INVALID_ENTITY; } + // true if this dirent is valid + // if not, it means don't read any values from the Dirent as they are not + bool is_valid() const + { return ftype != INVALID_ENTITY; } - // most common types - bool is_file() const noexcept - { return ftype == FILE; } - bool is_dir() const noexcept - { return ftype == DIR; } + // most common types + bool is_file() const noexcept + { return ftype == FILE; } + bool is_dir() const noexcept + { return ftype == DIR; } - // the entrys name - const std::string& name() const noexcept - { return fname; } + // the entrys name + const std::string& name() const noexcept + { return fname; } - // type converted to human-readable string - std::string type_string() const { - switch (ftype) { - case FILE: - return "File"; - case DIR: - return "Directory"; - case VOLUME_ID: - return "Volume ID"; + // type converted to human-readable string + std::string type_string() const { + switch (ftype) { + case FILE: + return "File"; + case DIR: + return "Directory"; + case VOLUME_ID: + return "Volume ID"; - case INVALID_ENTITY: - return "Invalid entity"; - default: - return "Unknown type"; - } //< switch (type) - } - }; //< struct Dirent + case INVALID_ENTITY: + return "Invalid entity"; + default: + return "Unknown type"; + } //< switch (type) + } + }; //< struct Dirent - /** Mount this filesystem with LBA at @base_sector */ + /** Mount this filesystem with LBA at @base_sector */ virtual void mount(uint64_t lba, uint64_t size, on_mount_func on_mount) = 0; /** @param path: Path in the mounted filesystem */ @@ -144,13 +144,13 @@ class FileSystem { /** Default destructor */ virtual ~FileSystem() noexcept = default; -}; //< class FileSystem + }; //< class FileSystem -// simplify initializing shared vector -inline FileSystem::dirvec_t new_shared_vector() -{ - return std::make_shared (); -} + // simplify initializing shared vector + inline FileSystem::dirvec_t new_shared_vector() + { + return std::make_shared (); + } } //< namespace fs diff --git a/api/fs/mbr.hpp b/api/fs/mbr.hpp index d36d539544..f888162e0d 100644 --- a/api/fs/mbr.hpp +++ b/api/fs/mbr.hpp @@ -24,53 +24,53 @@ namespace fs { -struct MBR { - static constexpr int PARTITIONS {4}; + struct MBR { + static constexpr int PARTITIONS {4}; - struct partition { - uint8_t flags; - uint8_t CHS_BEG[3]; - uint8_t type; - uint8_t CHS_END[3]; - uint32_t lba_begin; - uint32_t sectors; - } __attribute__((packed)); + struct partition { + uint8_t flags; + uint8_t CHS_BEG[3]; + uint8_t type; + uint8_t CHS_END[3]; + uint32_t lba_begin; + uint32_t sectors; + } __attribute__((packed)); - /** Legacy BIOS Parameter Block */ - struct BPB { - uint16_t bytes_per_sector; - uint8_t sectors_per_cluster; - uint16_t reserved_sectors; - uint8_t fa_tables; - uint16_t root_entries; - uint16_t small_sectors; - uint8_t media_type; // 0xF8 == hard drive - uint16_t sectors_per_fat; - uint16_t sectors_per_track; - uint16_t num_heads; - uint32_t hidden_sectors; - uint32_t large_sectors; // Used if small_sectors == 0 - uint8_t disk_number; // Starts at 0x80 - uint8_t current_head; - uint8_t signature; // Must be 0x28 or 0x29 - uint32_t serial_number; // Unique ID created by mkfs - char volume_label[11]; // Deprecated - char system_id[8]; // FAT12 or FAT16 - } __attribute__((packed)); + /** Legacy BIOS Parameter Block */ + struct BPB { + uint16_t bytes_per_sector; + uint8_t sectors_per_cluster; + uint16_t reserved_sectors; + uint8_t fa_tables; + uint16_t root_entries; + uint16_t small_sectors; + uint8_t media_type; // 0xF8 == hard drive + uint16_t sectors_per_fat; + uint16_t sectors_per_track; + uint16_t num_heads; + uint32_t hidden_sectors; + uint32_t large_sectors; // Used if small_sectors == 0 + uint8_t disk_number; // Starts at 0x80 + uint8_t current_head; + uint8_t signature; // Must be 0x28 or 0x29 + uint32_t serial_number; // Unique ID created by mkfs + char volume_label[11]; // Deprecated + char system_id[8]; // FAT12 or FAT16 + } __attribute__((packed)); - struct mbr { - uint8_t jump[3]; - char oem_name[8]; - uint8_t boot[435]; // Boot-code - partition part[PARTITIONS]; - uint16_t magic; // 0xAA55 + struct mbr { + uint8_t jump[3]; + char oem_name[8]; + uint8_t boot[435]; // Boot-code + partition part[PARTITIONS]; + uint16_t magic; // 0xAA55 - inline BPB* bpb() noexcept - { return reinterpret_cast(boot); } - } __attribute__((packed)); + inline BPB* bpb() noexcept + { return reinterpret_cast(boot); } + } __attribute__((packed)); - static std::string id_to_name(uint8_t); -}; //< struct MBR + static std::string id_to_name(uint8_t); + }; //< struct MBR } //< namespace fs diff --git a/api/fs/memdisk.hpp b/api/fs/memdisk.hpp index d5397a74d4..cab44d12f2 100644 --- a/api/fs/memdisk.hpp +++ b/api/fs/memdisk.hpp @@ -25,35 +25,35 @@ namespace fs { -class MemDisk : public hw::IDiskDevice { -public: - static constexpr size_t SECTOR_SIZE = 512; + class MemDisk : public hw::IDiskDevice { + public: + static constexpr size_t SECTOR_SIZE = 512; - MemDisk() noexcept; + MemDisk() noexcept; - /** Returns the optimal block size for this device. */ - virtual block_t block_size() const noexcept override - { return SECTOR_SIZE; } + /** Returns the optimal block size for this device. */ + virtual block_t block_size() const noexcept override + { return SECTOR_SIZE; } - virtual const char* name() const noexcept override - { - return "MemDisk"; - } + virtual const char* name() const noexcept override + { + return "MemDisk"; + } - virtual void - read(block_t blk, on_read_func reader) override; + virtual void + read(block_t blk, on_read_func reader) override; - virtual void - read(block_t start, block_t cnt, on_read_func reader) override; + virtual void + read(block_t start, block_t cnt, on_read_func reader) override; - virtual buffer_t read_sync(block_t blk) override; + virtual buffer_t read_sync(block_t blk) override; - virtual block_t size() const noexcept override; + virtual block_t size() const noexcept override; -private: - void* image_start; - void* image_end; -}; //< class MemDisk + private: + void* image_start; + void* image_end; + }; //< class MemDisk } //< namespace fs diff --git a/api/fs/path.hpp b/api/fs/path.hpp index 55bcf088db..2abd3e7449 100644 --- a/api/fs/path.hpp +++ b/api/fs/path.hpp @@ -24,79 +24,79 @@ namespace fs { -class Path { -public: - //! constructs Path to the current directory - Path(); + class Path { + public: + //! constructs Path to the current directory + Path(); - //! constructs Path to @path - Path(const std::string& path); + //! constructs Path to @path + Path(const std::string& path); - size_t size() const noexcept - { return stk.size(); } + size_t size() const noexcept + { return stk.size(); } - const std::string& operator [] (const int i) const noexcept - { return stk[i]; } + const std::string& operator [] (const int i) const noexcept + { return stk[i]; } - int getState() const noexcept - { return state; } + int getState() const noexcept + { return state; } - Path& operator = (const std::string& p) { - stk.clear(); - this->state = parse(p); - return *this; - } + Path& operator = (const std::string& p) { + stk.clear(); + this->state = parse(p); + return *this; + } - Path& operator += (const std::string& p) { - this->state = parse(p); - return *this; - } + Path& operator += (const std::string& p) { + this->state = parse(p); + return *this; + } - Path operator + (const std::string& p) const { - Path np = Path(*this); - np.state = np.parse(p); - return np; - } + Path operator + (const std::string& p) const { + Path np = Path(*this); + np.state = np.parse(p); + return np; + } - bool operator == (const Path& p) const { - if (stk.size() not_eq p.stk.size()) return false; - return this->to_string() == p.to_string(); - } + bool operator == (const Path& p) const { + if (stk.size() not_eq p.stk.size()) return false; + return this->to_string() == p.to_string(); + } - bool operator != (const Path& p) const - { return not this->operator == (p); } + bool operator != (const Path& p) const + { return not this->operator == (p); } - bool operator == (const std::string& p) const - { return *this == Path(p); } + bool operator == (const std::string& p) const + { return *this == Path(p); } - bool empty() const noexcept - { return stk.empty(); } + bool empty() const noexcept + { return stk.empty(); } - std::string front() const - { return stk.front(); } + std::string front() const + { return stk.front(); } - std::string back() const - { return stk.back(); } + std::string back() const + { return stk.back(); } - Path& pop_front() noexcept - { stk.pop_front(); return *this; } + Path& pop_front() noexcept + { stk.pop_front(); return *this; } - Path& pop_back() noexcept - { stk.pop_back(); return *this; } + Path& pop_back() noexcept + { stk.pop_back(); return *this; } - Path& up() - { if (not stk.empty()) stk.pop_back(); return *this; } + Path& up() + { if (not stk.empty()) stk.pop_back(); return *this; } - std::string to_string() const; + std::string to_string() const; -private: - int parse(const std::string& path); - void name_added(const std::string& name); - std::string real_path() const; + private: + int parse(const std::string& path); + void name_added(const std::string& name); + std::string real_path() const; - int state; - std::deque stk; -}; //< class Path + int state; + std::deque stk; + }; //< class Path } //< namespace fs diff --git a/api/fs/vbr.hpp b/api/fs/vbr.hpp index bef8b24129..dbb145b7bf 100644 --- a/api/fs/vbr.hpp +++ b/api/fs/vbr.hpp @@ -21,9 +21,9 @@ namespace fs { -class VBR { + class VBR { -}; //< class VBR + }; //< class VBR } //< namespace fs diff --git a/api/hw/dev.hpp b/api/hw/dev.hpp index 5571982d1d..559d72982f 100644 --- a/api/hw/dev.hpp +++ b/api/hw/dev.hpp @@ -30,58 +30,58 @@ namespace hw { -/** @Todo: Implement */ -class Serial; -class APIC; -class HPET; + /** @Todo: Implement */ + class Serial; + class APIC; + class HPET; -/** - * Access point for devices - * - * Get a nic by calling `Dev::eth<0, Virtio_Net>(n)`, a disk by calling `Dev::disk<0, VirtioBlk>(n)` etc. - */ -class Dev { -public: - /** Get ethernet device n */ - template - static Nic& eth() { - static Nic eth_ {PCI_manager::device(N)}; - return eth_; - } - - /** Get disk N using driver DRIVER */ - template - static Disk& disk(Args&&... args) { - static Disk - disk_ { - PCI_manager::device(N), - std::forward(args)... - }; - return disk_; - } - - /** Get console N using driver DRIVER */ - template - static DRIVER& console() { - static DRIVER con_ {PCI_manager::device(N)}; - return con_; - } - /** - * Get serial port n - * - * @Todo: Make a serial port class, and move rsprint / rswrite etc. from OS out to it. + * Access point for devices * - * @Note: The DRIVER parameter is there to support virtio serial ports. + * Get a nic by calling `Dev::eth<0, Virtio_Net>(n)`, a disk by calling `Dev::disk<0, VirtioBlk>(n)` etc. */ - template - static PCI_Device& serial(int n); + class Dev { + public: + /** Get ethernet device n */ + template + static Nic& eth() { + static Nic eth_ {PCI_manager::device(N)}; + return eth_; + } + + /** Get disk N using driver DRIVER */ + template + static Disk& disk(Args&&... args) { + static Disk + disk_ { + PCI_manager::device(N), + std::forward(args)... + }; + return disk_; + } + + /** Get console N using driver DRIVER */ + template + static DRIVER& console() { + static DRIVER con_ {PCI_manager::device(N)}; + return con_; + } + + /** + * Get serial port n + * + * @Todo: Make a serial port class, and move rsprint / rswrite etc. from OS out to it. + * + * @Note: The DRIVER parameter is there to support virtio serial ports. + */ + template + static PCI_Device& serial(int n); - /** Programmable Interval Timer device, with ~ms-precision asynchronous timers. */ - static PIT& basic_timer() { - return PIT::instance(); - } -}; //< class Dev + /** Programmable Interval Timer device, with ~ms-precision asynchronous timers. */ + static PIT& basic_timer() { + return PIT::instance(); + } + }; //< class Dev } //< namespace hw diff --git a/api/hw/disk.hpp b/api/hw/disk.hpp index b616613fef..548fc8ca94 100644 --- a/api/hw/disk.hpp +++ b/api/hw/disk.hpp @@ -23,55 +23,55 @@ namespace hw { -template -class Disk : public IDiskDevice { -public: - /** optimal block size for this device */ - virtual block_t block_size() const noexcept override - { return driver.block_size(); } + template + class Disk : public IDiskDevice { + public: + /** optimal block size for this device */ + virtual block_t block_size() const noexcept override + { return driver.block_size(); } - /** Human readable name */ - const char* name() const noexcept override - { - return driver.name(); - } + /** Human readable name */ + const char* name() const noexcept override + { + return driver.name(); + } - virtual void - read(block_t blk, on_read_func del) override - { - driver.read(blk, del); - } - virtual void - read(block_t blk, block_t count, on_read_func del) override - { - driver.read(blk, count, del); - } + virtual void + read(block_t blk, on_read_func del) override + { + driver.read(blk, del); + } + virtual void + read(block_t blk, block_t count, on_read_func del) override + { + driver.read(blk, count, del); + } - virtual buffer_t read_sync(block_t blk) override - { - return driver.read_sync(blk); - } + virtual buffer_t read_sync(block_t blk) override + { + return driver.read_sync(blk); + } - virtual block_t size() const noexcept override - { - return driver.size(); - } + virtual block_t size() const noexcept override + { + return driver.size(); + } - virtual ~Disk() = default; + virtual ~Disk() = default; -private: - DRIVER driver; + private: + DRIVER driver; - /** - * Just a wrapper around the driver constructor - * @note The Dev-class is a friend and will call this - */ - template - explicit Disk(PCI_Device& d, Args&&... args): - driver{d, std::forward(args)... } {} + /** + * Just a wrapper around the driver constructor + * @note The Dev-class is a friend and will call this + */ + template + explicit Disk(PCI_Device& d, Args&&... args): + driver{d, std::forward(args)... } {} - friend class Dev; -}; //< class Disk + friend class Dev; + }; //< class Disk } //< namespace hw diff --git a/api/hw/disk_device.hpp b/api/hw/disk_device.hpp index 0612356c3c..909165f41a 100644 --- a/api/hw/disk_device.hpp +++ b/api/hw/disk_device.hpp @@ -26,39 +26,39 @@ namespace hw { -class IDiskDevice { -public: - using block_t = uint64_t; //< Disk device block size - using buffer_t = std::shared_ptr; + class IDiskDevice { + public: + using block_t = uint64_t; //< Disk device block size + using buffer_t = std::shared_ptr; - // Delegate for result of reading a disk sector - using on_read_func = std::function; + // Delegate for result of reading a disk sector + using on_read_func = std::function; - /** Human-readable name of this disk controller */ - virtual const char* name() const noexcept = 0; + /** Human-readable name of this disk controller */ + virtual const char* name() const noexcept = 0; - /** The size of the disk in whole sectors */ - virtual block_t size() const noexcept = 0; + /** The size of the disk in whole sectors */ + virtual block_t size() const noexcept = 0; - /** Returns the optimal block size for this device */ - virtual block_t block_size() const noexcept = 0; + /** Returns the optimal block size for this device */ + virtual block_t block_size() const noexcept = 0; - /** - * Read block(s) from blk and call func with result - * A null-pointer is passed to result if something bad happened - * Validate using !buffer_t: - * if (!buffer) - * error("Device failed to read sector"); - **/ - virtual void read(block_t blk, on_read_func func) = 0; - virtual void read(block_t blk, block_t count, on_read_func) = 0; + /** + * Read block(s) from blk and call func with result + * A null-pointer is passed to result if something bad happened + * Validate using !buffer_t: + * if (!buffer) + * error("Device failed to read sector"); + **/ + virtual void read(block_t blk, on_read_func func) = 0; + virtual void read(block_t blk, block_t count, on_read_func) = 0; - /** read synchronously the block @blk */ - virtual buffer_t read_sync(block_t blk) = 0; + /** read synchronously the block @blk */ + virtual buffer_t read_sync(block_t blk) = 0; - /** Default destructor */ - virtual ~IDiskDevice() noexcept = default; -}; //< class IDiskDevice + /** Default destructor */ + virtual ~IDiskDevice() noexcept = default; + }; //< class IDiskDevice } //< namespace hw diff --git a/api/hw/ide.hpp b/api/hw/ide.hpp index 9e4d3b2760..759305a712 100644 --- a/api/hw/ide.hpp +++ b/api/hw/ide.hpp @@ -26,59 +26,59 @@ namespace hw { -/** IDE device driver */ -class IDE : public IDiskDevice { -public: - enum selector_t - { - MASTER = 0x00, - SLAVE = 0x10 - }; + /** IDE device driver */ + class IDE : public IDiskDevice { + public: + enum selector_t + { + MASTER = 0x00, + SLAVE = 0x10 + }; - /** - * Constructor - * - * @param pcidev: An initialized PCI device - */ - explicit IDE(hw::PCI_Device& pcidev, selector_t); + /** + * Constructor + * + * @param pcidev: An initialized PCI device + */ + explicit IDE(hw::PCI_Device& pcidev, selector_t); - /** Human-readable name of this disk controller */ - virtual const char* name() const noexcept override - { return "IDE Controller"; } + /** Human-readable name of this disk controller */ + virtual const char* name() const noexcept override + { return "IDE Controller"; } - /** Returns the optimal block size for this device. */ - virtual block_t block_size() const noexcept override - { return 512; } + /** Returns the optimal block size for this device. */ + virtual block_t block_size() const noexcept override + { return 512; } - virtual void read(block_t blk, on_read_func reader) override; - virtual void read(block_t blk, block_t count, on_read_func reader) override; + virtual void read(block_t blk, on_read_func reader) override; + virtual void read(block_t blk, block_t count, on_read_func reader) override; - /** read synchronously from IDE disk */ - virtual buffer_t read_sync(block_t blk) override; + /** read synchronously from IDE disk */ + virtual buffer_t read_sync(block_t blk) override; - virtual block_t size() const noexcept override - { return _nb_blk; } + virtual block_t size() const noexcept override + { return _nb_blk; } - static void set_irq_mode(const bool on) noexcept; + static void set_irq_mode(const bool on) noexcept; - static void wait_status_busy() noexcept; - static void wait_status_flags(const int flags, const bool set) noexcept; + static void wait_status_busy() noexcept; + static void wait_status_flags(const int flags, const bool set) noexcept; -private: - void set_drive(const uint8_t drive) const noexcept; - void set_nbsectors(const uint8_t cnt) const noexcept; - void set_blocknum(block_t blk) const noexcept; - void set_command(const uint16_t command) const noexcept; + private: + void set_drive(const uint8_t drive) const noexcept; + void set_nbsectors(const uint8_t cnt) const noexcept; + void set_blocknum(block_t blk) const noexcept; + void set_command(const uint16_t command) const noexcept; - void callback_wrapper(); - void enable_irq_handler(); + void callback_wrapper(); + void enable_irq_handler(); -private: - hw::PCI_Device& _pcidev; // PCI device - uint8_t _drive; // Drive id (IDE_MASTER or IDE_SLAVE) - uint32_t _iobase; // PCI device io base address - block_t _nb_blk; // Max nb blocks of the device -}; //< class IDE + private: + hw::PCI_Device& _pcidev; // PCI device + uint8_t _drive; // Drive id (IDE_MASTER or IDE_SLAVE) + uint32_t _iobase; // PCI device io base address + block_t _nb_blk; // Max nb blocks of the device + }; //< class IDE } //< namespace hw diff --git a/api/hw/pci.hpp b/api/hw/pci.hpp index f839eae85d..fbd0b5a975 100644 --- a/api/hw/pci.hpp +++ b/api/hw/pci.hpp @@ -5,53 +5,53 @@ namespace hw { -typedef uint16_t port_t; + typedef uint16_t port_t; -static inline int inp(port_t port) -{ - int ret; + static inline int inp(port_t port) + { + int ret; - __asm__ volatile("xorl %eax,%eax"); - __asm__ volatile("inb %%dx,%%al" - :"=a"(ret) - :"d"(port)); - return ret; -} - -static inline uint16_t inpw(port_t port) -{ - uint16_t ret; - __asm__ volatile("xorl %eax,%eax"); - __asm__ volatile("inw %%dx,%%ax" - :"=a"(ret) - :"d"(port)); - return ret; -} - -static inline uint32_t inpd(port_t port) -{ - uint32_t ret; - __asm__ volatile("xorl %eax,%eax"); - __asm__ volatile("inl %%dx,%%eax" - :"=a"(ret) - :"d"(port)); + __asm__ volatile("xorl %eax,%eax"); + __asm__ volatile("inb %%dx,%%al" + :"=a"(ret) + :"d"(port)); + return ret; + } + + static inline uint16_t inpw(port_t port) + { + uint16_t ret; + __asm__ volatile("xorl %eax,%eax"); + __asm__ volatile("inw %%dx,%%ax" + :"=a"(ret) + :"d"(port)); + return ret; + } + + static inline uint32_t inpd(port_t port) + { + uint32_t ret; + __asm__ volatile("xorl %eax,%eax"); + __asm__ volatile("inl %%dx,%%eax" + :"=a"(ret) + :"d"(port)); - return ret; -} - - -static inline void outp(port_t port, uint8_t data) -{ - __asm__ volatile ("outb %%al,%%dx"::"a" (data), "d"(port)); -} -static inline void outpw(port_t port, uint16_t data) -{ - __asm__ volatile ("outw %%ax,%%dx"::"a" (data), "d"(port)); -} -static inline void outpd(port_t port, uint32_t data) -{ - __asm__ volatile ("outl %%eax,%%dx"::"a" (data), "d"(port)); -} + return ret; + } + + + static inline void outp(port_t port, uint8_t data) + { + __asm__ volatile ("outb %%al,%%dx"::"a" (data), "d"(port)); + } + static inline void outpw(port_t port, uint16_t data) + { + __asm__ volatile ("outw %%ax,%%dx"::"a" (data), "d"(port)); + } + static inline void outpd(port_t port, uint32_t data) + { + __asm__ volatile ("outl %%eax,%%dx"::"a" (data), "d"(port)); + } } //< namespace hw diff --git a/api/hw/pci_device.hpp b/api/hw/pci_device.hpp index 4e200fa1a3..fb55a09972 100644 --- a/api/hw/pci_device.hpp +++ b/api/hw/pci_device.hpp @@ -23,244 +23,244 @@ namespace PCI { -static const uint16_t CONFIG_ADDR {0xCF8U}; -static const uint16_t CONFIG_DATA {0xCFCU}; -static const uint8_t CONFIG_INTR {0x3CU}; + static const uint16_t CONFIG_ADDR {0xCF8U}; + static const uint16_t CONFIG_DATA {0xCFCU}; + static const uint8_t CONFIG_INTR {0x3CU}; -static const uint8_t CONFIG_VENDOR {0x00U}; -static const uint8_t CONFIG_CLASS_REV {0x08U}; + static const uint8_t CONFIG_VENDOR {0x00U}; + static const uint8_t CONFIG_CLASS_REV {0x08U}; -static const uint8_t CONFIG_BASE_ADDR_0 {0x10U}; + static const uint8_t CONFIG_BASE_ADDR_0 {0x10U}; -static const uint32_t BASE_ADDRESS_MEM_MASK {~0x0FUL}; -static const uint32_t BASE_ADDRESS_IO_MASK {~0x03UL}; + static const uint32_t BASE_ADDRESS_MEM_MASK {~0x0FUL}; + static const uint32_t BASE_ADDRESS_IO_MASK {~0x03UL}; -static const uint32_t WTF {0xffffffffU}; + static const uint32_t WTF {0xffffffffU}; -/** - * @brief PCI device message format - * - * Used to communicate with PCI devices - */ -union msg { - - //! The whole message - uint32_t data; - - /** - * Packed attribtues, ordered low to high. - * - * @note: Doxygen thinks this is a function - it's not + /** + * @brief PCI device message format * - * it's a GCC-directive. + * Used to communicate with PCI devices */ - struct __attribute__((packed)) { - //! The PCI register - uint8_t reg; + union msg { + + //! The whole message + uint32_t data; + + /** + * Packed attribtues, ordered low to high. + * + * @note: Doxygen thinks this is a function - it's not + * + * it's a GCC-directive. + */ + struct __attribute__((packed)) { + //! The PCI register + uint8_t reg; - //! The 16-bit PCI-address @see pci_addr() - uint16_t addr; - uint8_t code; - }; -}; //< union msg + //! The 16-bit PCI-address @see pci_addr() + uint16_t addr; + uint8_t code; + }; + }; //< union msg -/** Relevant class codes (many more) */ -enum classcode_t { - OLD, - STORAGE, - NIC, - DISPLAY, - MULTIMEDIA, - MEMORY, - BRIDGE, - COMMUNICATION, - BASE_SYSTEM_PER, - INPUT_DEVICE, - DOCKING_STATION, - PROCESSOR, - SERIAL_BUS, - WIRELESS, - IO_CTL, - SATELLITE, - ENCRYPTION, - SIGPRO, - OTHER=255 -}; //< enum classcode_t + /** Relevant class codes (many more) */ + enum classcode_t { + OLD, + STORAGE, + NIC, + DISPLAY, + MULTIMEDIA, + MEMORY, + BRIDGE, + COMMUNICATION, + BASE_SYSTEM_PER, + INPUT_DEVICE, + DOCKING_STATION, + PROCESSOR, + SERIAL_BUS, + WIRELESS, + IO_CTL, + SATELLITE, + ENCRYPTION, + SIGPRO, + OTHER=255 + }; //< enum classcode_t } //< namespace PCI namespace hw { -/** - * @brief Communication class for all PCI devices - * - * All low level communication with PCI devices should (ideally) go here. - * - * @todo - * - Consider if we ever need to separate the address into 'bus/dev/func' parts. - * - Do we ever need anything but PCI Devices? -*/ -class PCI_Device { // public Device //Why not? A PCI device is too general to be accessible? -public: - - enum { - VENDOR_AMD = 0x1022, - VENDOR_INTEL = 0x8086, - VENDOR_CIRRUS = 0x1013, - VENDOR_VIRTIO = 0x1AF4, - VENDOR_REALTEK = 0x10EC - }; - /** - * Constructor - * - * @param pci_addr: A 16-bit PCI address. - * @param device_id: A device ID, consisting of PCI vendor and product ID's. - * - * @see pci_addr() for more about the address + * @brief Communication class for all PCI devices + * + * All low level communication with PCI devices should (ideally) go here. + * + * @todo + * - Consider if we ever need to separate the address into 'bus/dev/func' parts. + * - Do we ever need anything but PCI Devices? */ - explicit PCI_Device(const uint16_t pci_addr, const uint32_t device_id) noexcept; + class PCI_Device { // public Device //Why not? A PCI device is too general to be accessible? + public: - //! @brief Read from device with implicit pci_address (e.g. used by Nic) - uint32_t read_dword(const uint8_t reg) noexcept; + enum { + VENDOR_AMD = 0x1022, + VENDOR_INTEL = 0x8086, + VENDOR_CIRRUS = 0x1013, + VENDOR_VIRTIO = 0x1AF4, + VENDOR_REALTEK = 0x10EC + }; - //! @brief Read from device with explicit pci_addr - static uint32_t read_dword(const uint16_t pci_addr, const uint8_t reg) noexcept; + /** + * Constructor + * + * @param pci_addr: A 16-bit PCI address. + * @param device_id: A device ID, consisting of PCI vendor and product ID's. + * + * @see pci_addr() for more about the address + */ + explicit PCI_Device(const uint16_t pci_addr, const uint32_t device_id) noexcept; + + //! @brief Read from device with implicit pci_address (e.g. used by Nic) + uint32_t read_dword(const uint8_t reg) noexcept; - /** - * Probe for a device on the given address - * - * @param pci_addr: the address to probe - * - * @deprecated We got a 20% performance degradation using this for probing - * - * @see PCI_Device() - */ - static PCI_Device* Create(uint16_t pci_addr); + //! @brief Read from device with explicit pci_addr + static uint32_t read_dword(const uint16_t pci_addr, const uint8_t reg) noexcept; - // @brief Get a device by address. @see pci_addr(). - static PCI_Device* get(uint16_t pci_addr); + /** + * Probe for a device on the given address + * + * @param pci_addr: the address to probe + * + * @deprecated We got a 20% performance degradation using this for probing + * + * @see PCI_Device() + */ + static PCI_Device* Create(uint16_t pci_addr); - // @brief Get a device by individual address parts. - // @todo Will we ever need this? - static PCI_Device* get(int busno, int devno, int funcno); + // @brief Get a device by address. @see pci_addr(). + static PCI_Device* get(uint16_t pci_addr); + + // @brief Get a device by individual address parts. + // @todo Will we ever need this? + static PCI_Device* get(int busno, int devno, int funcno); - /** A descriptive name */ - inline const char* name(); + /** A descriptive name */ + inline const char* name(); - /** - * Get the PCI address of device. - * - * The address is a composite of 'bus', 'device' and 'function', usually used - * (i.e. by Linux) to designate a PCI device. - * - * @return: The address of the device - */ - inline uint16_t pci_addr() const noexcept - { return pci_addr_; }; + /** + * Get the PCI address of device. + * + * The address is a composite of 'bus', 'device' and 'function', usually used + * (i.e. by Linux) to designate a PCI device. + * + * @return: The address of the device + */ + inline uint16_t pci_addr() const noexcept + { return pci_addr_; }; - /** Get the pci class code. */ - inline PCI::classcode_t classcode() const noexcept - { return static_cast(devtype_.classcode); } + /** Get the pci class code. */ + inline PCI::classcode_t classcode() const noexcept + { return static_cast(devtype_.classcode); } - inline uint16_t rev_id() const noexcept - { return devtype_.rev_id; } + inline uint16_t rev_id() const noexcept + { return devtype_.rev_id; } - /** Get the pci vendor and product id */ - inline uint16_t vendor_id() const noexcept - { return device_id_.vendor; } + /** Get the pci vendor and product id */ + inline uint16_t vendor_id() const noexcept + { return device_id_.vendor; } - inline uint16_t product_id() const noexcept - { return device_id_.product; } + inline uint16_t product_id() const noexcept + { return device_id_.product; } - /** - * Parse all Base Address Registers (BAR's) - * - * Used to determine how to communicate with the device. - * - * This function adds resources to the PCI_Device. - */ - void probe_resources() noexcept; + /** + * Parse all Base Address Registers (BAR's) + * + * Used to determine how to communicate with the device. + * + * This function adds resources to the PCI_Device. + */ + void probe_resources() noexcept; - /** The base address of the (first) I/O resource */ - uint32_t iobase() const noexcept; + /** The base address of the (first) I/O resource */ + uint32_t iobase() const noexcept; -private: - // @brief The 3-part PCI address - uint16_t pci_addr_; + private: + // @brief The 3-part PCI address + uint16_t pci_addr_; - //@brief The three address parts derived (if needed) - uint8_t busno_ {0}; - uint8_t devno_ {0}; - uint8_t funcno_ {0}; + //@brief The three address parts derived (if needed) + uint8_t busno_ {0}; + uint8_t devno_ {0}; + uint8_t funcno_ {0}; - // @brief The 2-part ID retrieved from the device - union vendor_product { - uint32_t __value; - struct __attribute__((packed)) { - uint16_t vendor; - uint16_t product; - }; - } device_id_; + // @brief The 2-part ID retrieved from the device + union vendor_product { + uint32_t __value; + struct __attribute__((packed)) { + uint16_t vendor; + uint16_t product; + }; + } device_id_; - // @brief The class code (device type) - union class_revision { - uint32_t reg; - struct __attribute__((packed)) { - uint8_t rev_id; - uint8_t prog_if; - uint8_t subclass; - uint8_t classcode; - }; - struct __attribute__((packed)) { - uint16_t class_subclass; - uint8_t __prog_if; //Overlaps the above - uint8_t revision; - }; - } devtype_; + // @brief The class code (device type) + union class_revision { + uint32_t reg; + struct __attribute__((packed)) { + uint8_t rev_id; + uint8_t prog_if; + uint8_t subclass; + uint8_t classcode; + }; + struct __attribute__((packed)) { + uint16_t class_subclass; + uint8_t __prog_if; //Overlaps the above + uint8_t revision; + }; + } devtype_; - // @brief Printable names - const char* classname_; - const char* vendorname_; - const char* productname_; + // @brief Printable names + const char* classname_; + const char* vendorname_; + const char* productname_; - // Device Resources + // Device Resources - //! @brief Resource types, "Memory" or "I/O" - enum resource_t { RES_MEM, RES_IO }; + //! @brief Resource types, "Memory" or "I/O" + enum resource_t { RES_MEM, RES_IO }; - /** A device resource - possibly a list */ - template - struct Resource { - const resource_t type {RT}; - uint32_t start_; - uint32_t len_; - Resource* next {nullptr}; - Resource(const uint32_t start, const uint32_t len) : start_{start}, len_{len} {}; - }; + /** A device resource - possibly a list */ + template + struct Resource { + const resource_t type {RT}; + uint32_t start_; + uint32_t len_; + Resource* next {nullptr}; + Resource(const uint32_t start, const uint32_t len) : start_{start}, len_{len} {}; + }; - //! @brief Resource lists. Members added by add_resource(); - Resource* res_mem_ {nullptr}; - Resource* res_io_ {nullptr}; + //! @brief Resource lists. Members added by add_resource(); + Resource* res_mem_ {nullptr}; + Resource* res_io_ {nullptr}; - //! @brief Write to device with implicit pci_address (e.g. used by Nic) - void write_dword(const uint8_t reg, const uint32_t value) noexcept; + //! @brief Write to device with implicit pci_address (e.g. used by Nic) + void write_dword(const uint8_t reg, const uint32_t value) noexcept; - /** - * Add a resource to a resource queue. - * - * (This seems pretty dirty; private class, reference to pointer etc.) */ - template - void add_resource(Resource* res, Resource*& Q) noexcept { - Resource* q; - if (Q) { - q = Q; - while (q->next) q = q->next; - q->next = res; - } else { - Q = res; + /** + * Add a resource to a resource queue. + * + * (This seems pretty dirty; private class, reference to pointer etc.) */ + template + void add_resource(Resource* res, Resource*& Q) noexcept { + Resource* q; + if (Q) { + q = Q; + while (q->next) q = q->next; + q->next = res; + } else { + Q = res; + } } - } -}; //< class PCI_Device + }; //< class PCI_Device } //< namespace hw diff --git a/api/hw/pic.hpp b/api/hw/pic.hpp index 392e7f6600..c08b346f77 100644 --- a/api/hw/pic.hpp +++ b/api/hw/pic.hpp @@ -27,7 +27,7 @@ namespace hw { /** Programmable Interrupt Controller implementation according to Intel 8259A / 8259A-2 1988 whitepaper - */ + */ class PIC { public: static void init() noexcept; @@ -49,19 +49,19 @@ namespace hw { } /** - @brief End of Interrupt. Master IRQ-lines (0-7) currently use Auto EOI, - but the user should assume that IRQ-specific EOI's are necessary. + @brief End of Interrupt. Master IRQ-lines (0-7) currently use Auto EOI, + but the user should assume that IRQ-specific EOI's are necessary. - @note: - According to Intel 8259A / 8259A-2 whitepaper p. 15 - "The AEOI mode can only be used in a master 8259A and not a slave. - 8259As with a copyright date of 1985 or later will operate in the AEOI - mode as a master or a slave" + @note: + According to Intel 8259A / 8259A-2 whitepaper p. 15 + "The AEOI mode can only be used in a master 8259A and not a slave. + 8259As with a copyright date of 1985 or later will operate in the AEOI + mode as a master or a slave" - If I enable auto-eoi for slave, everything seems to freeze in Qemu, - the moment I get the first network interrupt (IRQ 11). + If I enable auto-eoi for slave, everything seems to freeze in Qemu, + the moment I get the first network interrupt (IRQ 11). - I'm assuming this means that I have an old chip :-) + I'm assuming this means that I have an old chip :-) */ inline static void eoi(const uint8_t irq) noexcept { diff --git a/api/hw/pit.hpp b/api/hw/pit.hpp index 7e29aff3a6..5d21588c9d 100644 --- a/api/hw/pit.hpp +++ b/api/hw/pit.hpp @@ -23,165 +23,165 @@ namespace hw { -/** - Programmable Interval Timer class. A singleton. + /** + Programmable Interval Timer class. A singleton. - @TODO - ...It has timer-functionality, which should probably be super-classed, - so that i.e. the HPET could be used with the same interface. -*/ -class PIT{ -public: - - typedef delegate timeout_handler; - typedef std::function repeat_condition; - - /** Create a one-shot timer. - @param ms: Expiration time. Compatible with all std::chrono durations. - @param handler: A delegate or function to be called on timeout. */ - void onTimeout(std::chrono::milliseconds ms, timeout_handler handler); - - /** Create a repeating timer. - @param ms: Expiration time. Compatible with all std::chrono durations. - @param handler: A delegate or function to be called every ms interval. - @param cond: The timer ends when cond() returns false. Default to true. */ - void onRepeatedTimeout(std::chrono::milliseconds ms, - timeout_handler handler, - repeat_condition cond = forever); - - /** No copy or move. The OS owns one instance forever. */ - PIT(PIT&) = delete; - PIT(PIT&&) = delete; - - /** Get the (single) instance. */ - static PIT& instance() { - static PIT instance_; - return instance_; - }; - - /** Initialize the hardware. */ - static void init(); - - /** The constant frequency of the PIT-hardware, before frequency dividers */ - static constexpr MHz frequency() { return frequency_; } - - static inline MHz current_frequency(){ return frequency() / current_freq_divider_; } - - /** Estimate cpu frequency based on the fixed PIT frequency and rdtsc. - @Note This is an asynchronous function. Once finished the result can be - fetched by CPUFrequency() (below) */ - static void estimateCPUFrequency(); - - /** Get the last estimated CPU frequency. May trigger frequency sampling */ - static MHz CPUFrequency(); - -private: - // Default repeat-condition - static std::function forever; + @TODO + ...It has timer-functionality, which should probably be super-classed, + so that i.e. the HPET could be used with the same interface. + */ + class PIT{ + public: - enum Mode { ONE_SHOT = 0, - HW_ONESHOT = 1 << 1, - RATE_GEN = 2 << 1, - SQ_WAVE = 3 << 1, - SW_STROBE = 4 << 1, - HW_STROBE = 5 << 1, - NONE = 256}; + typedef delegate timeout_handler; + typedef std::function repeat_condition; - // The PIT-chip runs at this fixed frequency (in MHz) , according to OSDev.org */ - static constexpr MHz frequency_ = MHz(14.31818 / 12); + /** Create a one-shot timer. + @param ms: Expiration time. Compatible with all std::chrono durations. + @param handler: A delegate or function to be called on timeout. */ + void onTimeout(std::chrono::milliseconds ms, timeout_handler handler); + + /** Create a repeating timer. + @param ms: Expiration time. Compatible with all std::chrono durations. + @param handler: A delegate or function to be called every ms interval. + @param cond: The timer ends when cond() returns false. Default to true. */ + void onRepeatedTimeout(std::chrono::milliseconds ms, + timeout_handler handler, + repeat_condition cond = forever); + + /** No copy or move. The OS owns one instance forever. */ + PIT(PIT&) = delete; + PIT(PIT&&) = delete; + + /** Get the (single) instance. */ + static PIT& instance() { + static PIT instance_; + return instance_; + }; + + /** Initialize the hardware. */ + static void init(); + + /** The constant frequency of the PIT-hardware, before frequency dividers */ + static constexpr MHz frequency() { return frequency_; } + + static inline MHz current_frequency(){ return frequency() / current_freq_divider_; } + + /** Estimate cpu frequency based on the fixed PIT frequency and rdtsc. + @Note This is an asynchronous function. Once finished the result can be + fetched by CPUFrequency() (below) */ + static void estimateCPUFrequency(); + + /** Get the last estimated CPU frequency. May trigger frequency sampling */ + static MHz CPUFrequency(); + + private: + // Default repeat-condition + static std::function forever; + + enum Mode { ONE_SHOT = 0, + HW_ONESHOT = 1 << 1, + RATE_GEN = 2 << 1, + SQ_WAVE = 3 << 1, + SW_STROBE = 4 << 1, + HW_STROBE = 5 << 1, + NONE = 256}; + + // The PIT-chip runs at this fixed frequency (in MHz) , according to OSDev.org */ + static constexpr MHz frequency_ = MHz(14.31818 / 12); - /** Disable regular timer interrupts- which are turned on at boot-time. */ - static void disable_regular_interrupts(); + /** Disable regular timer interrupts- which are turned on at boot-time. */ + static void disable_regular_interrupts(); - /** The default (soft)handler for timer interrupts */ - void irq_handler(); + /** The default (soft)handler for timer interrupts */ + void irq_handler(); - // Private constructor / destructor. It's a singleton. - PIT(); - ~PIT(); + // Private constructor / destructor. It's a singleton. + PIT(); + ~PIT(); - // State-keeping - static Mode temp_mode_; - static uint16_t temp_freq_divider_; - static uint8_t status_byte_; - static uint16_t current_freq_divider_; - static Mode current_mode_; - static uint64_t IRQ_counter_; + // State-keeping + static Mode temp_mode_; + static uint16_t temp_freq_divider_; + static uint8_t status_byte_; + static uint16_t current_freq_divider_; + static Mode current_mode_; + static uint64_t IRQ_counter_; - // The closest we can get to a millisecond interval, with the PIT-frequency - static constexpr uint16_t millisec_interval = KHz(frequency_).count(); + // The closest we can get to a millisecond interval, with the PIT-frequency + static constexpr uint16_t millisec_interval = KHz(frequency_).count(); - // Count the "milliseconds" - static uint64_t millisec_counter; + // Count the "milliseconds" + static uint64_t millisec_counter; - // Access mode bits are bits 4- and 5 in the Mode register - enum AccessMode { LATCH_COUNT = 0x0, LO_ONLY=0x10, HI_ONLY=0x20, LO_HI=0x30 }; + // Access mode bits are bits 4- and 5 in the Mode register + enum AccessMode { LATCH_COUNT = 0x0, LO_ONLY=0x10, HI_ONLY=0x20, LO_HI=0x30 }; - /** Physically set the PIT-mode */ - static void set_mode(Mode); + /** Physically set the PIT-mode */ + static void set_mode(Mode); - /** Physiclally set the PIT frequency divider */ - static void set_freq_divider(uint16_t); + /** Physiclally set the PIT frequency divider */ + static void set_freq_divider(uint16_t); - /** Set mode to one-shot, and frequency-divider to t */ - static void oneshot(uint16_t t); + /** Set mode to one-shot, and frequency-divider to t */ + static void oneshot(uint16_t t); - /** Read back the PIT status from hardware */ - static uint8_t read_back(uint8_t channel); + /** Read back the PIT status from hardware */ + static uint8_t read_back(uint8_t channel); - /** A timer is a handler and an expiration time (interval). - @todo The timer also keeps a pre-computed rdtsc-value, which is currently unused.*/ - class Timer { - public: - enum Type { ONE_SHOT, REPEAT, REPEAT_WHILE} type_; + /** A timer is a handler and an expiration time (interval). + @todo The timer also keeps a pre-computed rdtsc-value, which is currently unused.*/ + class Timer { + public: + enum Type { ONE_SHOT, REPEAT, REPEAT_WHILE} type_; - Timer() = delete; - Timer(Type, timeout_handler, std::chrono::milliseconds, repeat_condition = forever); - Timer(const Timer&) = default; - Timer(Timer&&) = default; - Timer& operator=(Timer&) = default; - Timer& operator=(Timer&&) = default; - virtual ~Timer() = default; + Timer() = delete; + Timer(Type, timeout_handler, std::chrono::milliseconds, repeat_condition = forever); + Timer(const Timer&) = default; + Timer(Timer&&) = default; + Timer& operator=(Timer&) = default; + Timer& operator=(Timer&&) = default; + virtual ~Timer() = default; - inline Type type(){ return type_; } - inline std::chrono::milliseconds interval(){ return interval_; } - inline uint64_t start() { return timestamp_start_; } - inline uint64_t end() { return timestamp_end_; } - inline void setStart(uint64_t s) { timestamp_start_ = s; } - inline void setEnd(uint64_t e) { timestamp_end_ = e; } - inline timeout_handler handler(){ return handler_; } - inline const repeat_condition cond() { return cond_; } - inline uint32_t id(){ return id_; } - - private: - static uint32_t timers_count_; - uint32_t id_ = 0; - timeout_handler handler_; - uint64_t timestamp_start_; - uint64_t timestamp_end_; - std::chrono::milliseconds interval_; + inline Type type(){ return type_; } + inline std::chrono::milliseconds interval(){ return interval_; } + inline uint64_t start() { return timestamp_start_; } + inline uint64_t end() { return timestamp_end_; } + inline void setStart(uint64_t s) { timestamp_start_ = s; } + inline void setEnd(uint64_t e) { timestamp_end_ = e; } + inline timeout_handler handler(){ return handler_; } + inline const repeat_condition cond() { return cond_; } + inline uint32_t id(){ return id_; } + + private: + static uint32_t timers_count_; + uint32_t id_ = 0; + timeout_handler handler_; + uint64_t timestamp_start_; + uint64_t timestamp_end_; + std::chrono::milliseconds interval_; - /* This Could be a reference in the default case of "forever", but then the - case of a normal lambda being passed in, the user would have to be in charge - of storage. */ - const repeat_condition cond_; - }; - - /** A map of timers. - @note {Performance: We take advantage of the fact that std::map have sorted keys. - * Timers soonest to expire are in the front, so we only iterate over those - * Deletion of finished timers in amortized constant time, via iterators - * Timer insertion is log(n) } - @note This is why we want to instantiate PIT, and why it's a singleton: - If you don't use PIT-timers, you won't pay for them. */ - std::multimap timers_; + /* This Could be a reference in the default case of "forever", but then the + case of a normal lambda being passed in, the user would have to be in charge + of storage. */ + const repeat_condition cond_; + }; + + /** A map of timers. + @note {Performance: We take advantage of the fact that std::map have sorted keys. + * Timers soonest to expire are in the front, so we only iterate over those + * Deletion of finished timers in amortized constant time, via iterators + * Timer insertion is log(n) } + @note This is why we want to instantiate PIT, and why it's a singleton: + If you don't use PIT-timers, you won't pay for them. */ + std::multimap timers_; - /** Queue the timer. This will update timestamps in the timer */ - void start_timer(Timer t, std::chrono::milliseconds); + /** Queue the timer. This will update timestamps in the timer */ + void start_timer(Timer t, std::chrono::milliseconds); -}; + }; } //< namespace hw diff --git a/api/kernel/irq_manager.hpp b/api/kernel/irq_manager.hpp index 77b4911b6d..74dfc5d1ff 100644 --- a/api/kernel/irq_manager.hpp +++ b/api/kernel/irq_manager.hpp @@ -54,14 +54,14 @@ extern "C" { NOTES: * All IRQ-callbacks are in charge of calling End-Of-Interrupt - eoi. - Why? Because this makes it possible to prevent further interrupts until - a condition of your choice is met. And, interrupts are costly as they - always cause vm-exit. + Why? Because this makes it possible to prevent further interrupts until + a condition of your choice is met. And, interrupts are costly as they + always cause vm-exit. * IRQ-numbering: 0 or 32? @TODO: Remove all dependencies on old SanOS code. In particular, eoi is now in global scope - */ +*/ class IRQ_manager { public: using irq_delegate = delegate; @@ -90,7 +90,7 @@ class IRQ_manager { * Failure to do so will keep the interrupt from firing and cause a * stack overflow or similar badness. * } - */ + */ static void set_handler(uint8_t irq, void(*function_addr)()); /** Get handler from inside the IDT. */ @@ -100,7 +100,7 @@ class IRQ_manager { * Subscribe to an IRQ * @param irq: The IRQ to subscribe to - * @param del: A delegate to attach to the IRQ DPC-system + * @param del: A delegate to attach to the IRQ DPC-system * The delegate will be called a.s.a.p. after @param irq gets triggered * @@ -116,7 +116,7 @@ class IRQ_manager { * Get the current subscriber of an IRQ-line * * @param irq: The IRQ to get subscriber for - */ + */ static irq_delegate get_subscriber(uint8_t irq); /** @@ -169,9 +169,9 @@ class IRQ_manager { * Use "set_handler" for a simpler version using defaults */ static void create_gate(IDTDescr* idt_entry, - void (*function_addr)(), - uint16_t segment_sel, - char attributes); + void (*function_addr)(), + uint16_t segment_sel, + char attributes); /** The OS will call the following : */ friend class OS; diff --git a/api/kernel/os.hpp b/api/kernel/os.hpp index 7f64e49f4b..58f4e3fdf0 100644 --- a/api/kernel/os.hpp +++ b/api/kernel/os.hpp @@ -56,7 +56,7 @@ class OS { * Write a cstring to serial port. @todo Should be moved to Dev::serial(n). * * @param ptr: The string to write to serial port - */ + */ static size_t rsprint(const char* ptr); static size_t rsprint(const char* ptr, const size_t len); @@ -69,7 +69,7 @@ class OS { /** * Write to serial port with rswrite. - */ + */ static void default_rsprint(const char*, size_t); /** Start the OS. @todo Should be `init()` - and not accessible from ABI */ diff --git a/api/kernel/service.hpp b/api/kernel/service.hpp index 84f57f0e2f..e4c1c2e1fe 100644 --- a/api/kernel/service.hpp +++ b/api/kernel/service.hpp @@ -26,7 +26,7 @@ extern "C" const char* service_name__; * This is where you take over * * The service gets started whenever the OS is done initializing -*/ + */ class Service { public: /** diff --git a/api/kernel/terminal.hpp b/api/kernel/terminal.hpp index 21180b13ce..79257a620b 100644 --- a/api/kernel/terminal.hpp +++ b/api/kernel/terminal.hpp @@ -50,16 +50,16 @@ class Terminal using Connection_ptr = std::shared_ptr; using Disk_ptr = std::shared_ptr; enum - { - NUL = 0, - BELL = 7, - BS = 8, - HTAB = 9, - LF = 10, - VTAB = 11, - FF = 12, - CR = 13 - }; + { + NUL = 0, + BELL = 7, + BS = 8, + HTAB = 9, + LF = 10, + VTAB = 11, + FF = 12, + CR = 13 + }; using on_write_func = std::function; diff --git a/api/net/arp.hpp b/api/net/arp.hpp index b0c81c1c2b..76317161b6 100644 --- a/api/net/arp.hpp +++ b/api/net/arp.hpp @@ -27,127 +27,127 @@ namespace net { -class PacketArp; + class PacketArp; -/** ARP manager, including an ARP-Cache. */ -class Arp { -private: - /** ARP cache expires after cache_exp_t_ seconds */ - static constexpr uint16_t cache_exp_t_ {60 * 60 * 12}; - - /** Cache entries are just MAC's and timestamps */ - struct cache_entry { - Ethernet::addr mac_; - uint64_t timestamp_; + /** ARP manager, including an ARP-Cache. */ + class Arp { + private: + /** ARP cache expires after cache_exp_t_ seconds */ + static constexpr uint16_t cache_exp_t_ {60 * 60 * 12}; + + /** Cache entries are just MAC's and timestamps */ + struct cache_entry { + Ethernet::addr mac_; + uint64_t timestamp_; - /** Map needs empty constructor (we have no emplace yet) */ - cache_entry() noexcept = default; + /** Map needs empty constructor (we have no emplace yet) */ + cache_entry() noexcept = default; - cache_entry(Ethernet::addr mac) noexcept - : mac_(mac), timestamp_(OS::uptime()) {} + cache_entry(Ethernet::addr mac) noexcept + : mac_(mac), timestamp_(OS::uptime()) {} - cache_entry(const cache_entry& cpy) noexcept - : mac_(cpy.mac_), timestamp_(cpy.timestamp_) {} + cache_entry(const cache_entry& cpy) noexcept + : mac_(cpy.mac_), timestamp_(cpy.timestamp_) {} - void update() noexcept { timestamp_ = OS::uptime(); } - }; //< struct cache_entry - - using Cache = std::map; - using PacketQueue = std::map; -public: - /** - * You can assign your own ARP-resolution delegate - * - * We're doing this to keep the Hårek Haugerud mapping (HH_MAP) - */ - using Arp_resolver = delegate; - - enum Opcode { H_request = 0x100, H_reply = 0x200 }; - - /** Arp opcodes (Big-endian) */ - static constexpr uint16_t H_htype_eth {0x0100}; - static constexpr uint16_t H_ptype_ip4 {0x0008}; - static constexpr uint16_t H_hlen_plen {0x0406}; - - /** Constructor */ - explicit Arp(Inet&) noexcept; - - struct __attribute__((packed)) header { - Ethernet::header ethhdr; // Ethernet header - uint16_t htype; // Hardware type - uint16_t ptype; // Protocol type - uint16_t hlen_plen; // Protocol address length - uint16_t opcode; // Opcode - Ethernet::addr shwaddr; // Source mac - IP4::addr sipaddr; // Source ip - Ethernet::addr dhwaddr; // Target mac - IP4::addr dipaddr; // Target ip - }; - - /** Handle incoming ARP packet. */ - void bottom(Packet_ptr pckt); - - /** Roll your own arp-resolution system. */ - void set_resolver(Arp_resolver ar) - { arp_resolver_ = ar; } - - enum Resolver_name { DEFAULT, HH_MAP }; - - void set_resolver(Resolver_name nm) { - // @TODO: Add HÅREK-mapping here - switch (nm) { - case HH_MAP: - arp_resolver_ = Arp_resolver::from(*this); - break; - default: - arp_resolver_ = Arp_resolver::from(*this); - } - } - - /** Delegate link-layer output. */ - void set_linklayer_out(downstream link) - { linklayer_out_ = link; } - - /** Downstream transmission. */ - void transmit(Packet_ptr); - -private: - Inet& inet_; - - /** Needs to know which mac address to put in header->swhaddr */ - Ethernet::addr mac_; + void update() noexcept { timestamp_ = OS::uptime(); } + }; //< struct cache_entry + + using Cache = std::map; + using PacketQueue = std::map; + public: + /** + * You can assign your own ARP-resolution delegate + * + * We're doing this to keep the Hårek Haugerud mapping (HH_MAP) + */ + using Arp_resolver = delegate; + + enum Opcode { H_request = 0x100, H_reply = 0x200 }; + + /** Arp opcodes (Big-endian) */ + static constexpr uint16_t H_htype_eth {0x0100}; + static constexpr uint16_t H_ptype_ip4 {0x0008}; + static constexpr uint16_t H_hlen_plen {0x0406}; + + /** Constructor */ + explicit Arp(Inet&) noexcept; + + struct __attribute__((packed)) header { + Ethernet::header ethhdr; // Ethernet header + uint16_t htype; // Hardware type + uint16_t ptype; // Protocol type + uint16_t hlen_plen; // Protocol address length + uint16_t opcode; // Opcode + Ethernet::addr shwaddr; // Source mac + IP4::addr sipaddr; // Source ip + Ethernet::addr dhwaddr; // Target mac + IP4::addr dipaddr; // Target ip + }; + + /** Handle incoming ARP packet. */ + void bottom(Packet_ptr pckt); + + /** Roll your own arp-resolution system. */ + void set_resolver(Arp_resolver ar) + { arp_resolver_ = ar; } + + enum Resolver_name { DEFAULT, HH_MAP }; + + void set_resolver(Resolver_name nm) { + // @TODO: Add HÅREK-mapping here + switch (nm) { + case HH_MAP: + arp_resolver_ = Arp_resolver::from(*this); + break; + default: + arp_resolver_ = Arp_resolver::from(*this); + } + } + + /** Delegate link-layer output. */ + void set_linklayer_out(downstream link) + { linklayer_out_ = link; } + + /** Downstream transmission. */ + void transmit(Packet_ptr); + + private: + Inet& inet_; + + /** Needs to know which mac address to put in header->swhaddr */ + Ethernet::addr mac_; - /** Outbound data goes through here */ - downstream linklayer_out_; + /** Outbound data goes through here */ + downstream linklayer_out_; - /** The ARP cache */ - Cache cache_; + /** The ARP cache */ + Cache cache_; - /** Cache IP resolution. */ - void cache(IP4::addr, Ethernet::addr); + /** Cache IP resolution. */ + void cache(IP4::addr, Ethernet::addr); - /** Check if an IP is cached and not expired */ - bool is_valid_cached(IP4::addr); + /** Check if an IP is cached and not expired */ + bool is_valid_cached(IP4::addr); - /** ARP resolution. */ - Ethernet::addr resolve(IP4::addr); + /** ARP resolution. */ + Ethernet::addr resolve(IP4::addr); - void arp_respond(header* hdr_in); + void arp_respond(header* hdr_in); - // two different ARP resolvers - void arp_resolve(Packet_ptr); - void hh_map(Packet_ptr); + // two different ARP resolvers + void arp_resolve(Packet_ptr); + void hh_map(Packet_ptr); - Arp_resolver arp_resolver_ = Arp_resolver::from(*this); + Arp_resolver arp_resolver_ = Arp_resolver::from(*this); - PacketQueue waiting_packets_; + PacketQueue waiting_packets_; - /** Add a packet to waiting queue, to be sent when IP is resolved */ - void await_resolution(Packet_ptr, IP4::addr); + /** Add a packet to waiting queue, to be sent when IP is resolved */ + void await_resolution(Packet_ptr, IP4::addr); - /** Create a default initialized ARP-packet */ - Packet_ptr createPacket(); -}; //< class Arp + /** Create a default initialized ARP-packet */ + Packet_ptr createPacket(); + }; //< class Arp } //< namespace net diff --git a/api/net/buffer_store.hpp b/api/net/buffer_store.hpp index f552f4b31b..c215e5dcd6 100644 --- a/api/net/buffer_store.hpp +++ b/api/net/buffer_store.hpp @@ -25,80 +25,80 @@ namespace net{ -/** - * Network buffer storage for uniformly sized buffers. - * - * @note : The buffer store is intended to be used by Packet, which is - * a semi-intelligent buffer wrapper, used throughout the IP-stack. - * - * There shouldn't be any need for raw buffers in services. - **/ -class BufferStore { -public: - using buffer_t = uint8_t*; - using release_del = delegate; - - BufferStore(size_t num, size_t bufsize, size_t device_offset); - - /** Free all the buffers **/ - ~BufferStore(); - - /** Get a free buffer */ - buffer_t get_raw_buffer(); - - /** Get a free buffer, offset by device-offset */ - buffer_t get_offset_buffer(); - - /** Return a buffer. */ - void release_raw_buffer(buffer_t b, size_t); - - /** Return a buffer, offset by offset_ bytes from actual buffer. */ - void release_offset_buffer(buffer_t b, size_t); - - /** Get size of a raw buffer **/ - inline size_t raw_bufsize() - { return bufsize_; } - - inline size_t offset_bufsize() - { return bufsize_ - device_offset_; } - - /** @return the total buffer capacity in bytes */ - inline size_t capacity() - { return available_buffers_.size() * bufsize_; } - - /** Check if a buffer belongs here */ - inline bool address_is_from_pool(buffer_t addr) - { return addr >= pool_ and addr < pool_ + (bufcount_ * bufsize_); } - - /** Check if an address is the start of a buffer */ - inline bool address_is_bufstart(buffer_t addr) - { return (addr - pool_) % bufsize_ == 0; } - - /** Check if an address is the start of a buffer */ - inline bool address_is_offset_bufstart(buffer_t addr) - { return (addr - pool_ - device_offset_) % bufsize_ == 0; } - - inline size_t buffers_available() - { return available_buffers_.size(); } - -private: - size_t bufcount_; - const size_t bufsize_; - size_t device_offset_; - buffer_t pool_; - std::deque available_buffers_; - - /** Delete move and copy operations **/ - BufferStore(BufferStore&) = delete; - BufferStore(BufferStore&&) = delete; - BufferStore& operator=(BufferStore&) = delete; - BufferStore operator=(BufferStore&&) = delete; - - /** Prohibit default construction **/ - BufferStore() = delete; - - void increaseStorage(); -}; //< class BufferStore + /** + * Network buffer storage for uniformly sized buffers. + * + * @note : The buffer store is intended to be used by Packet, which is + * a semi-intelligent buffer wrapper, used throughout the IP-stack. + * + * There shouldn't be any need for raw buffers in services. + **/ + class BufferStore { + public: + using buffer_t = uint8_t*; + using release_del = delegate; + + BufferStore(size_t num, size_t bufsize, size_t device_offset); + + /** Free all the buffers **/ + ~BufferStore(); + + /** Get a free buffer */ + buffer_t get_raw_buffer(); + + /** Get a free buffer, offset by device-offset */ + buffer_t get_offset_buffer(); + + /** Return a buffer. */ + void release_raw_buffer(buffer_t b, size_t); + + /** Return a buffer, offset by offset_ bytes from actual buffer. */ + void release_offset_buffer(buffer_t b, size_t); + + /** Get size of a raw buffer **/ + inline size_t raw_bufsize() + { return bufsize_; } + + inline size_t offset_bufsize() + { return bufsize_ - device_offset_; } + + /** @return the total buffer capacity in bytes */ + inline size_t capacity() + { return available_buffers_.size() * bufsize_; } + + /** Check if a buffer belongs here */ + inline bool address_is_from_pool(buffer_t addr) + { return addr >= pool_ and addr < pool_ + (bufcount_ * bufsize_); } + + /** Check if an address is the start of a buffer */ + inline bool address_is_bufstart(buffer_t addr) + { return (addr - pool_) % bufsize_ == 0; } + + /** Check if an address is the start of a buffer */ + inline bool address_is_offset_bufstart(buffer_t addr) + { return (addr - pool_ - device_offset_) % bufsize_ == 0; } + + inline size_t buffers_available() + { return available_buffers_.size(); } + + private: + size_t bufcount_; + const size_t bufsize_; + size_t device_offset_; + buffer_t pool_; + std::deque available_buffers_; + + /** Delete move and copy operations **/ + BufferStore(BufferStore&) = delete; + BufferStore(BufferStore&&) = delete; + BufferStore& operator=(BufferStore&) = delete; + BufferStore operator=(BufferStore&&) = delete; + + /** Prohibit default construction **/ + BufferStore() = delete; + + void increaseStorage(); + }; //< class BufferStore } //< namespace net #endif //< NET_BUFFER_STORE_HPP diff --git a/api/net/dns/client.hpp b/api/net/dns/client.hpp index 93b61d59c8..f8b76bdeb6 100644 --- a/api/net/dns/client.hpp +++ b/api/net/dns/client.hpp @@ -30,12 +30,12 @@ namespace net using Stack = Inet; DNSClient(Stack& stk) - : stack(stk) {} + : stack(stk) {} /** * @func a delegate that provides a hostname and its address, which is 0 if the * name @hostname was not found. Note: Test with INADDR_ANY for a 0-address. - **/ + **/ void resolve(IP4::addr dns_server, const std::string& hostname, Stack::resolve_func func); diff --git a/api/net/dns/dns.hpp b/api/net/dns/dns.hpp index d54a11c02a..f15bf3ea22 100644 --- a/api/net/dns/dns.hpp +++ b/api/net/dns/dns.hpp @@ -116,14 +116,14 @@ namespace net #pragma pack(pop) enum resp_code - { - NO_ERROR = 0, - FORMAT_ERROR = 1, - SERVER_FAIL = 2, - NAME_ERROR = 3, - NOT_IMPL = 4, // unimplemented feature - OP_REFUSED = 5, // for political reasons - }; + { + NO_ERROR = 0, + FORMAT_ERROR = 1, + SERVER_FAIL = 2, + NAME_ERROR = 3, + NOT_IMPL = 4, // unimplemented feature + OP_REFUSED = 5, // for political reasons + }; typedef std::function* (const std::string&)> lookup_func; @@ -132,18 +132,18 @@ namespace net static std::string question_string(unsigned short type) { switch (type) - { - case DNS_TYPE_A: - return "IPv4 address"; - case DNS_TYPE_ALIAS: - return "Alias"; - case DNS_TYPE_MX: - return "Mail exchange"; - case DNS_TYPE_NS: - return "Name server"; - default: - return "FIXME DNS::question_string(type = " + std::to_string(type) + ")"; - } + { + case DNS_TYPE_A: + return "IPv4 address"; + case DNS_TYPE_ALIAS: + return "Alias"; + case DNS_TYPE_MX: + return "Mail exchange"; + case DNS_TYPE_NS: + return "Name server"; + default: + return "FIXME DNS::question_string(type = " + std::to_string(type) + ")"; + } } class Request @@ -161,7 +161,7 @@ namespace net { IP4::addr result{{0}}; if (answers.size()) - result = answers[0].getIP4(); + result = answers[0].getIP4(); return result; } diff --git a/api/net/inet.hpp b/api/net/inet.hpp index 198b153d4d..761d64614f 100644 --- a/api/net/inet.hpp +++ b/api/net/inet.hpp @@ -22,54 +22,54 @@ namespace net { -class TCP; -class UDP; -class DHClient; + class TCP; + class UDP; + class DHClient; -/** An abstract IP-stack interface */ -template -class Inet { -public: - using Stack = Inet; + /** An abstract IP-stack interface */ + template + class Inet { + public: + using Stack = Inet; - template - using resolve_func = delegate; + template + using resolve_func = delegate; - virtual typename IPV::addr ip_addr() = 0; - virtual typename IPV::addr netmask() = 0; - virtual typename IPV::addr router() = 0; - virtual typename LINKLAYER::addr link_addr() = 0; + virtual typename IPV::addr ip_addr() = 0; + virtual typename IPV::addr netmask() = 0; + virtual typename IPV::addr router() = 0; + virtual typename LINKLAYER::addr link_addr() = 0; - virtual LINKLAYER& link() = 0; - virtual IPV& ip_obj() = 0; - virtual TCP& tcp() = 0; - virtual UDP& udp() = 0; + virtual LINKLAYER& link() = 0; + virtual IPV& ip_obj() = 0; + virtual TCP& tcp() = 0; + virtual UDP& udp() = 0; - virtual std::shared_ptr dhclient() = 0; + virtual std::shared_ptr dhclient() = 0; - virtual uint16_t MTU() const = 0; + virtual uint16_t MTU() const = 0; - virtual Packet_ptr createPacket(size_t size) = 0; + virtual Packet_ptr createPacket(size_t size) = 0; - virtual void resolve(const std::string& hostname, resolve_func func) = 0; + virtual void resolve(const std::string& hostname, resolve_func func) = 0; - virtual void set_dns_server(typename IPV::addr server) = 0; + virtual void set_dns_server(typename IPV::addr server) = 0; - virtual void network_config(typename IPV::addr ip, - typename IPV::addr nmask, - typename IPV::addr router, - typename IPV::addr dnssrv) = 0; + virtual void network_config(typename IPV::addr ip, + typename IPV::addr nmask, + typename IPV::addr router, + typename IPV::addr dnssrv) = 0; - /** Event triggered when there are available buffers in the transmit queue */ - virtual void on_transmit_queue_available(transmit_avail_delg del) = 0; + /** Event triggered when there are available buffers in the transmit queue */ + virtual void on_transmit_queue_available(transmit_avail_delg del) = 0; - /** Number of packets the transmit queue has room for */ - virtual size_t transmit_queue_available() = 0; + /** Number of packets the transmit queue has room for */ + virtual size_t transmit_queue_available() = 0; - /** Number of buffers available in the bufstore */ - virtual size_t buffers_available() = 0; + /** Number of buffers available in the bufstore */ + virtual size_t buffers_available() = 0; -}; //< class Inet + }; //< class Inet } //< namespace net #endif diff --git a/api/net/inet4.hpp b/api/net/inet4.hpp index 36f0a3db10..83ec392339 100644 --- a/api/net/inet4.hpp +++ b/api/net/inet4.hpp @@ -93,7 +93,7 @@ namespace net { /** * @func a delegate that provides a hostname and its address, which is 0 if the * name @hostname was not found. Note: Test with INADDR_ANY for a 0-address. - **/ + **/ inline virtual void resolve(const std::string& hostname, resolve_func func) override diff --git a/api/net/inet64.hpp b/api/net/inet64.hpp index 471f603762..dc323cc365 100644 --- a/api/net/inet64.hpp +++ b/api/net/inet64.hpp @@ -62,7 +62,7 @@ namespace net { } /// send an UDPv6 packet, hopefully (please dont lie!) std::shared_ptr udp6_create( - Ethernet::addr ether_dest, const IP6::addr& ip_dest, UDPv6::port_t port) + Ethernet::addr ether_dest, const IP6::addr& ip_dest, UDPv6::port_t port) { return _udp6.create(ether_dest, ip_dest, port); } @@ -79,13 +79,13 @@ namespace net { } /** Bind an IP and a netmask to a given device. - The function expects the given device to exist.*/ + The function expects the given device to exist.*/ static void ifconfig( - netdev nic, - IP4::addr ip, - IP4::addr netmask, - IP6::addr ip6); + netdev nic, + IP4::addr ip, + IP4::addr netmask, + IP6::addr ip6); inline static IP4::addr ip4(netdev nic) { return _ip4_list[nic]; } @@ -125,7 +125,7 @@ namespace net { /** Don't think we *want* copy construction. @todo: Fix this with a singleton or something. - */ + */ Inet(Inet& UNUSED(cpy)) = delete; Inet(std::vector ips); diff --git a/api/net/ip4.hpp b/api/net/ip4.hpp index 85905ddadd..4414c88836 100644 --- a/api/net/ip4.hpp +++ b/api/net/ip4.hpp @@ -26,147 +26,147 @@ namespace net { -// Default delegate assignments -void ignore_ip4_up(Packet_ptr); -void ignore_ip4_down(Packet_ptr); + // Default delegate assignments + void ignore_ip4_up(Packet_ptr); + void ignore_ip4_down(Packet_ptr); -/** IP4 layer */ -class IP4 { -public: - /** Initialize. Sets a dummy linklayer out. */ - explicit IP4(Inet&) noexcept; + /** IP4 layer */ + class IP4 { + public: + /** Initialize. Sets a dummy linklayer out. */ + explicit IP4(Inet&) noexcept; - /** Known transport layer protocols. */ - enum proto { IP4_ICMP=1, IP4_UDP=17, IP4_TCP=6 }; + /** Known transport layer protocols. */ + enum proto { IP4_ICMP=1, IP4_UDP=17, IP4_TCP=6 }; - /** IP4 address representation */ - union __attribute__((packed)) addr { - uint8_t part[4]; - uint32_t whole; + /** IP4 address representation */ + union __attribute__((packed)) addr { + uint8_t part[4]; + uint32_t whole; - /** - * NOTE: Constructors - * Can't have them - removes the packed-attribute - */ + /** + * NOTE: Constructors + * Can't have them - removes the packed-attribute + */ - inline addr& operator=(addr cpy) noexcept { - whole = cpy.whole; - return *this; - } + inline addr& operator=(addr cpy) noexcept { + whole = cpy.whole; + return *this; + } - /** Standard comparison operators */ - inline bool operator==(addr rhs) const noexcept - { return whole == rhs.whole; } + /** Standard comparison operators */ + inline bool operator==(addr rhs) const noexcept + { return whole == rhs.whole; } - inline bool operator==(const uint32_t rhs) const noexcept - { return whole == rhs; } + inline bool operator==(const uint32_t rhs) const noexcept + { return whole == rhs; } - inline bool operator<(const addr rhs) const noexcept - { return whole < rhs.whole; } + inline bool operator<(const addr rhs) const noexcept + { return whole < rhs.whole; } - inline bool operator<(const uint32_t rhs) const noexcept - { return whole < rhs; } + inline bool operator<(const uint32_t rhs) const noexcept + { return whole < rhs; } - inline bool operator>(const addr rhs) const noexcept - { return whole > rhs.whole; } + inline bool operator>(const addr rhs) const noexcept + { return whole > rhs.whole; } - inline bool operator>(const uint32_t rhs) const noexcept - { return whole > rhs; } + inline bool operator>(const uint32_t rhs) const noexcept + { return whole > rhs; } - inline bool operator!=(const addr rhs) const noexcept - { return whole != rhs.whole; } + inline bool operator!=(const addr rhs) const noexcept + { return whole != rhs.whole; } - inline bool operator!=(const uint32_t rhs) const noexcept - { return whole != rhs; } + inline bool operator!=(const uint32_t rhs) const noexcept + { return whole != rhs; } - /** x.x.x.x string representation */ - std::string str() const { - char ip_addr[16]; - sprintf(ip_addr, "%1i.%1i.%1i.%1i", - part[0], part[1], part[2], part[3]); - return ip_addr; - } - }; //< union addr + /** x.x.x.x string representation */ + std::string str() const { + char ip_addr[16]; + sprintf(ip_addr, "%1i.%1i.%1i.%1i", + part[0], part[1], part[2], part[3]); + return ip_addr; + } + }; //< union addr - static const addr INADDR_ANY; - static const addr INADDR_BCAST; + static const addr INADDR_ANY; + static const addr INADDR_BCAST; - /** IP4 header representation */ - struct ip_header { - uint8_t version_ihl; - uint8_t tos; - uint16_t tot_len; - uint16_t id; - uint16_t frag_off_flags; - uint8_t ttl; - uint8_t protocol; - uint16_t check; - addr saddr; - addr daddr; - }; + /** IP4 header representation */ + struct ip_header { + uint8_t version_ihl; + uint8_t tos; + uint16_t tot_len; + uint16_t id; + uint16_t frag_off_flags; + uint8_t ttl; + uint8_t protocol; + uint16_t check; + addr saddr; + addr daddr; + }; - /** - * The full header including IP - * - * @Note: This might be removed if we decide to isolate layers more - */ - struct full_header { - uint8_t link_hdr[sizeof(typename LinkLayer::header)]; - ip_header ip_hdr; - }; + /** + * The full header including IP + * + * @Note: This might be removed if we decide to isolate layers more + */ + struct full_header { + uint8_t link_hdr[sizeof(typename LinkLayer::header)]; + ip_header ip_hdr; + }; - /** Upstream: Input from link layer */ - void bottom(Packet_ptr); + /** Upstream: Input from link layer */ + void bottom(Packet_ptr); - /** Upstream: Outputs to transport layer */ - inline void set_icmp_handler(upstream s) - { icmp_handler_ = s; } + /** Upstream: Outputs to transport layer */ + inline void set_icmp_handler(upstream s) + { icmp_handler_ = s; } - inline void set_udp_handler(upstream s) - { udp_handler_ = s; } + inline void set_udp_handler(upstream s) + { udp_handler_ = s; } - inline void set_tcp_handler(upstream s) - { tcp_handler_ = s; } + inline void set_tcp_handler(upstream s) + { tcp_handler_ = s; } - /** Downstream: Delegate linklayer out */ - void set_linklayer_out(downstream s) - { linklayer_out_ = s; }; + /** Downstream: Delegate linklayer out */ + void set_linklayer_out(downstream s) + { linklayer_out_ = s; }; - /** - * Downstream: Receive data from above and transmit - * - * @note: The following *must be set* in the packet: - * - * * Destination IP - * * Protocol - * - * Source IP *can* be set - if it's not, IP4 will set it - */ - void transmit(Packet_ptr); + /** + * Downstream: Receive data from above and transmit + * + * @note: The following *must be set* in the packet: + * + * * Destination IP + * * Protocol + * + * Source IP *can* be set - if it's not, IP4 will set it + */ + void transmit(Packet_ptr); - /** Compute the IP4 header checksum */ - uint16_t checksum(ip_header*); + /** Compute the IP4 header checksum */ + uint16_t checksum(ip_header*); - /** - * \brief - * - * Returns the IPv4 address associated with this interface - **/ - const addr local_ip() const { - return stack_.ip_addr(); - } + /** + * \brief + * + * Returns the IPv4 address associated with this interface + **/ + const addr local_ip() const { + return stack_.ip_addr(); + } -private: - Inet& stack_; + private: + Inet& stack_; - /** Downstream: Linklayer output delegate */ - downstream linklayer_out_ {ignore_ip4_down}; + /** Downstream: Linklayer output delegate */ + downstream linklayer_out_ {ignore_ip4_down}; - /** Upstream delegates */ - upstream icmp_handler_ {ignore_ip4_up}; - upstream udp_handler_ {ignore_ip4_up}; - upstream tcp_handler_ {ignore_ip4_up}; -}; //< class IP4 + /** Upstream delegates */ + upstream icmp_handler_ {ignore_ip4_up}; + upstream udp_handler_ {ignore_ip4_up}; + upstream tcp_handler_ {ignore_ip4_up}; + }; //< class IP4 } //< namespace net #endif diff --git a/api/net/ip4/icmpv4.hpp b/api/net/ip4/icmpv4.hpp index d0787fd783..084f2b0860 100644 --- a/api/net/ip4/icmpv4.hpp +++ b/api/net/ip4/icmpv4.hpp @@ -23,44 +23,44 @@ namespace net { -void icmp_default_out(Packet_ptr); + void icmp_default_out(Packet_ptr); -class ICMPv4 { -public: - // Initialize - ICMPv4(Inet&); + class ICMPv4 { + public: + // Initialize + ICMPv4(Inet&); - // Known ICMP types - enum icmp_types { ICMP_ECHO_REPLY, ICMP_ECHO = 8 }; + // Known ICMP types + enum icmp_types { ICMP_ECHO_REPLY, ICMP_ECHO = 8 }; - struct icmp_header { - uint8_t type; - uint8_t code; - uint16_t checksum; - uint16_t identifier; - uint16_t sequence; - uint8_t payload[0]; - }__attribute__((packed)); + struct icmp_header { + uint8_t type; + uint8_t code; + uint16_t checksum; + uint16_t identifier; + uint16_t sequence; + uint8_t payload[0]; + }__attribute__((packed)); - struct full_header { - LinkLayer::header link_hdr; - IP4::ip_header ip_hdr; - icmp_header icmp_hdr; - }__attribute__((packed)); + struct full_header { + LinkLayer::header link_hdr; + IP4::ip_header ip_hdr; + icmp_header icmp_hdr; + }__attribute__((packed)); - // Input from network layer - void bottom(Packet_ptr); + // Input from network layer + void bottom(Packet_ptr); - // Delegate output to network layer - inline void set_network_out(downstream s) - { network_layer_out_ = s; }; + // Delegate output to network layer + inline void set_network_out(downstream s) + { network_layer_out_ = s; }; -private: - Inet& inet_; - downstream network_layer_out_ {icmp_default_out}; + private: + Inet& inet_; + downstream network_layer_out_ {icmp_default_out}; - void ping_reply(full_header* full_hdr, uint16_t size); -}; //< class ICMPv4 + void ping_reply(full_header* full_hdr, uint16_t size); + }; //< class ICMPv4 } //< namespace net #endif //< NET_IP4_ICMPv4_HPP diff --git a/api/net/ip4/packet_ip4.hpp b/api/net/ip4/packet_ip4.hpp index 7076fce840..918ec77f1d 100644 --- a/api/net/ip4/packet_ip4.hpp +++ b/api/net/ip4/packet_ip4.hpp @@ -25,70 +25,70 @@ namespace net { -class PacketIP4 : public Packet, // might work as upcast: - public std::enable_shared_from_this -{ -public: - static constexpr size_t DEFAULT_TTL {64}; + class PacketIP4 : public Packet, // might work as upcast: + public std::enable_shared_from_this + { + public: + static constexpr size_t DEFAULT_TTL {64}; - const IP4::addr& src() const noexcept - { return ip4_header().saddr; } + const IP4::addr& src() const noexcept + { return ip4_header().saddr; } - void set_src(const IP4::addr& addr) noexcept - { ip4_header().saddr = addr; } + void set_src(const IP4::addr& addr) noexcept + { ip4_header().saddr = addr; } - const IP4::addr& dst() const noexcept - { return ip4_header().daddr; } + const IP4::addr& dst() const noexcept + { return ip4_header().daddr; } - void set_dst(const IP4::addr& addr) noexcept - { ip4_header().daddr = addr; } + void set_dst(const IP4::addr& addr) noexcept + { ip4_header().daddr = addr; } - void set_protocol(IP4::proto p) noexcept - { ip4_header().protocol = p; } + void set_protocol(IP4::proto p) noexcept + { ip4_header().protocol = p; } - uint8_t protocol() const noexcept - { return ip4_header().protocol; } + uint8_t protocol() const noexcept + { return ip4_header().protocol; } - uint16_t ip4_segment_size() const noexcept - { return ntohs(ip4_header().tot_len); } + uint16_t ip4_segment_size() const noexcept + { return ntohs(ip4_header().tot_len); } - /** Last modifications before transmission */ - void make_flight_ready() noexcept { - assert( ip4_header().protocol ); - set_segment_length(); - set_ip4_checksum(); - } + /** Last modifications before transmission */ + void make_flight_ready() noexcept { + assert( ip4_header().protocol ); + set_segment_length(); + set_ip4_checksum(); + } - void init() noexcept { - ip4_header().version_ihl = 0x45; - ip4_header().tos = 0; - ip4_header().id = 0; - ip4_header().frag_off_flags = 0; - ip4_header().ttl = DEFAULT_TTL; - } + void init() noexcept { + ip4_header().version_ihl = 0x45; + ip4_header().tos = 0; + ip4_header().id = 0; + ip4_header().frag_off_flags = 0; + ip4_header().ttl = DEFAULT_TTL; + } -private: - const IP4::ip_header& ip4_header() const noexcept - { return (reinterpret_cast(buffer()))->ip_hdr; } + private: + const IP4::ip_header& ip4_header() const noexcept + { return (reinterpret_cast(buffer()))->ip_hdr; } - IP4::ip_header& ip4_header() noexcept - { return (reinterpret_cast(buffer()))->ip_hdr; } + IP4::ip_header& ip4_header() noexcept + { return (reinterpret_cast(buffer()))->ip_hdr; } - /** - * Set IP4 header length - * - * Inferred from packet size and linklayer header size - */ - void set_segment_length() noexcept - { ip4_header().tot_len = htons(size() - sizeof(LinkLayer::header)); } + /** + * Set IP4 header length + * + * Inferred from packet size and linklayer header size + */ + void set_segment_length() noexcept + { ip4_header().tot_len = htons(size() - sizeof(LinkLayer::header)); } - void set_ip4_checksum() noexcept { - auto& hdr = ip4_header(); - hdr.check = 0; - hdr.check = net::checksum(&hdr, sizeof(IP4::ip_header)); - } + void set_ip4_checksum() noexcept { + auto& hdr = ip4_header(); + hdr.check = 0; + hdr.check = net::checksum(&hdr, sizeof(IP4::ip_header)); + } -}; //< class PacketIP4 + }; //< class PacketIP4 } //< namespace net #endif //< IP4_PACKET_IP4_HPP diff --git a/api/net/ip4/udp.hpp b/api/net/ip4/udp.hpp index be016c3b87..21c6245d6a 100644 --- a/api/net/ip4/udp.hpp +++ b/api/net/ip4/udp.hpp @@ -25,77 +25,77 @@ namespace net { -class PacketUDP; + class PacketUDP; -template -class Socket; + template + class Socket; -void ignore_udp(Packet_ptr); + void ignore_udp(Packet_ptr); -/** Basic UDP support. @todo Implement UDP sockets. */ -class UDP { -public: - using addr_t = IP4::addr; + /** Basic UDP support. @todo Implement UDP sockets. */ + class UDP { + public: + using addr_t = IP4::addr; - /** UDP port number */ - using port_t = uint16_t; + /** UDP port number */ + using port_t = uint16_t; - using Socket = Socket; - using Stack = Inet; + using Socket = Socket; + using Stack = Inet; - /** UDP header */ - struct udp_header { - port_t sport; - port_t dport; - uint16_t length; - uint16_t checksum; - }; + /** UDP header */ + struct udp_header { + port_t sport; + port_t dport; + uint16_t length; + uint16_t checksum; + }; - /** Full UDP Header with all sub-headers */ - struct full_header { - IP4::full_header full_hdr; - udp_header udp_hdr; - }__attribute__((packed)); + /** Full UDP Header with all sub-headers */ + struct full_header { + IP4::full_header full_hdr; + udp_header udp_hdr; + }__attribute__((packed)); - //////////////////////////////////////////// + //////////////////////////////////////////// - inline addr_t local_ip() const - { return stack_.ip_addr(); } + inline addr_t local_ip() const + { return stack_.ip_addr(); } - /** Input from network layer */ - void bottom(Packet_ptr); + /** Input from network layer */ + void bottom(Packet_ptr); - /** Delegate output to network layer */ - inline void set_network_out(downstream del) - { network_layer_out_ = del; } + /** Delegate output to network layer */ + inline void set_network_out(downstream del) + { network_layer_out_ = del; } - /** Send UDP datagram from source ip/port to destination ip/port. + /** Send UDP datagram from source ip/port to destination ip/port. - @param sip Local IP-address - @param sport Local port - @param dip Remote IP-address - @param dport Remote port */ - void transmit(std::shared_ptr udp); + @param sip Local IP-address + @param sport Local port + @param dip Remote IP-address + @param dport Remote port */ + void transmit(std::shared_ptr udp); - //! @param port local port - Socket& bind(port_t port); + //! @param port local port + Socket& bind(port_t port); - //! returns a new UDP socket bound to a random port - Socket& bind(); + //! returns a new UDP socket bound to a random port + Socket& bind(); - //! construct this UDP module with @inet - UDP(Stack& inet) : - network_layer_out_ {ignore_udp}, - stack_ {inet} - { } -private: - downstream network_layer_out_; - Stack& stack_; - std::map ports_; - port_t current_port_ {1024}; + //! construct this UDP module with @inet + UDP(Stack& inet) : + network_layer_out_ {ignore_udp}, + stack_ {inet} + { } + private: + downstream network_layer_out_; + Stack& stack_; + std::map ports_; + port_t current_port_ {1024}; - friend class SocketUDP; -}; //< class UDP + friend class SocketUDP; + }; //< class UDP } //< namespace net #include "packet_udp.hpp" diff --git a/api/net/ip6/icmp6.hpp b/api/net/ip6/icmp6.hpp index eb4d48d0e4..b26d28e5c5 100644 --- a/api/net/ip6/icmp6.hpp +++ b/api/net/ip6/icmp6.hpp @@ -144,6 +144,6 @@ namespace net size_ = sizeof(IP6::full_header) + icmp_len; } - }; + }; } diff --git a/api/net/ip6/ip6.hpp b/api/net/ip6/ip6.hpp index 31db6d09f0..1378c2021d 100644 --- a/api/net/ip6/ip6.hpp +++ b/api/net/ip6/ip6.hpp @@ -43,17 +43,17 @@ namespace net public: /** Known transport layer protocols. */ enum proto - { - PROTO_HOPOPT = 0, // IPv6 hop-by-hop + { + PROTO_HOPOPT = 0, // IPv6 hop-by-hop - PROTO_ICMPv4 = 1, - PROTO_TCP = 6, - PROTO_UDP = 17, + PROTO_ICMPv4 = 1, + PROTO_TCP = 6, + PROTO_UDP = 17, - PROTO_ICMPv6 = 58, // IPv6 ICMP - PROTO_NoNext = 59, // no next-header - PROTO_OPTSv6 = 60, // dest options - }; + PROTO_ICMPv6 = 58, // IPv6 ICMP + PROTO_NoNext = 59, // no next-header + PROTO_OPTSv6 = 60, // dest options + }; struct addr { @@ -64,11 +64,11 @@ namespace net uint16_t c1, uint16_t c2, uint16_t d1, uint16_t d2) { i128 = _mm_set_epi16( - //d2, d1, c2, c1, b2, b1, a2, a1); - htons(d2), htons(d1), - htons(c2), htons(c1), - htons(b2), htons(b1), - htons(a2), htons(a1)); + //d2, d1, c2, c1, b2, b1, a2, a1); + htons(d2), htons(d1), + htons(c2), htons(c1), + htons(b2), htons(b1), + htons(a2), htons(a1)); } addr(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { @@ -121,15 +121,15 @@ namespace net bool is_multicast() const { /** - RFC 4291 2.7 Multicast Addresses + RFC 4291 2.7 Multicast Addresses - An IPv6 multicast address is an identifier for a group of interfaces - (typically on different nodes). An interface may belong to any - number of multicast groups. Multicast addresses have the following format: - | 8 | 4 | 4 | 112 bits | - +------ -+----+----+---------------------------------------------+ - |11111111|flgs|scop| group ID | - +--------+----+----+---------------------------------------------+ + An IPv6 multicast address is an identifier for a group of interfaces + (typically on different nodes). An interface may belong to any + number of multicast groups. Multicast addresses have the following format: + | 8 | 4 | 4 | 112 bits | + +------ -+----+----+---------------------------------------------+ + |11111111|flgs|scop| group ID | + +--------+----+----+---------------------------------------------+ **/ return i8[0] == 0xFF; } @@ -142,7 +142,7 @@ namespace net }; } __attribute__((aligned(alignof(__m128i)))); - #pragma pack(push, 1) +#pragma pack(push, 1) class header { public: @@ -153,7 +153,7 @@ namespace net uint8_t tclass() const { return ((scanline[0] & 0xF000) >> 12) + - (scanline[0] & 0xF); + (scanline[0] & 0xF); } // initializes the first scanline with the IPv6 version void init_scan0() @@ -164,7 +164,7 @@ namespace net uint16_t size() const { return ((scanline[1] & 0x00FF) << 8) + - ((scanline[1] & 0xFF00) >> 8); + ((scanline[1] & 0xFF00) >> 8); } void set_size(uint16_t newsize) { @@ -218,7 +218,7 @@ namespace net return hdr_ext_len; } }; - #pragma pack(pop) +#pragma pack(pop) struct full_header { @@ -243,25 +243,25 @@ namespace net static std::string protocol_name(uint8_t protocol) { switch (protocol) - { - case PROTO_HOPOPT: - return "IPv6 Hop-By-Hop (0)"; + { + case PROTO_HOPOPT: + return "IPv6 Hop-By-Hop (0)"; - case PROTO_TCP: - return "TCPv6 (6)"; - case PROTO_UDP: - return "UDPv6 (17)"; + case PROTO_TCP: + return "TCPv6 (6)"; + case PROTO_UDP: + return "UDPv6 (17)"; - case PROTO_ICMPv6: - return "ICMPv6 (58)"; - case PROTO_NoNext: - return "No next header (59)"; - case PROTO_OPTSv6: - return "IPv6 destination options (60)"; + case PROTO_ICMPv6: + return "ICMPv6 (58)"; + case PROTO_NoNext: + return "No next header (59)"; + case PROTO_OPTSv6: + return "IPv6 destination options (60)"; - default: - return "Unknown: " + std::to_string(protocol); - } + default: + return "Unknown: " + std::to_string(protocol); + } } // handler for upstream IPv6 packets @@ -283,7 +283,7 @@ namespace net // creates a new IPv6 packet to be sent over the ether static std::shared_ptr create(uint8_t proto, - Ethernet::addr ether_dest, const IP6::addr& dest); + Ethernet::addr ether_dest, const IP6::addr& dest); private: addr local; diff --git a/api/net/ip6/udp6.hpp b/api/net/ip6/udp6.hpp index 66ac4ec510..30ca33a5f8 100644 --- a/api/net/ip6/udp6.hpp +++ b/api/net/ip6/udp6.hpp @@ -72,7 +72,7 @@ namespace net // creates a new packet to be sent over the ether std::shared_ptr create( - Ethernet::addr ether_dest, const IP6::addr& dest, port_t port); + Ethernet::addr ether_dest, const IP6::addr& dest, port_t port); private: std::map listeners; @@ -125,7 +125,7 @@ namespace net header().length = htons(sizeof(UDPv6::header) + newlen); // new total IPv6 payload length ip6_header().set_size( - sizeof(IP6::header) + sizeof(UDPv6::header) + newlen); + sizeof(IP6::header) + sizeof(UDPv6::header) + newlen); // new total packet length size_ = sizeof(IP6::full_header) + sizeof(UDPv6::header) + newlen; } diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index 00973a4bdb..f545e8d095 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -29,344 +29,344 @@ #include // enable_shared_from_this inline unsigned round_up(unsigned n, unsigned div) { - assert(n); - return (n + div - 1) / div; + assert(n); + return (n + div - 1) / div; } namespace net { -class TCP { -public: - using Address = IP4::addr; - using Port = uint16_t; - /* - A Sequence number (SYN/ACK) (32 bits) - */ - using Seq = uint32_t; + class TCP { + public: + using Address = IP4::addr; + using Port = uint16_t; + /* + A Sequence number (SYN/ACK) (32 bits) + */ + using Seq = uint32_t; - using buffer_t = std::shared_ptr; + using buffer_t = std::shared_ptr; - class Packet; - using Packet_ptr = std::shared_ptr; + class Packet; + using Packet_ptr = std::shared_ptr; - class TCPException; - class TCPBadOptionException; + class TCPException; + class TCPBadOptionException; - class Connection; - using Connection_ptr = std::shared_ptr; - using IPStack = Inet; + class Connection; + using Connection_ptr = std::shared_ptr; + using IPStack = Inet; -public: - /* - An IP address and a Port. - */ - class Socket { - public: - /* - Intialize an empty socket. - */ - inline Socket() : address_(), port_(0) { address_.whole = 0; }; - - /* - Create a socket with a Address and Port. - */ - inline Socket(Address address, Port port) : address_(address), port_(port) {}; - - /* - Returns the Socket's address. - */ - inline const TCP::Address address() const { return address_; } - - /* - Returns the Socket's port. - */ - inline TCP::Port port() const { return port_; } - - /* - Returns a string in the format "Address:Port". - */ - std::string to_string() const { - std::stringstream ss; - ss << address_.str() << ":" << port_; - return ss.str(); - } - - inline bool is_empty() const { return (address_.whole == 0 and port_ == 0); } - - /* - Comparator used for vector. - */ - inline bool operator ==(const Socket &s2) const { - return address().whole == s2.address().whole - and port() == s2.port(); - } - - /* - Comparator used for map. - */ - inline bool operator <(const Socket& s2) const { - return address().whole < s2.address().whole - or (address().whole == s2.address().whole and port() < s2.port()); - } - - private: - //SocketID id_; // Maybe a hash or something. Not sure if needed (yet) - TCP::Address address_; - TCP::Port port_; - - }; // << class TCP::Socket - - - /////// TCP Stuff - Relevant to the protocol ///// - - static constexpr uint16_t default_window_size = 0xffff; - - static constexpr uint16_t default_mss = 536; + public: + /* + An IP address and a Port. + */ + class Socket { + public: + /* + Intialize an empty socket. + */ + inline Socket() : address_(), port_(0) { address_.whole = 0; }; - /* - Flags (Control bits) in the TCP Header. - */ - enum Flag { - NS = (1 << 8), // Nounce (Experimental: see RFC 3540) - CWR = (1 << 7), // Congestion Window Reduced - ECE = (1 << 6), // ECN-Echo - URG = (1 << 5), // Urgent - ACK = (1 << 4), // Acknowledgement - PSH = (1 << 3), // Push - RST = (1 << 2), // Reset - SYN = (1 << 1), // Syn(chronize) - FIN = 1, // Fin(ish) + /* + Create a socket with a Address and Port. + */ + inline Socket(Address address, Port port) : address_(address), port_(port) {}; + + /* + Returns the Socket's address. + */ + inline const TCP::Address address() const { return address_; } + + /* + Returns the Socket's port. + */ + inline TCP::Port port() const { return port_; } + + /* + Returns a string in the format "Address:Port". + */ + std::string to_string() const { + std::stringstream ss; + ss << address_.str() << ":" << port_; + return ss.str(); + } + + inline bool is_empty() const { return (address_.whole == 0 and port_ == 0); } + + /* + Comparator used for vector. + */ + inline bool operator ==(const Socket &s2) const { + return address().whole == s2.address().whole + and port() == s2.port(); + } + + /* + Comparator used for map. + */ + inline bool operator <(const Socket& s2) const { + return address().whole < s2.address().whole + or (address().whole == s2.address().whole and port() < s2.port()); + } + + private: + //SocketID id_; // Maybe a hash or something. Not sure if needed (yet) + TCP::Address address_; + TCP::Port port_; + + }; // << class TCP::Socket + + + /////// TCP Stuff - Relevant to the protocol ///// + + static constexpr uint16_t default_window_size = 0xffff; + + static constexpr uint16_t default_mss = 536; + + /* + Flags (Control bits) in the TCP Header. + */ + enum Flag { + NS = (1 << 8), // Nounce (Experimental: see RFC 3540) + CWR = (1 << 7), // Congestion Window Reduced + ECE = (1 << 6), // ECN-Echo + URG = (1 << 5), // Urgent + ACK = (1 << 4), // Acknowledgement + PSH = (1 << 3), // Push + RST = (1 << 2), // Reset + SYN = (1 << 1), // Syn(chronize) + FIN = 1, // Fin(ish) }; /* - Representation of the TCP Header. - - RFC 793, (p.15): - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Source Port | Destination Port | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Sequence Number | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Acknowledgment Number | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Data | |U|A|P|R|S|F| | - | Offset| Reserved |R|C|S|S|Y|I| Window | - | | |G|K|H|T|N|N| | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Checksum | Urgent Pointer | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Options | Padding | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | data | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + Representation of the TCP Header. + + RFC 793, (p.15): + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Source Port | Destination Port | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Sequence Number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Acknowledgment Number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Data | |U|A|P|R|S|F| | + | Offset| Reserved |R|C|S|S|Y|I| Window | + | | |G|K|H|T|N|N| | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Checksum | Urgent Pointer | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Options | Padding | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | data | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ - struct Header { - TCP::Port source_port; // Source port - TCP::Port destination_port; // Destination port - uint32_t seq_nr; // Sequence number - uint32_t ack_nr; // Acknowledge number - union { - uint16_t whole; // Reference to offset_reserved & flags together. - struct { - uint8_t offset_reserved; // Offset (4 bits) + Reserved (3 bits) + NS (1 bit) - uint8_t flags; // All Flags (Control bits) except NS (9 bits - 1 bit) - }; - } offset_flags; // Data offset + Reserved + Flags (16 bits) - uint16_t window_size; // Window size - uint16_t checksum; // Checksum - uint16_t urgent; // Urgent pointer offset - uint8_t options[0]; // Options - }__attribute__((packed)); // << struct TCP::Header + struct Header { + TCP::Port source_port; // Source port + TCP::Port destination_port; // Destination port + uint32_t seq_nr; // Sequence number + uint32_t ack_nr; // Acknowledge number + union { + uint16_t whole; // Reference to offset_reserved & flags together. + struct { + uint8_t offset_reserved; // Offset (4 bits) + Reserved (3 bits) + NS (1 bit) + uint8_t flags; // All Flags (Control bits) except NS (9 bits - 1 bit) + }; + } offset_flags; // Data offset + Reserved + Flags (16 bits) + uint16_t window_size; // Window size + uint16_t checksum; // Checksum + uint16_t urgent; // Urgent pointer offset + uint8_t options[0]; // Options + }__attribute__((packed)); // << struct TCP::Header - /* - TCP Pseudo header, for checksum calculation - */ - struct Pseudo_header { - IP4::addr saddr; - IP4::addr daddr; - uint8_t zero; - uint8_t proto; - uint16_t tcp_length; - }__attribute__((packed)); + /* + TCP Pseudo header, for checksum calculation + */ + struct Pseudo_header { + IP4::addr saddr; + IP4::addr daddr; + uint8_t zero; + uint8_t proto; + uint16_t tcp_length; + }__attribute__((packed)); - /* - TCP Checksum-header (TCP-header + pseudo-header) - */ - struct Checksum_header { - TCP::Pseudo_header pseudo; - TCP::Header tcp; - }__attribute__((packed)); + /* + TCP Checksum-header (TCP-header + pseudo-header) + */ + struct Checksum_header { + TCP::Pseudo_header pseudo; + TCP::Header tcp; + }__attribute__((packed)); - /* - To extract the TCP part from a Packet_ptr and calculate size. (?) - */ - struct Full_header { - Ethernet::header ethernet; - IP4::ip_header ip4; - TCP::Header tcp; - }__attribute__((packed)); + /* + To extract the TCP part from a Packet_ptr and calculate size. (?) + */ + struct Full_header { + Ethernet::header ethernet; + IP4::ip_header ip4; + TCP::Header tcp; + }__attribute__((packed)); - /* - TCP Header Option - */ - struct Option { - uint8_t kind; - uint8_t length; - uint8_t data[0]; - - enum Kind { - END = 0x00, // End of option list - NOP = 0x01, // No-Opeartion - MSS = 0x02, // Maximum Segment Size [RFC 793] Rev: [879, 6691] - }; - - static std::string kind_string(Kind kind) { - switch(kind) { - case MSS: - return {"MSS"}; - - default: - return {"Unknown Option"}; - } - } - - struct opt_mss { - uint8_t kind; - uint8_t length; - uint16_t mss; - - opt_mss(uint16_t mss) - : kind(MSS), length(4), mss(htons(mss)) {} - }; - - struct opt_timestamp { - uint8_t kind; - uint8_t length; - uint32_t ts_val; - uint32_t ts_ecr; - }; - }; + /* + TCP Header Option + */ + struct Option { + uint8_t kind; + uint8_t length; + uint8_t data[0]; + + enum Kind { + END = 0x00, // End of option list + NOP = 0x01, // No-Opeartion + MSS = 0x02, // Maximum Segment Size [RFC 793] Rev: [879, 6691] + }; + + static std::string kind_string(Kind kind) { + switch(kind) { + case MSS: + return {"MSS"}; + + default: + return {"Unknown Option"}; + } + } + struct opt_mss { + uint8_t kind; + uint8_t length; + uint16_t mss; + + opt_mss(uint16_t mss) + : kind(MSS), length(4), mss(htons(mss)) {} + }; + + struct opt_timestamp { + uint8_t kind; + uint8_t length; + uint32_t ts_val; + uint32_t ts_ecr; + }; + }; - /* - A Wrapper for a TCP Packet. Is everything as a IP4 Packet, - in addition to the TCP Header and functions to modify this and the control bits (FLAGS). - */ - class Packet : public PacketIP4 { - public: - inline TCP::Header& header() const - { - return ((TCP::Full_header*) buffer())->tcp; - } + /* + A Wrapper for a TCP Packet. Is everything as a IP4 Packet, + in addition to the TCP Header and functions to modify this and the control bits (FLAGS). + */ + class Packet : public PacketIP4 { + public: + + inline TCP::Header& header() const + { + return ((TCP::Full_header*) buffer())->tcp; + } - static const size_t HEADERS_SIZE = sizeof(TCP::Full_header); + static const size_t HEADERS_SIZE = sizeof(TCP::Full_header); - //! initializes to a default, empty TCP packet, given - //! a valid MTU-sized buffer - void init() - { - // Erase all headers (smart? necessary? ...well, convenient) - memset(buffer(), 0, HEADERS_SIZE); - PacketIP4::init(); + //! initializes to a default, empty TCP packet, given + //! a valid MTU-sized buffer + void init() + { + // Erase all headers (smart? necessary? ...well, convenient) + memset(buffer(), 0, HEADERS_SIZE); + PacketIP4::init(); - set_protocol(IP4::IP4_TCP); - set_win_size(TCP::default_window_size); - set_offset(5); + set_protocol(IP4::IP4_TCP); + set_win_size(TCP::default_window_size); + set_offset(5); - // set TCP payload location (!?) - set_payload(buffer() + all_headers_len()); - } + // set TCP payload location (!?) + set_payload(buffer() + all_headers_len()); + } - // GETTERS - inline TCP::Port src_port() const { return ntohs(header().source_port); } + // GETTERS + inline TCP::Port src_port() const { return ntohs(header().source_port); } - inline TCP::Port dst_port() const { return ntohs(header().destination_port); } + inline TCP::Port dst_port() const { return ntohs(header().destination_port); } - inline TCP::Seq seq() const { return ntohl(header().seq_nr); } + inline TCP::Seq seq() const { return ntohl(header().seq_nr); } - inline TCP::Seq ack() const { return ntohl(header().ack_nr); } + inline TCP::Seq ack() const { return ntohl(header().ack_nr); } - inline uint16_t win() const { return ntohs(header().window_size); } + inline uint16_t win() const { return ntohs(header().window_size); } - inline TCP::Socket source() const { return TCP::Socket{src(), src_port()}; } + inline TCP::Socket source() const { return TCP::Socket{src(), src_port()}; } - inline TCP::Socket destination() const { return TCP::Socket{dst(), dst_port()}; } + inline TCP::Socket destination() const { return TCP::Socket{dst(), dst_port()}; } - // SETTERS - inline TCP::Packet& set_src_port(TCP::Port p) { - header().source_port = htons(p); - return *this; - } + // SETTERS + inline TCP::Packet& set_src_port(TCP::Port p) { + header().source_port = htons(p); + return *this; + } - inline TCP::Packet& set_dst_port(TCP::Port p) { - header().destination_port = htons(p); - return *this; - } + inline TCP::Packet& set_dst_port(TCP::Port p) { + header().destination_port = htons(p); + return *this; + } - inline TCP::Packet& set_seq(TCP::Seq n) { - header().seq_nr = htonl(n); - return *this; - } + inline TCP::Packet& set_seq(TCP::Seq n) { + header().seq_nr = htonl(n); + return *this; + } - inline TCP::Packet& set_ack(TCP::Seq n) { - header().ack_nr = htonl(n); - return *this; - } + inline TCP::Packet& set_ack(TCP::Seq n) { + header().ack_nr = htonl(n); + return *this; + } - inline TCP::Packet& set_win_size(uint16_t size) { - header().window_size = htons(size); - return *this; - } + inline TCP::Packet& set_win_size(uint16_t size) { + header().window_size = htons(size); + return *this; + } - inline TCP::Packet& set_checksum(uint16_t checksum) { - header().checksum = checksum; - return *this; - } + inline TCP::Packet& set_checksum(uint16_t checksum) { + header().checksum = checksum; + return *this; + } - inline TCP::Packet& set_source(const TCP::Socket& src) { - set_src(src.address()); // PacketIP4::set_src - set_src_port(src.port()); - return *this; - } + inline TCP::Packet& set_source(const TCP::Socket& src) { + set_src(src.address()); // PacketIP4::set_src + set_src_port(src.port()); + return *this; + } - inline TCP::Packet& set_destination(const TCP::Socket& dest) { - set_dst(dest.address()); // PacketIP4::set_dst - set_dst_port(dest.port()); - return *this; - } + inline TCP::Packet& set_destination(const TCP::Socket& dest) { + set_dst(dest.address()); // PacketIP4::set_dst + set_dst_port(dest.port()); + return *this; + } - /// FLAGS / CONTROL BITS /// + /// FLAGS / CONTROL BITS /// - inline TCP::Packet& set_flag(TCP::Flag f) { - header().offset_flags.whole |= htons(f); - return *this; - } + inline TCP::Packet& set_flag(TCP::Flag f) { + header().offset_flags.whole |= htons(f); + return *this; + } - inline TCP::Packet& set_flags(uint16_t f) { - header().offset_flags.whole |= htons(f); - return *this; - } + inline TCP::Packet& set_flags(uint16_t f) { + header().offset_flags.whole |= htons(f); + return *this; + } - inline TCP::Packet& clear_flag(TCP::Flag f) { - header().offset_flags.whole &= ~ htons(f); - return *this; - } + inline TCP::Packet& clear_flag(TCP::Flag f) { + header().offset_flags.whole &= ~ htons(f); + return *this; + } - inline TCP::Packet& clear_flags() { - header().offset_flags.whole &= 0x00ff; - return *this; - } + inline TCP::Packet& clear_flags() { + header().offset_flags.whole &= 0x00ff; + return *this; + } - inline bool isset(TCP::Flag f) { return ntohs(header().offset_flags.whole) & f; } + inline bool isset(TCP::Flag f) { return ntohs(header().offset_flags.whole) & f; } - /// OFFSET, OPTIONS, DATA /// + /// OFFSET, OPTIONS, DATA /// - // Get the raw tcp offset, in quadruples + // Get the raw tcp offset, in quadruples inline uint8_t offset() const { return (uint8_t)(header().offset_flags.offset_reserved >> 4); } // Set raw TCP offset in quadruples @@ -406,1069 +406,1069 @@ class TCP { set_length(); // update } - inline uint8_t* options() { return (uint8_t*) header().options; } - - inline uint8_t options_length() const { return header_size() - sizeof(TCP::Header); } - - inline bool has_options() const { return options_length() > 0; } - - // sets the correct length for all the protocols up to IP4 - void set_length(uint16_t newlen = 0) { - // new total packet length - set_size( all_headers_len() + newlen ); - } - - //! assuming the packet has been properly initialized, - //! this will fill bytes from @buffer into this packets buffer, - //! then return the number of bytes written. buffer is unmodified - size_t fill(const char* buffer, size_t length) { - size_t rem = capacity() - all_headers_len(); - size_t total = (length < rem) ? length : rem; - // copy from buffer to packet buffer - memcpy(data() + data_length(), buffer, total); - // set new packet length - set_length(data_length() + total); - return total; - } - - inline std::string to_string() { - std::ostringstream os; - os << "[ S:" << source().to_string() << " D:" << destination().to_string() - << " SEQ:" << seq() << " ACK:" << ack() - << " HEAD-LEN:" << (int)header_size() << " OPT-LEN:" << (int)options_length() << " DATA-LEN:" << data_length() - << " WIN:" << win() << " FLAGS:" << std::bitset<8>{header().offset_flags.flags} << " ]"; - return os.str(); - } - - }; // << class TCP::Packet - - /* - TODO: Does this need to be better? (faster? stronger?) - */ - class TCPException : public std::runtime_error { - public: - TCPException(const std::string& error) : std::runtime_error(error) {}; - virtual ~TCPException() {}; - }; - - /* - Exception for Bad TCP Header Option (TCP::Option) - */ - class TCPBadOptionException : public TCPException { - public: - TCPBadOptionException(Option::Kind kind, const std::string& error) : - TCPException("Bad Option [" + Option::kind_string(kind) + "]: " + error), - kind_(kind) {}; - - Option::Kind kind(); - private: - Option::Kind kind_; - }; - - /* - A connection between two Sockets (local and remote). - Receives and handle TCP::Packet. - Transist between many states. - */ - class Connection : public std::enable_shared_from_this { - friend class TCP; - public: - - /* - Wrapper around a buffer that receives data. - */ - struct ReadBuffer { - buffer_t buffer; - size_t remaining; - size_t offset; - bool push; - - ReadBuffer(buffer_t buf, size_t length, size_t offs = 0) - : buffer(buf), remaining(length-offs), offset(offs), push(false) {} - - inline size_t capacity() const { return remaining + offset; } - - inline bool empty() const { return offset == 0; } - - inline bool full() const { return remaining == 0; } - - inline size_t size() const { return offset; } + inline uint8_t* options() { return (uint8_t*) header().options; } - inline uint8_t* begin() const { return buffer.get(); } + inline uint8_t options_length() const { return header_size() - sizeof(TCP::Header); } - inline uint8_t* pos() const { return buffer.get() + offset; } + inline bool has_options() const { return options_length() > 0; } - inline uint8_t* end() const { return buffer.get() + capacity(); } - - inline bool advance(size_t length) { - assert(length <= remaining); - offset += length; - remaining -= length; - return length > 0; + // sets the correct length for all the protocols up to IP4 + void set_length(uint16_t newlen = 0) { + // new total packet length + set_size( all_headers_len() + newlen ); } - inline size_t add(uint8_t* data, size_t n) { - auto written = std::min(n, remaining); - memcpy(pos(), data, written); - return written; + //! assuming the packet has been properly initialized, + //! this will fill bytes from @buffer into this packets buffer, + //! then return the number of bytes written. buffer is unmodified + size_t fill(const char* buffer, size_t length) { + size_t rem = capacity() - all_headers_len(); + size_t total = (length < rem) ? length : rem; + // copy from buffer to packet buffer + memcpy(data() + data_length(), buffer, total); + // set new packet length + set_length(data_length() + total); + return total; } - inline void clear() { - memset(begin(), 0, offset); - remaining = capacity(); - offset = 0; - push = false; + inline std::string to_string() { + std::ostringstream os; + os << "[ S:" << source().to_string() << " D:" << destination().to_string() + << " SEQ:" << seq() << " ACK:" << ack() + << " HEAD-LEN:" << (int)header_size() << " OPT-LEN:" << (int)options_length() << " DATA-LEN:" << data_length() + << " WIN:" << win() << " FLAGS:" << std::bitset<8>{header().offset_flags.flags} << " ]"; + return os.str(); } - }; // < Connection::ReadBuffer + }; // << class TCP::Packet /* - Wrapper around a buffer that contains data to be written. + TODO: Does this need to be better? (faster? stronger?) */ - struct WriteBuffer { - buffer_t buffer; - size_t remaining; - size_t offset; - bool push; - - WriteBuffer(buffer_t buf, size_t length, bool PSH, size_t offs = 0) - : buffer(buf), remaining(length-offs), offset(offs), push(PSH) {} - - inline size_t length() const { return remaining + offset; } - - inline bool done() const { return remaining == 0; } - - inline uint8_t* begin() const { return buffer.get(); } - - inline uint8_t* pos() const { return buffer.get() + offset; } - - inline uint8_t* end() const { return buffer.get() + length(); } - - inline bool advance(size_t length) { - assert(length <= remaining); - offset += length; - remaining -= length; - return length > 0; - } - }; // < Connection::WriteBuffer + class TCPException : public std::runtime_error { + public: + TCPException(const std::string& error) : std::runtime_error(error) {}; + virtual ~TCPException() {}; + }; /* - Callback when a receive buffer receives either push or is full - - Supplied on asynchronous read + Exception for Bad TCP Header Option (TCP::Option) */ - using ReadCallback = delegate; - - struct ReadRequest { - ReadBuffer buffer; - ReadCallback callback; - - ReadRequest(ReadBuffer buf, ReadCallback cb) : buffer(buf), callback(cb) {} - ReadRequest(size_t n = 0) : - buffer(buffer_t(new uint8_t[n], std::default_delete()), n), - callback([](auto, auto){}) {} + class TCPBadOptionException : public TCPException { + public: + TCPBadOptionException(Option::Kind kind, const std::string& error) : + TCPException("Bad Option [" + Option::kind_string(kind) + "]: " + error), + kind_(kind) {}; + + Option::Kind kind(); + private: + Option::Kind kind_; }; /* - Callback when a write is sent by the TCP - - Supplied on asynchronous write + A connection between two Sockets (local and remote). + Receives and handle TCP::Packet. + Transist between many states. */ - using WriteCallback = delegate; - - using WriteRequest = std::pair; - - /* - Connection identifier - */ - using Tuple = std::pair; - - /// CALLBACKS /// - /* - On connection attempt - When a remote sends SYN to connection in LISTENING state. - First thing that will happen. - */ - using AcceptCallback = delegate)>; - - /* - On connected - When both hosts exchanged sequence numbers (handshake is done). - Now in ESTABLISHED state - it's allowed to write and read to/from the remote. - */ - using ConnectCallback = delegate)>; - - /* - On disconnect - When a remote told it wanna close the connection. - Connection has received a FIN, currently last thing that will happen before a connection is remoed. - */ - struct Disconnect; - - using DisconnectCallback = delegate, Disconnect)>; - - /* - On error - When any of the users request fails. - */ - using ErrorCallback = delegate, TCPException)>; - - /* - When a packet is received - Everytime a connection receives an incoming packet. - Would probably be used for debugging. - (Currently not in use) - */ - using PacketReceivedCallback = delegate, TCP::Packet_ptr)>; - - /* - When a packet is dropped - Everytime an incoming packet is unallowed, it will be dropped. - Can be used for debugging. - */ - using PacketDroppedCallback = delegate; - - - /* - Reason for disconnect event. - */ - struct Disconnect { - public: - enum Reason { - CLOSING, - REFUSED, - RESET - }; - - Reason reason; - - explicit Disconnect(Reason reason) : reason(reason) {} - - inline operator Reason() const noexcept { return reason; } - - inline operator std::string() const noexcept { return to_string(); } - - inline bool operator ==(const Disconnect& dc) const { return reason == dc.reason; } - - std::string to_string() const { - switch(reason) { - case CLOSING: - return "Connection closing"; - case REFUSED: - return "Conneciton refused"; - case RESET: - return "Connection reset"; - default: - return "Unknown reason"; - } - } - }; // < struct TCP::Connection::Disconnect - - /* - Interface for one of the many states a Connection can have. - */ - class State { - public: - enum Result { - CLOSED = -1, - OK = 0, - CLOSE = 1 - }; - /* - Open a Connection. - OPEN - */ - virtual void open(Connection&, bool active = false); - - /* - Write to a Connection. - SEND - */ - virtual size_t send(Connection&, WriteBuffer&); - - /* - Read from a Connection. - RECEIVE - */ - virtual void receive(Connection&, ReadBuffer&); - - /* - Close a Connection. - CLOSE - */ - virtual void close(Connection&); - - /* - Terminate a Connection. - ABORT - */ - virtual void abort(Connection&); - - /* - Handle a Packet - SEGMENT ARRIVES - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) = 0; - - /* - The current state represented as a string. - STATUS - */ - virtual std::string to_string() const = 0; - - /* - - */ - virtual bool is_connected() const { return false; } - - virtual bool is_writable() const { return false; } - - virtual bool is_readable() const { return false; } - - virtual bool is_closing() const { return false; } - - protected: - /* - Helper functions - TODO: Clean up names. - */ - virtual bool check_seq(Connection&, TCP::Packet_ptr); - - virtual void unallowed_syn_reset_connection(Connection&, TCP::Packet_ptr); - - virtual bool check_ack(Connection&, TCP::Packet_ptr); - - virtual void process_segment(Connection&, TCP::Packet_ptr); - - virtual void process_fin(Connection&, TCP::Packet_ptr); - - virtual void send_reset(Connection&); - - }; // < class TCP::Connection::State - - /* - Forward declaration of concrete states. - Definition in "tcp_connection_states.hpp" - */ - class Closed; - class Listen; - class SynSent; - class SynReceived; - class Established; - class FinWait1; - class FinWait2; - class CloseWait; - class Closing; - class LastAck; - class TimeWait; - - /* - Transmission Control Block. - Keep tracks of all the data for a connection. - - RFC 793: Page 19 - Among the variables stored in the - TCB are the local and remote socket numbers, the security and - precedence of the connection, pointers to the user's send and receive - buffers, pointers to the retransmit queue and to the current segment. - In addition several variables relating to the send and receive - sequence numbers are stored in the TCB. - */ - struct TCB { - /* Send Sequence Variables */ - struct { - TCP::Seq UNA; // send unacknowledged - TCP::Seq NXT; // send next - uint16_t WND; // send window - uint16_t UP; // send urgent pointer - TCP::Seq WL1; // segment sequence number used for last window update - TCP::Seq WL2; // segment acknowledgment number used for last window update - - uint16_t MSS; // Maximum segment size for outgoing segments. - } SND; // << - TCP::Seq ISS; // initial send sequence number - - /* Receive Sequence Variables */ - struct { - TCP::Seq NXT; // receive next - uint16_t WND; // receive window - uint16_t UP; // receive urgent pointer - } RCV; // << - TCP::Seq IRS; // initial receive sequence number - - TCB() { - SND = { 0, 0, TCP::default_window_size, 0, 0, 0, TCP::default_mss }; - ISS = 0; - RCV = { 0, TCP::default_window_size, 0 }; - IRS = 0; - }; - - std::string to_string() const; - }__attribute__((packed)); // < struct TCP::Connection::TCB - - /* - Creates a connection without a remote. - */ - Connection(TCP& host, Port local_port); - - /* - Creates a connection with a remote. - */ - Connection(TCP& host, Port local_port, Socket remote); - - /* - The hosting TCP instance. - */ - inline const TCP& host() const { return host_; } - - /* - The local Socket bound to this connection. - */ - inline TCP::Socket local() const { return {host_.inet_.ip_addr(), local_port_}; } - - /* - The remote Socket bound to this connection. - */ - inline TCP::Socket remote() const { return remote_; } - - /* - Set remote Socket bound to this connection. - @WARNING: Should this be public? Used by TCP. - */ - inline void set_remote(Socket remote) { remote_ = remote; } + class Connection : public std::enable_shared_from_this { + friend class TCP; + public: + /* + Wrapper around a buffer that receives data. + */ + struct ReadBuffer { + buffer_t buffer; + size_t remaining; + size_t offset; + bool push; - /* - Read asynchronous from a remote. + ReadBuffer(buffer_t buf, size_t length, size_t offs = 0) + : buffer(buf), remaining(length-offs), offset(offs), push(false) {} - Create n sized internal read buffer and callback for when data is received. - Callback will be called until overwritten with a new read() or connection closes. - Buffer is cleared for data after every reset. - */ - inline void read(size_t n, ReadCallback callback) { - ReadBuffer buffer = {buffer_t(new uint8_t[n], std::default_delete()), n}; - read(buffer, callback); - } + inline size_t capacity() const { return remaining + offset; } - /* - Assign the connections receive buffer and callback for when data is received. - Works as read(size_t, ReadCallback); - */ - inline void read(buffer_t buffer, size_t n, ReadCallback callback) { - read({buffer, n}, callback); - } + inline bool empty() const { return offset == 0; } - void read(ReadBuffer buffer, ReadCallback callback); + inline bool full() const { return remaining == 0; } + inline size_t size() const { return offset; } - /* - Write asynchronous to a remote. + inline uint8_t* begin() const { return buffer.get(); } - Copies the data from the buffer into an internal buffer. Callback is called when a a write is either done or aborted. - Immediately tries to write the data to the connection. If not possible, queues the write for processing when possible (FIFO). - */ - inline void write(const void* buf, size_t n, WriteCallback callback, bool PUSH = true) { - auto buffer = buffer_t(new uint8_t[n], std::default_delete()); - memcpy(buffer.get(), buf, n); - write(buffer, n, callback, PUSH); - } + inline uint8_t* pos() const { return buffer.get() + offset; } - /* - Works as write(const void*, size_t, WriteCallback, bool), - but with the exception of avoiding copying the data to an internal buffer. - */ - inline void write(buffer_t buffer, size_t n, WriteCallback callback, bool PUSH = true) { - write({buffer, n, PUSH}, callback); - } + inline uint8_t* end() const { return buffer.get() + capacity(); } - /* - Works the same as it's counterpart, without subscribing to a WriteCallback. - */ - inline void write(const void* buf, size_t n, bool PUSH = true) { - write(buf, n, [](auto){}, PUSH); - } + inline bool advance(size_t length) { + assert(length <= remaining); + offset += length; + remaining -= length; + return length > 0; + } - /* - Works the same as it's counterpart, without subscribing to a WriteCallback. - */ - inline void write(buffer_t buffer, size_t n, bool PUSH = true) { - write({buffer, n, PUSH}, [](auto){}); - } + inline size_t add(uint8_t* data, size_t n) { + auto written = std::min(n, remaining); + memcpy(pos(), data, written); + return written; + } - void write(WriteBuffer request, WriteCallback callback); - - - /* - Open connection. - */ - void open(bool active = false); - - /* - Close connection. - */ - void close(); - - /* - Abort connection. (Same as Terminate) - */ - inline void abort() { - state_->abort(*this); - signal_close(); - } - - /* - Set callback for ACCEPT event. - */ - inline Connection& onAccept(AcceptCallback callback) { - on_accept_ = callback; - return *this; - } - - /* - Set callback for CONNECT event. - */ - inline Connection& onConnect(ConnectCallback callback) { - on_connect_ = callback; - return *this; - } - - /* - Set callback for DISCONNECT event. - */ - inline Connection& onDisconnect(DisconnectCallback callback) { - on_disconnect_ = callback; - return *this; - } - - /* - Set callback for ERROR event. - */ - inline Connection& onError(ErrorCallback callback) { - on_error_ = callback; - return *this; - } - - /* - Set callback for every packet received. - */ - inline Connection& onPacketReceived(PacketReceivedCallback callback) { - on_packet_received_ = callback; - return *this; - } - - /* - Set callback for when a packet is dropped. - */ - inline Connection& onPacketDropped(PacketDroppedCallback callback) { - on_packet_dropped_ = callback; - return *this; - } - - /* - Represent the Connection as a string (STATUS). - */ - std::string to_string() const; - - /* - Returns the current state of the connection. - */ - inline Connection::State& state() const { return *state_; } - - /* - Returns the previous state of the connection. - */ - inline Connection::State& prev_state() const { return *prev_state_; } - - /* - Calculates and return bytes transmitted. - TODO: Not sure if this will suffice. - */ - inline uint32_t bytes_transmitted() const { - return control_block.SND.NXT - control_block.ISS; - } - - /* - Calculates and return bytes received. - TODO: Not sure if this will suffice. - */ - inline uint32_t bytes_received() const { - return control_block.RCV.NXT - control_block.IRS; - } + inline void clear() { + memset(begin(), 0, offset); + remaining = capacity(); + offset = 0; + push = false; + } + }; // < Connection::ReadBuffer - /* - Bytes queued for transmission. - TODO: Implement when retransmission is up and running. - */ - //inline size_t send_queue_bytes() const {} - /* - Bytes currently in receive buffer. - */ - inline size_t read_queue_bytes() const { - return read_request.buffer.size(); - } + /* + Wrapper around a buffer that contains data to be written. + */ + struct WriteBuffer { + buffer_t buffer; + size_t remaining; + size_t offset; + bool push; - /* - Return the id (TUPLE) of the connection. - */ - inline Connection::Tuple tuple() const { - return {local_port_, remote_}; - } + WriteBuffer(buffer_t buf, size_t length, bool PSH, size_t offs = 0) + : buffer(buf), remaining(length-offs), offset(offs), push(PSH) {} + inline size_t length() const { return remaining + offset; } - /* - State checks. - */ - bool is_listening() const; + inline bool done() const { return remaining == 0; } - inline bool is_connected() const { return state_->is_connected(); } + inline uint8_t* begin() const { return buffer.get(); } - inline bool is_writable() const { return state_->is_writable(); } + inline uint8_t* pos() const { return buffer.get() + offset; } - inline bool is_readable() const { return state_->is_readable(); } + inline uint8_t* end() const { return buffer.get() + length(); } - inline bool is_closing() const { return state_->is_closing(); } + inline bool advance(size_t length) { + assert(length <= remaining); + offset += length; + remaining -= length; + return length > 0; + } + }; // < Connection::WriteBuffer + /* + Callback when a receive buffer receives either push or is full + - Supplied on asynchronous read + */ + using ReadCallback = delegate; + struct ReadRequest { + ReadBuffer buffer; + ReadCallback callback; - /* - Helper function for state checks. - */ - inline bool is_state(const State& state) const { - return state_ == &state; - } + ReadRequest(ReadBuffer buf, ReadCallback cb) : buffer(buf), callback(cb) {} + ReadRequest(size_t n = 0) : + buffer(buffer_t(new uint8_t[n], std::default_delete()), n), + callback([](auto, auto){}) {} + }; - inline bool is_state(const std::string& state_str) const { - return state_->to_string() == state_str; - } + /* + Callback when a write is sent by the TCP + - Supplied on asynchronous write + */ + using WriteCallback = delegate; - /* - Destroy the Connection. + using WriteRequest = std::pair; - Clean up. - */ - ~Connection(); + /* + Connection identifier + */ + using Tuple = std::pair; - private: - /* - "Parent" for Connection. - */ - TCP& host_; // 4 B + /// CALLBACKS /// + /* + On connection attempt - When a remote sends SYN to connection in LISTENING state. + First thing that will happen. + */ + using AcceptCallback = delegate)>; - /* - End points. - */ - TCP::Port local_port_; // 2 B - TCP::Socket remote_; // 8~ B + /* + On connected - When both hosts exchanged sequence numbers (handshake is done). + Now in ESTABLISHED state - it's allowed to write and read to/from the remote. + */ + using ConnectCallback = delegate)>; - /* - The current state the Connection is in. - Handles most of the logic. - */ - State* state_; // 4 B - // Previous state. Used to keep track of state transitions. - State* prev_state_; // 4 B + /* + On disconnect - When a remote told it wanna close the connection. + Connection has received a FIN, currently last thing that will happen before a connection is remoed. + */ + struct Disconnect; - /* - Keep tracks of all sequence variables. - */ - TCB control_block; // 36 B + using DisconnectCallback = delegate, Disconnect)>; - /* - The given read request - */ - ReadRequest read_request; + /* + On error - When any of the users request fails. + */ + using ErrorCallback = delegate, TCPException)>; - /* - Queue for write requests to process - */ - std::queue write_queue; + /* + When a packet is received - Everytime a connection receives an incoming packet. + Would probably be used for debugging. + (Currently not in use) + */ + using PacketReceivedCallback = delegate, TCP::Packet_ptr)>; - /* - Bytes queued for transmission. - */ - //size_t write_queue_total; + /* + When a packet is dropped - Everytime an incoming packet is unallowed, it will be dropped. + Can be used for debugging. + */ + using PacketDroppedCallback = delegate; - /* - When time-wait timer was started. - */ - uint64_t time_wait_started; + /* + Reason for disconnect event. + */ + struct Disconnect { + public: + enum Reason { + CLOSING, + REFUSED, + RESET + }; - /// CALLBACK HANDLING /// + Reason reason; - /* When a Connection is initiated. */ - AcceptCallback on_accept_ = AcceptCallback::from(this); - inline bool default_on_accept(std::shared_ptr) { - //debug2(" Connection attempt from: %s \n", conn->remote().to_string().c_str()); - return true; // Always accept - } + explicit Disconnect(Reason reason) : reason(reason) {} - /* When Connection is ESTABLISHED. */ - ConnectCallback on_connect_ = [](std::shared_ptr) { - debug2(" Connected.\n"); - }; + inline operator Reason() const noexcept { return reason; } - /* When Connection is CLOSING. */ - DisconnectCallback on_disconnect_ = [](std::shared_ptr, Disconnect) { - //debug2(" Connection disconnect. Reason: %s \n", msg.c_str()); - }; + inline operator std::string() const noexcept { return to_string(); } - /* When error occcured. */ - ErrorCallback on_error_ = ErrorCallback::from(this); - inline void default_on_error(std::shared_ptr, TCPException) { - //debug2(" TCPException: %s \n", error.what()); - } + inline bool operator ==(const Disconnect& dc) const { return reason == dc.reason; } - /* When packet is received */ - PacketReceivedCallback on_packet_received_ = [](std::shared_ptr, TCP::Packet_ptr) { - //debug2(" Packet received: %s \n", packet->to_string().c_str()); - }; + std::string to_string() const { + switch(reason) { + case CLOSING: + return "Connection closing"; + case REFUSED: + return "Conneciton refused"; + case RESET: + return "Connection reset"; + default: + return "Unknown reason"; + } + } + }; // < struct TCP::Connection::Disconnect - /* When a packet is dropped. */ - PacketDroppedCallback on_packet_dropped_ = [](TCP::Packet_ptr, std::string) { - //debug(" Packet dropped. %s | Reason: %s \n", - // packet->to_string().c_str(), reason.c_str()); - }; + /* + Interface for one of the many states a Connection can have. + */ + class State { + public: + enum Result { + CLOSED = -1, + OK = 0, + CLOSE = 1 + }; + /* + Open a Connection. + OPEN + */ + virtual void open(Connection&, bool active = false); + /* + Write to a Connection. + SEND + */ + virtual size_t send(Connection&, WriteBuffer&); - /// READING /// + /* + Read from a Connection. + RECEIVE + */ + virtual void receive(Connection&, ReadBuffer&); - /* - Assign the read request (read buffer) - */ - inline void receive(ReadBuffer& buffer) { - read_request.buffer = {buffer}; - } + /* + Close a Connection. + CLOSE + */ + virtual void close(Connection&); - /* - Receive data into the current read requests buffer. - */ - size_t receive(const uint8_t* data, size_t n, bool PUSH); + /* + Terminate a Connection. + ABORT + */ + virtual void abort(Connection&); - /* - Copy data into the ReadBuffer - */ - inline size_t receive(ReadBuffer& buf, const uint8_t* data, size_t n) { - auto received = std::min(n, buf.remaining); - memcpy(buf.pos(), data, received); // Can we use move? - return received; - } + /* + Handle a Packet + SEGMENT ARRIVES + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) = 0; - /* - Remote is closing, no more data will be received. - Returns receive buffer to user. - */ - inline void receive_disconnect() { - assert(!read_request.buffer.empty()); - auto& buf = read_request.buffer; - buf.push = true; - read_request.callback(buf.buffer, buf.size()); - } + /* + The current state represented as a string. + STATUS + */ + virtual std::string to_string() const = 0; + /* - /// WRITING /// + */ + virtual bool is_connected() const { return false; } - /* - Active try to send a buffer by asking the TCP. - */ - inline size_t send(WriteBuffer& buffer) { - return host_.send(shared_from_this(), buffer); - } + virtual bool is_writable() const { return false; } - /* - Segmentize buffer into packets until either everything has been written, - or all packets are used up. - */ - size_t send(const char* buffer, size_t remaining, size_t& packets, bool PUSH); + virtual bool is_readable() const { return false; } - inline size_t send(WriteBuffer& buffer, size_t& packets) { - return send((char*)buffer.pos(), buffer.remaining, packets, buffer.push); - } + virtual bool is_closing() const { return false; } - /* - Process the write queue with the given amount of packets. - Returns true if all the jobs are done (queue is empty) - */ - bool offer(size_t& packets); + protected: + /* + Helper functions + TODO: Clean up names. + */ + virtual bool check_seq(Connection&, TCP::Packet_ptr); - /* - Try to write (some of) queue on connected. - */ - void write_queue_on_connect(); + virtual void unallowed_syn_reset_connection(Connection&, TCP::Packet_ptr); - /* - Reset queue on disconnect. Clears the queue and notice every requests callback. - */ - void write_queue_reset(); + virtual bool check_ack(Connection&, TCP::Packet_ptr); - /* - Invoke/signal the diffrent TCP events. - */ - inline bool signal_accept() { return on_accept_(shared_from_this()); } + virtual void process_segment(Connection&, TCP::Packet_ptr); - inline void signal_connect() { on_connect_(shared_from_this()); } + virtual void process_fin(Connection&, TCP::Packet_ptr); - inline void signal_disconnect(Disconnect::Reason&& reason) { on_disconnect_(shared_from_this(), Disconnect{reason}); } + virtual void send_reset(Connection&); - inline void signal_error(TCPException error) { on_error_(shared_from_this(), error); } + }; // < class TCP::Connection::State - inline void signal_packet_received(TCP::Packet_ptr packet) { on_packet_received_(shared_from_this(), packet); } + /* + Forward declaration of concrete states. + Definition in "tcp_connection_states.hpp" + */ + class Closed; + class Listen; + class SynSent; + class SynReceived; + class Established; + class FinWait1; + class FinWait2; + class CloseWait; + class Closing; + class LastAck; + class TimeWait; - inline void signal_packet_dropped(TCP::Packet_ptr packet, std::string reason) { on_packet_dropped_(packet, reason); } + /* + Transmission Control Block. + Keep tracks of all the data for a connection. + + RFC 793: Page 19 + Among the variables stored in the + TCB are the local and remote socket numbers, the security and + precedence of the connection, pointers to the user's send and receive + buffers, pointers to the retransmit queue and to the current segment. + In addition several variables relating to the send and receive + sequence numbers are stored in the TCB. + */ + struct TCB { + /* Send Sequence Variables */ + struct { + TCP::Seq UNA; // send unacknowledged + TCP::Seq NXT; // send next + uint16_t WND; // send window + uint16_t UP; // send urgent pointer + TCP::Seq WL1; // segment sequence number used for last window update + TCP::Seq WL2; // segment acknowledgment number used for last window update + + uint16_t MSS; // Maximum segment size for outgoing segments. + } SND; // << + TCP::Seq ISS; // initial send sequence number + + /* Receive Sequence Variables */ + struct { + TCP::Seq NXT; // receive next + uint16_t WND; // receive window + uint16_t UP; // receive urgent pointer + } RCV; // << + TCP::Seq IRS; // initial receive sequence number + + TCB() { + SND = { 0, 0, TCP::default_window_size, 0, 0, 0, TCP::default_mss }; + ISS = 0; + RCV = { 0, TCP::default_window_size, 0 }; + IRS = 0; + }; - /* - Drop a packet. Used for debug/callback. - */ - inline void drop(TCP::Packet_ptr packet, std::string reason) { signal_packet_dropped(packet, reason); } - inline void drop(TCP::Packet_ptr packet) { drop(packet, "None given."); } + std::string to_string() const; + }__attribute__((packed)); // < struct TCP::Connection::TCB + /* + Creates a connection without a remote. + */ + Connection(TCP& host, Port local_port); - /// TCB HANDLING /// + /* + Creates a connection with a remote. + */ + Connection(TCP& host, Port local_port, Socket remote); - /* - Returns the TCB. - */ - inline Connection::TCB& tcb() { return control_block; } + /* + The hosting TCP instance. + */ + inline const TCP& host() const { return host_; } - /* - Generate a new ISS. - */ - TCP::Seq generate_iss(); + /* + The local Socket bound to this connection. + */ + inline TCP::Socket local() const { return {host_.inet_.ip_addr(), local_port_}; } + /* + The remote Socket bound to this connection. + */ + inline TCP::Socket remote() const { return remote_; } - /// STATE HANDLING /// - /* - Set state. (used by substates) - */ - void set_state(State& state); + /* + Set remote Socket bound to this connection. + @WARNING: Should this be public? Used by TCP. + */ + inline void set_remote(Socket remote) { remote_ = remote; } - /// BUFFER HANDLING /// + /* + Read asynchronous from a remote. - /* - Transmit the send buffer. - */ - void transmit(); + Create n sized internal read buffer and callback for when data is received. + Callback will be called until overwritten with a new read() or connection closes. + Buffer is cleared for data after every reset. + */ + inline void read(size_t n, ReadCallback callback) { + ReadBuffer buffer = {buffer_t(new uint8_t[n], std::default_delete()), n}; + read(buffer, callback); + } - /* - Transmit the packet. - */ - void transmit(TCP::Packet_ptr); + /* + Assign the connections receive buffer and callback for when data is received. + Works as read(size_t, ReadCallback); + */ + inline void read(buffer_t buffer, size_t n, ReadCallback callback) { + read({buffer, n}, callback); + } - /* - Creates a new outgoing packet with the current TCB values and options. - */ - TCP::Packet_ptr create_outgoing_packet(); + void read(ReadBuffer buffer, ReadCallback callback); - /* - */ - inline TCP::Packet_ptr outgoing_packet() { - return create_outgoing_packet(); - } + /* + Write asynchronous to a remote. - /// RETRANSMISSION /// + Copies the data from the buffer into an internal buffer. Callback is called when a a write is either done or aborted. + Immediately tries to write the data to the connection. If not possible, queues the write for processing when possible (FIFO). + */ + inline void write(const void* buf, size_t n, WriteCallback callback, bool PUSH = true) { + auto buffer = buffer_t(new uint8_t[n], std::default_delete()); + memcpy(buffer.get(), buf, n); + write(buffer, n, callback, PUSH); + } - /* - Starts a retransmission timer that retransmits the packet when RTO has passed. + /* + Works as write(const void*, size_t, WriteCallback, bool), + but with the exception of avoiding copying the data to an internal buffer. + */ + inline void write(buffer_t buffer, size_t n, WriteCallback callback, bool PUSH = true) { + write({buffer, n, PUSH}, callback); + } - // TODO: Calculate RTO, currently hardcoded to 1 second (1000ms). - */ - void add_retransmission(TCP::Packet_ptr); + /* + Works the same as it's counterpart, without subscribing to a WriteCallback. + */ + inline void write(const void* buf, size_t n, bool PUSH = true) { + write(buf, n, [](auto){}, PUSH); + } - /* - Measure the elapsed time between sending a data octet with a - particular sequence number and receiving an acknowledgment that - covers that sequence number (segments sent do not have to match - segments received). This measured elapsed time is the Round Trip - Time (RTT). - */ - //std::chrono::milliseconds RTT() const; - std::chrono::milliseconds RTO() const; + /* + Works the same as it's counterpart, without subscribing to a WriteCallback. + */ + inline void write(buffer_t buffer, size_t n, bool PUSH = true) { + write({buffer, n, PUSH}, [](auto){}); + } - /* - Start the time wait timeout for 2*MSL - */ - void start_time_wait_timeout(); + void write(WriteBuffer request, WriteCallback callback); - /* - Tell the host (TCP) to delete this connection. - */ - void signal_close(); + /* + Open connection. + */ + void open(bool active = false); - /// OPTIONS /// - /* - Maximum Segment Data Size - (Limit the size for outgoing packets) - */ - inline uint16_t MSDS() const { - return std::min(host_.MSS(), control_block.SND.MSS); - } + /* + Close connection. + */ + void close(); - /* - Parse and apply options. - */ - void parse_options(TCP::Packet_ptr); + /* + Abort connection. (Same as Terminate) + */ + inline void abort() { + state_->abort(*this); + signal_close(); + } - /* - Add an option. - */ - void add_option(TCP::Option::Kind, TCP::Packet_ptr); + /* + Set callback for ACCEPT event. + */ + inline Connection& onAccept(AcceptCallback callback) { + on_accept_ = callback; + return *this; + } - /* - Receive a TCP Packet. - */ - void segment_arrived(TCP::Packet_ptr); + /* + Set callback for CONNECT event. + */ + inline Connection& onConnect(ConnectCallback callback) { + on_connect_ = callback; + return *this; + } - }; // < class TCP::Connection + /* + Set callback for DISCONNECT event. + */ + inline Connection& onDisconnect(DisconnectCallback callback) { + on_disconnect_ = callback; + return *this; + } + /* + Set callback for ERROR event. + */ + inline Connection& onError(ErrorCallback callback) { + on_error_ = callback; + return *this; + } - /// USER INTERFACE - TCP /// + /* + Set callback for every packet received. + */ + inline Connection& onPacketReceived(PacketReceivedCallback callback) { + on_packet_received_ = callback; + return *this; + } - /* - Constructor - */ - TCP(IPStack&); + /* + Set callback for when a packet is dropped. + */ + inline Connection& onPacketDropped(PacketDroppedCallback callback) { + on_packet_dropped_ = callback; + return *this; + } - /* - Bind a new listener to a given Port. - */ - TCP::Connection& bind(Port port); + /* + Represent the Connection as a string (STATUS). + */ + std::string to_string() const; - /* - Active open a new connection to the given remote. - */ - Connection_ptr connect(Socket remote); + /* + Returns the current state of the connection. + */ + inline Connection::State& state() const { return *state_; } - /* - Active open a new connection to the given remote. - */ - inline auto connect(TCP::Address address, Port port = 80) { - return connect({address, port}); - } + /* + Returns the previous state of the connection. + */ + inline Connection::State& prev_state() const { return *prev_state_; } - /* - Active open a new connection to the given remote. - */ - void connect(Socket remote, Connection::ConnectCallback); + /* + Calculates and return bytes transmitted. + TODO: Not sure if this will suffice. + */ + inline uint32_t bytes_transmitted() const { + return control_block.SND.NXT - control_block.ISS; + } - /* - Receive packet from network layer (IP). - */ - void bottom(net::Packet_ptr); + /* + Calculates and return bytes received. + TODO: Not sure if this will suffice. + */ + inline uint32_t bytes_received() const { + return control_block.RCV.NXT - control_block.IRS; + } - /* - Delegate output to network layer - */ - inline void set_network_out(downstream del) { _network_layer_out = del; } + /* + Bytes queued for transmission. + TODO: Implement when retransmission is up and running. + */ + //inline size_t send_queue_bytes() const {} - /* - Compute the TCP checksum - */ - static uint16_t checksum(const TCP::Packet_ptr); + /* + Bytes currently in receive buffer. + */ + inline size_t read_queue_bytes() const { + return read_request.buffer.size(); + } - inline const auto& listeners() { return listeners_; } + /* + Return the id (TUPLE) of the connection. + */ + inline Connection::Tuple tuple() const { + return {local_port_, remote_}; + } - inline const auto& connections() { return connections_; } - /* - Number of open ports. - */ - inline size_t openPorts() { return listeners_.size(); } + /* + State checks. + */ + bool is_listening() const; - /* - Number of active connections. - */ - inline size_t activeConnections() { return connections_.size(); } + inline bool is_connected() const { return state_->is_connected(); } - /* - Maximum Segment Lifetime - */ - inline auto MSL() const { return MAX_SEG_LIFETIME; } + inline bool is_writable() const { return state_->is_writable(); } - /* - Set Maximum Segment Lifetime - */ - inline void set_MSL(const std::chrono::milliseconds msl) { - MAX_SEG_LIFETIME = msl; - } + inline bool is_readable() const { return state_->is_readable(); } - /* - Maximum Segment Size - [RFC 793] [RFC 879] [RFC 6691] + inline bool is_closing() const { return state_->is_closing(); } - @NOTE: Currently not supporting MTU bigger than 1482 bytes. - */ - inline uint16_t MSS() const { - /* - VirtulaBox "issue": - MTU > 1498 will break TCP. - MTU > 1482 seems to cause fragmentation: https://www.virtualbox.org/ticket/13967 - */ - const uint16_t VBOX_LIMIT = 1482; - return std::min(inet_.MTU(), VBOX_LIMIT) - sizeof(Full_header::ip4) - sizeof(TCP::Header); - } - /* - Show all connections for TCP as a string. - */ - std::string status() const; + /* + Helper function for state checks. + */ + inline bool is_state(const State& state) const { + return state_ == &state; + } + + inline bool is_state(const std::string& state_str) const { + return state_->to_string() == state_str; + } -private: + /* + Destroy the Connection. - IPStack& inet_; - std::map listeners_; - std::map connections_; + Clean up. + */ + ~Connection(); - downstream _network_layer_out; + private: + /* + "Parent" for Connection. + */ + TCP& host_; // 4 B - std::queue write_queue; + /* + End points. + */ + TCP::Port local_port_; // 2 B + TCP::Socket remote_; // 8~ B - /* - Settings - */ - TCP::Port current_ephemeral_ = 1024; + /* + The current state the Connection is in. + Handles most of the logic. + */ + State* state_; // 4 B + // Previous state. Used to keep track of state transitions. + State* prev_state_; // 4 B - std::chrono::milliseconds MAX_SEG_LIFETIME; + /* + Keep tracks of all sequence variables. + */ + TCB control_block; // 36 B - /* - Transmit packet to network layer (IP). - */ - void transmit(TCP::Packet_ptr); + /* + The given read request + */ + ReadRequest read_request; - /* - Generate a unique initial sequence number (ISS). - */ - TCP::Seq generate_iss(); + /* + Queue for write requests to process + */ + std::queue write_queue; - /* - Returns a free port for outgoing connections. - */ - TCP::Port free_port(); + /* + Bytes queued for transmission. + */ + //size_t write_queue_total; - /* - Packet is dropped. - */ - void drop(TCP::Packet_ptr); + /* + When time-wait timer was started. + */ + uint64_t time_wait_started; - /* - Add a Connection. - */ - Connection_ptr add_connection(TCP::Port local_port, TCP::Socket remote); - /* - Close and delete the connection. + /// CALLBACK HANDLING /// + + /* When a Connection is initiated. */ + AcceptCallback on_accept_ = AcceptCallback::from(this); + inline bool default_on_accept(std::shared_ptr) { + //debug2(" Connection attempt from: %s \n", conn->remote().to_string().c_str()); + return true; // Always accept + } + + /* When Connection is ESTABLISHED. */ + ConnectCallback on_connect_ = [](std::shared_ptr) { + debug2(" Connected.\n"); + }; + + /* When Connection is CLOSING. */ + DisconnectCallback on_disconnect_ = [](std::shared_ptr, Disconnect) { + //debug2(" Connection disconnect. Reason: %s \n", msg.c_str()); + }; + + /* When error occcured. */ + ErrorCallback on_error_ = ErrorCallback::from(this); + inline void default_on_error(std::shared_ptr, TCPException) { + //debug2(" TCPException: %s \n", error.what()); + } + + /* When packet is received */ + PacketReceivedCallback on_packet_received_ = [](std::shared_ptr, TCP::Packet_ptr) { + //debug2(" Packet received: %s \n", packet->to_string().c_str()); + }; + + /* When a packet is dropped. */ + PacketDroppedCallback on_packet_dropped_ = [](TCP::Packet_ptr, std::string) { + //debug(" Packet dropped. %s | Reason: %s \n", + // packet->to_string().c_str(), reason.c_str()); + }; + + + /// READING /// + + /* + Assign the read request (read buffer) + */ + inline void receive(ReadBuffer& buffer) { + read_request.buffer = {buffer}; + } + + /* + Receive data into the current read requests buffer. + */ + size_t receive(const uint8_t* data, size_t n, bool PUSH); + + /* + Copy data into the ReadBuffer + */ + inline size_t receive(ReadBuffer& buf, const uint8_t* data, size_t n) { + auto received = std::min(n, buf.remaining); + memcpy(buf.pos(), data, received); // Can we use move? + return received; + } + + /* + Remote is closing, no more data will be received. + Returns receive buffer to user. + */ + inline void receive_disconnect() { + assert(!read_request.buffer.empty()); + auto& buf = read_request.buffer; + buf.push = true; + read_request.callback(buf.buffer, buf.size()); + } + + + /// WRITING /// + + /* + Active try to send a buffer by asking the TCP. + */ + inline size_t send(WriteBuffer& buffer) { + return host_.send(shared_from_this(), buffer); + } + + /* + Segmentize buffer into packets until either everything has been written, + or all packets are used up. + */ + size_t send(const char* buffer, size_t remaining, size_t& packets, bool PUSH); + + inline size_t send(WriteBuffer& buffer, size_t& packets) { + return send((char*)buffer.pos(), buffer.remaining, packets, buffer.push); + } + + /* + Process the write queue with the given amount of packets. + Returns true if all the jobs are done (queue is empty) + */ + bool offer(size_t& packets); + + /* + Try to write (some of) queue on connected. + */ + void write_queue_on_connect(); + + /* + Reset queue on disconnect. Clears the queue and notice every requests callback. + */ + void write_queue_reset(); + + /* + Invoke/signal the diffrent TCP events. + */ + inline bool signal_accept() { return on_accept_(shared_from_this()); } + + inline void signal_connect() { on_connect_(shared_from_this()); } + + inline void signal_disconnect(Disconnect::Reason&& reason) { on_disconnect_(shared_from_this(), Disconnect{reason}); } + + inline void signal_error(TCPException error) { on_error_(shared_from_this(), error); } + + inline void signal_packet_received(TCP::Packet_ptr packet) { on_packet_received_(shared_from_this(), packet); } + + inline void signal_packet_dropped(TCP::Packet_ptr packet, std::string reason) { on_packet_dropped_(packet, reason); } + + /* + Drop a packet. Used for debug/callback. + */ + inline void drop(TCP::Packet_ptr packet, std::string reason) { signal_packet_dropped(packet, reason); } + inline void drop(TCP::Packet_ptr packet) { drop(packet, "None given."); } + + + /// TCB HANDLING /// + + /* + Returns the TCB. + */ + inline Connection::TCB& tcb() { return control_block; } + + /* + Generate a new ISS. + */ + TCP::Seq generate_iss(); + + + /// STATE HANDLING /// + /* + Set state. (used by substates) + */ + void set_state(State& state); + + + /// BUFFER HANDLING /// + + /* + Transmit the send buffer. + */ + void transmit(); + + /* + Transmit the packet. + */ + void transmit(TCP::Packet_ptr); + + /* + Creates a new outgoing packet with the current TCB values and options. + */ + TCP::Packet_ptr create_outgoing_packet(); + + /* + */ + inline TCP::Packet_ptr outgoing_packet() { + return create_outgoing_packet(); + } + + + /// RETRANSMISSION /// + + /* + Starts a retransmission timer that retransmits the packet when RTO has passed. + + // TODO: Calculate RTO, currently hardcoded to 1 second (1000ms). */ - void close_connection(TCP::Connection&); + void add_retransmission(TCP::Packet_ptr); + + /* + Measure the elapsed time between sending a data octet with a + particular sequence number and receiving an acknowledgment that + covers that sequence number (segments sent do not have to match + segments received). This measured elapsed time is the Round Trip + Time (RTT). + */ + //std::chrono::milliseconds RTT() const; + std::chrono::milliseconds RTO() const; + + /* + Start the time wait timeout for 2*MSL + */ + void start_time_wait_timeout(); + + /* + Tell the host (TCP) to delete this connection. + */ + void signal_close(); + + + /// OPTIONS /// + /* + Maximum Segment Data Size + (Limit the size for outgoing packets) + */ + inline uint16_t MSDS() const { + return std::min(host_.MSS(), control_block.SND.MSS); + } + + /* + Parse and apply options. + */ + void parse_options(TCP::Packet_ptr); + + /* + Add an option. + */ + void add_option(TCP::Option::Kind, TCP::Packet_ptr); + + /* + Receive a TCP Packet. + */ + void segment_arrived(TCP::Packet_ptr); + + }; // < class TCP::Connection + + + /// USER INTERFACE - TCP /// + + /* + Constructor + */ + TCP(IPStack&); + + /* + Bind a new listener to a given Port. + */ + TCP::Connection& bind(Port port); + + /* + Active open a new connection to the given remote. + */ + Connection_ptr connect(Socket remote); + + /* + Active open a new connection to the given remote. + */ + inline auto connect(TCP::Address address, Port port = 80) { + return connect({address, port}); + } + + /* + Active open a new connection to the given remote. + */ + void connect(Socket remote, Connection::ConnectCallback); + + /* + Receive packet from network layer (IP). + */ + void bottom(net::Packet_ptr); + + /* + Delegate output to network layer + */ + inline void set_network_out(downstream del) { _network_layer_out = del; } + + /* + Compute the TCP checksum + */ + static uint16_t checksum(const TCP::Packet_ptr); + + inline const auto& listeners() { return listeners_; } + + inline const auto& connections() { return connections_; } + + /* + Number of open ports. + */ + inline size_t openPorts() { return listeners_.size(); } + + /* + Number of active connections. + */ + inline size_t activeConnections() { return connections_.size(); } + + /* + Maximum Segment Lifetime + */ + inline auto MSL() const { return MAX_SEG_LIFETIME; } + + /* + Set Maximum Segment Lifetime + */ + inline void set_MSL(const std::chrono::milliseconds msl) { + MAX_SEG_LIFETIME = msl; + } + + /* + Maximum Segment Size + [RFC 793] [RFC 879] [RFC 6691] + + @NOTE: Currently not supporting MTU bigger than 1482 bytes. + */ + inline uint16_t MSS() const { + /* + VirtulaBox "issue": + MTU > 1498 will break TCP. + MTU > 1482 seems to cause fragmentation: https://www.virtualbox.org/ticket/13967 + */ + const uint16_t VBOX_LIMIT = 1482; + return std::min(inet_.MTU(), VBOX_LIMIT) - sizeof(Full_header::ip4) - sizeof(TCP::Header); + } + + /* + Show all connections for TCP as a string. + */ + std::string status() const; + + + private: + + IPStack& inet_; + std::map listeners_; + std::map connections_; + + downstream _network_layer_out; + + std::queue write_queue; + + /* + Settings + */ + TCP::Port current_ephemeral_ = 1024; + + std::chrono::milliseconds MAX_SEG_LIFETIME; + + /* + Transmit packet to network layer (IP). + */ + void transmit(TCP::Packet_ptr); - /* - Process the write queue with the given amount of free packets. - */ - void process_write_queue(size_t packets); + /* + Generate a unique initial sequence number (ISS). + */ + TCP::Seq generate_iss(); + + /* + Returns a free port for outgoing connections. + */ + TCP::Port free_port(); - /* - Ask to send a Connection's WriteBuffer. - If there is no free packets, the job will be queued. - */ - size_t send(Connection_ptr, Connection::WriteBuffer&); + /* + Packet is dropped. + */ + void drop(TCP::Packet_ptr); + + /* + Add a Connection. + */ + Connection_ptr add_connection(TCP::Port local_port, TCP::Socket remote); + + /* + Close and delete the connection. + */ + void close_connection(TCP::Connection&); + + /* + Process the write queue with the given amount of free packets. + */ + void process_write_queue(size_t packets); + + /* + Ask to send a Connection's WriteBuffer. + If there is no free packets, the job will be queued. + */ + size_t send(Connection_ptr, Connection::WriteBuffer&); -}; // < class TCP + }; // < class TCP }; // < namespace net diff --git a/api/net/tcp_connection_states.hpp b/api/net/tcp_connection_states.hpp index b3935b7aa8..f0450d1d70 100644 --- a/api/net/tcp_connection_states.hpp +++ b/api/net/tcp_connection_states.hpp @@ -25,153 +25,153 @@ using Connection = TCP::Connection; using State = TCP::Connection::State; /* - CLOSED + CLOSED */ class Connection::Closed : public State { public: - inline static State& instance() { - static Closed instance; - return instance; - } + inline static State& instance() { + static Closed instance; + return instance; + } - virtual void open(Connection&, bool active = false) override; + virtual void open(Connection&, bool active = false) override; - virtual size_t send(Connection&, WriteBuffer&) override; + virtual size_t send(Connection&, WriteBuffer&) override; - /* - PASSIVE: - <- Do nothing (Start listening). + /* + PASSIVE: + <- Do nothing (Start listening). - => Listen. + => Listen. - ACTIVE: - <- Send SYN. + ACTIVE: + <- Send SYN. - => SynSent - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + => SynSent + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "CLOSED"; - }; + inline virtual std::string to_string() const override { + return "CLOSED"; + }; private: - inline Closed() {}; + inline Closed() {}; }; /* - LISTEN + LISTEN */ class Connection::Listen : public State { public: - inline static State& instance() { - static Listen instance; - return instance; - } - virtual void open(Connection&, bool active = false) override; + inline static State& instance() { + static Listen instance; + return instance; + } + virtual void open(Connection&, bool active = false) override; - virtual size_t send(Connection&, WriteBuffer&) override; + virtual size_t send(Connection&, WriteBuffer&) override; - virtual void close(Connection&) override; - /* - -> Receive SYN. + virtual void close(Connection&) override; + /* + -> Receive SYN. - <- Send SYN+ACK. + <- Send SYN+ACK. - => SynReceived. - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + => SynReceived. + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "LISTENING"; - }; + inline virtual std::string to_string() const override { + return "LISTENING"; + }; private: - inline Listen() {}; + inline Listen() {}; }; /* - SYN-SENT + SYN-SENT */ class Connection::SynSent : public State { public: - inline static State& instance() { - static SynSent instance; - return instance; - } + inline static State& instance() { + static SynSent instance; + return instance; + } - virtual size_t send(Connection&, WriteBuffer&) override; + virtual size_t send(Connection&, WriteBuffer&) override; - virtual void close(Connection&) override; - /* - -> Receive SYN+ACK + virtual void close(Connection&) override; + /* + -> Receive SYN+ACK - <- Send ACK. + <- Send ACK. - => Established. - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + => Established. + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "SYN-SENT"; - }; + inline virtual std::string to_string() const override { + return "SYN-SENT"; + }; private: - inline SynSent() {}; + inline SynSent() {}; }; /* - SYN-RCV + SYN-RCV */ class Connection::SynReceived : public State { public: - inline static State& instance() { - static SynReceived instance; - return instance; - } + inline static State& instance() { + static SynReceived instance; + return instance; + } - virtual size_t send(Connection&, WriteBuffer&) override; + virtual size_t send(Connection&, WriteBuffer&) override; - virtual void close(Connection&) override; + virtual void close(Connection&) override; - virtual void abort(Connection&) override; - /* - -> Receive ACK. + virtual void abort(Connection&) override; + /* + -> Receive ACK. - <- Do nothing (Connection is Established) + <- Do nothing (Connection is Established) - => Established. - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + => Established. + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "SYN-RCV"; - }; + inline virtual std::string to_string() const override { + return "SYN-RCV"; + }; private: - inline SynReceived() {}; + inline SynReceived() {}; }; /* - ESTABLISHED + ESTABLISHED */ class Connection::Established : public State { public: - inline static State& instance() { - static Established instance; - return instance; - } + inline static State& instance() { + static Established instance; + return instance; + } - virtual size_t send(Connection&, WriteBuffer&) override; + virtual size_t send(Connection&, WriteBuffer&) override; - virtual void receive(Connection&, ReadBuffer&) override; + virtual void receive(Connection&, ReadBuffer&) override; - virtual void close(Connection&) override; + virtual void close(Connection&) override; - virtual void abort(Connection&) override; + virtual void abort(Connection&) override; - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "ESTABLISHED"; - }; + inline virtual std::string to_string() const override { + return "ESTABLISHED"; + }; inline virtual bool is_connected() const override { return true; @@ -186,35 +186,35 @@ class Connection::Established : public State { } private: - inline Established() {}; + inline Established() {}; }; /* - FIN-WAIT-1 + FIN-WAIT-1 */ class Connection::FinWait1 : public State { public: - inline static State& instance() { - static FinWait1 instance; - return instance; - } + inline static State& instance() { + static FinWait1 instance; + return instance; + } - virtual void receive(Connection&, ReadBuffer&) override; + virtual void receive(Connection&, ReadBuffer&) override; - virtual void close(Connection&) override; + virtual void close(Connection&) override; - virtual void abort(Connection&) override; + virtual void abort(Connection&) override; - /* - -> Receive ACK. + /* + -> Receive ACK. - => FinWait2. - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + => FinWait2. + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "FIN-WAIT-1"; - }; + inline virtual std::string to_string() const override { + return "FIN-WAIT-1"; + }; inline virtual bool is_readable() const override { return true; @@ -225,32 +225,32 @@ class Connection::FinWait1 : public State { } private: - inline FinWait1() {}; + inline FinWait1() {}; }; /* - FIN-WAIT-2 + FIN-WAIT-2 */ class Connection::FinWait2 : public State { public: - inline static State& instance() { - static FinWait2 instance; - return instance; - } + inline static State& instance() { + static FinWait2 instance; + return instance; + } - virtual void receive(Connection&, ReadBuffer&) override; + virtual void receive(Connection&, ReadBuffer&) override; - virtual void close(Connection&) override; + virtual void close(Connection&) override; - virtual void abort(Connection&) override; - /* + virtual void abort(Connection&) override; + /* - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "FIN-WAIT-2"; - }; + inline virtual std::string to_string() const override { + return "FIN-WAIT-2"; + }; inline virtual bool is_readable() const override { return true; @@ -261,73 +261,73 @@ class Connection::FinWait2 : public State { } private: - inline FinWait2() {}; + inline FinWait2() {}; }; /* - CLOSE-WAIT + CLOSE-WAIT */ class Connection::CloseWait : public State { public: - inline static State& instance() { - static CloseWait instance; - return instance; - } + inline static State& instance() { + static CloseWait instance; + return instance; + } - virtual size_t send(Connection&, WriteBuffer&) override; + virtual size_t send(Connection&, WriteBuffer&) override; - virtual void receive(Connection&, ReadBuffer&) override; + virtual void receive(Connection&, ReadBuffer&) override; - virtual void close(Connection&) override; + virtual void close(Connection&) override; - virtual void abort(Connection&) override; - /* - -> Nothing I think... + virtual void abort(Connection&) override; + /* + -> Nothing I think... - <- Send FIN. + <- Send FIN. - => LastAck - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + => LastAck + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "CLOSE-WAIT"; - }; + inline virtual std::string to_string() const override { + return "CLOSE-WAIT"; + }; inline virtual bool is_writable() const override { return true; } private: - inline CloseWait() {}; + inline CloseWait() {}; }; /* - CLOSING + CLOSING */ class Connection::Closing : public State { public: - inline static State& instance() { - static Closing instance; - return instance; - } - /* - -> Receive ACK. + inline static State& instance() { + static Closing instance; + return instance; + } + /* + -> Receive ACK. - => TimeWait (Guess this isnt needed, just start a Close-timer) - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + => TimeWait (Guess this isnt needed, just start a Close-timer) + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "CLOSING"; - }; + inline virtual std::string to_string() const override { + return "CLOSING"; + }; inline virtual bool is_closing() const override { return true; } private: - inline Closing() {}; + inline Closing() {}; }; /* @@ -361,29 +361,29 @@ class Connection::LastAck : public State { }; /* - TIME-WAIT + TIME-WAIT */ class Connection::TimeWait : public State { public: - inline static State& instance() { - static TimeWait instance; - return instance; - } - /* + inline static State& instance() { + static TimeWait instance; + return instance; + } + /* - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) override; + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) override; - inline virtual std::string to_string() const override { - return "TIME-WAIT"; - }; + inline virtual std::string to_string() const override { + return "TIME-WAIT"; + }; inline virtual bool is_closing() const override { return true; } private: - inline TimeWait() {}; + inline TimeWait() {}; }; #endif diff --git a/api/net/util.hpp b/api/net/util.hpp index f5d3f7161a..621273bf2f 100644 --- a/api/net/util.hpp +++ b/api/net/util.hpp @@ -22,37 +22,37 @@ namespace net { -/* - * See P.49 of C programming - * Get "n" bits from integer "x", starting from position "p" - * e.g., getbits(x, 31, 8) -- highest byte - * getbits(x, 7, 8) -- lowest byte - */ + /* + * See P.49 of C programming + * Get "n" bits from integer "x", starting from position "p" + * e.g., getbits(x, 31, 8) -- highest byte + * getbits(x, 7, 8) -- lowest byte + */ #define getbits(x, p, n) (((x) >> ((p) + 1 - (n))) & ~(~0 << (n))) -inline uint16_t ntohs(uint16_t n) noexcept { - return __builtin_bswap16(n); -} + inline uint16_t ntohs(uint16_t n) noexcept { + return __builtin_bswap16(n); + } -inline uint16_t htons(uint16_t n) noexcept { - return __builtin_bswap16(n); -} + inline uint16_t htons(uint16_t n) noexcept { + return __builtin_bswap16(n); + } -inline uint32_t ntohl(uint32_t n) noexcept { - return __builtin_bswap32(n); -} + inline uint32_t ntohl(uint32_t n) noexcept { + return __builtin_bswap32(n); + } -inline uint32_t htonl(uint32_t n) noexcept { - return __builtin_bswap32(n); -} + inline uint32_t htonl(uint32_t n) noexcept { + return __builtin_bswap32(n); + } -inline uint64_t ntohll(uint64_t n) noexcept { - return __builtin_bswap64(n); -} + inline uint64_t ntohll(uint64_t n) noexcept { + return __builtin_bswap64(n); + } -inline uint64_t htonll(uint64_t n) noexcept { - return __builtin_bswap64(n); -} + inline uint64_t htonll(uint64_t n) noexcept { + return __builtin_bswap64(n); + } } //< namespace net diff --git a/api/utility/async_loop.hpp b/api/utility/async_loop.hpp index c4c456a360..d30230784e 100644 --- a/api/utility/async_loop.hpp +++ b/api/utility/async_loop.hpp @@ -6,27 +6,27 @@ typedef std::shared_ptr next_ptr_t; inline void async_loop( - std::function func, - std::function on_done) + std::function func, + std::function on_done) { // store next function on heap auto next = std::make_shared (); // loop: *next = - [next] (bool done) - { - // check we are done, and if so, - // execute the callback function and return - if (done) + [next] (bool done) { - on_done(); - return; + // check we are done, and if so, + // execute the callback function and return + if (done) + { + on_done(); + return; + } + // otherwise, + // execute one iteration of the loop + func(next); } - // otherwise, - // execute one iteration of the loop - func(next); - } // start the process next(false); } diff --git a/api/utility/delegate.hpp b/api/utility/delegate.hpp index 27c04c64cd..a942bf7da5 100644 --- a/api/utility/delegate.hpp +++ b/api/utility/delegate.hpp @@ -7,7 +7,7 @@ Licence: Assumed to be public domain. ...It's just awesome how people make great stuff and just post it - */ +*/ #ifndef OSABI_DELEGATE_HPP #define OSABI_DELEGATE_HPP @@ -25,7 +25,7 @@ class delegate using stub_ptr_type = R (*)(void*, A&&...); delegate(void* const o, stub_ptr_type const m) noexcept : - object_ptr_(o), + object_ptr_(o), stub_ptr_(m) { } @@ -42,16 +42,16 @@ class delegate delegate(::std::nullptr_t const) noexcept : delegate() { } template {}>::type> - explicit delegate(C const* const o) noexcept : - object_ptr_(const_cast(o)) + typename ::std::enable_if< ::std::is_class{}>::type> + explicit delegate(C const* const o) noexcept : + object_ptr_(const_cast(o)) { } template {}>::type> - explicit delegate(C const& o) noexcept : - object_ptr_(const_cast(&o)) + typename ::std::enable_if< ::std::is_class{}>::type> + explicit delegate(C const& o) noexcept : + object_ptr_(const_cast(&o)) { } @@ -84,11 +84,11 @@ class delegate typename = typename ::std::enable_if< !::std::is_same::type>{} >::type - > - delegate(T&& f) : + > + delegate(T&& f) : store_(operator new(sizeof(typename ::std::decay::type)), - functor_deleter::type>), - store_size_(sizeof(typename ::std::decay::type)) + functor_deleter::type>), + store_size_(sizeof(typename ::std::decay::type)) { using functor_type = typename ::std::decay::type; @@ -122,22 +122,22 @@ class delegate typename = typename ::std::enable_if< !::std::is_same::type>{} >::type - > - delegate& operator=(T&& f) + > + delegate& operator=(T&& f) { using functor_type = typename ::std::decay::type; if ((sizeof(functor_type) > store_size_) || !store_.unique()) - { - store_.reset(operator new(sizeof(functor_type)), - functor_deleter); + { + store_.reset(operator new(sizeof(functor_type)), + functor_deleter); - store_size_ = sizeof(functor_type); - } + store_size_ = sizeof(functor_type); + } else - { - deleter_(store_.get()); - } + { + deleter_(store_.get()); + } new (store_.get()) functor_type(::std::forward(f)); @@ -201,14 +201,14 @@ class delegate template static delegate from(C* const object_ptr, - R (C::* const method_ptr)(A...)) + R (C::* const method_ptr)(A...)) { return member_pair(object_ptr, method_ptr); } template static delegate from(C const* const object_ptr, - R (C::* const method_ptr)(A...) const) + R (C::* const method_ptr)(A...) const) { return const_member_pair(object_ptr, method_ptr); } @@ -221,7 +221,7 @@ class delegate template static delegate from(C const& object, - R (C::* const method_ptr)(A...) const) + R (C::* const method_ptr)(A...) const) { return const_member_pair(&object, method_ptr); } @@ -262,7 +262,7 @@ class delegate R operator()(A... args) const { -// assert(stub_ptr); + // assert(stub_ptr); return stub_ptr_(object_ptr_, ::std::forward
(args)...); } @@ -303,14 +303,14 @@ class delegate static R method_stub(void* const object_ptr, A&&... args) { return (static_cast(object_ptr)->*method_ptr)( - ::std::forward(args)...); + ::std::forward(args)...); } template static R const_method_stub(void* const object_ptr, A&&... args) { return (static_cast(object_ptr)->*method_ptr)( - ::std::forward(args)...); + ::std::forward(args)...); } template @@ -318,7 +318,7 @@ class delegate template struct is_member_pair< ::std::pair > : std::true_type + R (C::* const)(A...)> > : std::true_type { }; @@ -327,16 +327,16 @@ class delegate template struct is_const_member_pair< ::std::pair > : std::true_type + R (C::* const)(A...) const> > : std::true_type { }; template static typename ::std::enable_if< !(is_member_pair{} || - is_const_member_pair{}), + is_const_member_pair{}), R - >::type + >::type functor_stub(void* const object_ptr, A&&... args) { return (*static_cast(object_ptr))(::std::forward(args)...); @@ -345,13 +345,13 @@ class delegate template static typename ::std::enable_if< is_member_pair{} || - is_const_member_pair{}, + is_const_member_pair{}, R - >::type - functor_stub(void* const object_ptr, A&&... args) + >::type + functor_stub(void* const object_ptr, A&&... args) { return (static_cast(object_ptr)->first->* - static_cast(object_ptr)->second)(::std::forward(args)...); + static_cast(object_ptr)->second)(::std::forward(args)...); } }; @@ -365,7 +365,7 @@ namespace std auto const seed(hash()(d.object_ptr_)); return hash::stub_ptr_type>()( - d.stub_ptr_) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + d.stub_ptr_) + 0x9e3779b9 + (seed << 6) + (seed >> 2); } }; } diff --git a/api/utility/membitmap.hpp b/api/utility/membitmap.hpp index bf8606ced3..fe22eb1e67 100644 --- a/api/utility/membitmap.hpp +++ b/api/utility/membitmap.hpp @@ -23,7 +23,7 @@ * In-memory bitmap implementation * * -**/ + **/ namespace fs { @@ -56,15 +56,15 @@ namespace fs { // each word for (index_t i = 0; i < _size; i++) - if (_data[i] != WORD_MAX) - { - // each bit - for (index_t b = 0; b < CHUNK_SIZE; b++) - if (!(_data[i] & (1 << b))) - { - return i * CHUNK_SIZE + b; - } - } // chunk + if (_data[i] != WORD_MAX) + { + // each bit + for (index_t b = 0; b < CHUNK_SIZE; b++) + if (!(_data[i] & (1 << b))) + { + return i * CHUNK_SIZE + b; + } + } // chunk return -1; } // first_free() diff --git a/api/utility/ringbuffer.hpp b/api/utility/ringbuffer.hpp index 88bd7f9f38..1999811a90 100644 --- a/api/utility/ringbuffer.hpp +++ b/api/utility/ringbuffer.hpp @@ -24,110 +24,110 @@ namespace includeOS { - class RingBuffer - { - enum error_t - { - E_OK = 0, - E_NO_SPACE = -1; - E_WRITE_FAILED = -2; - }; + class RingBuffer + { + enum error_t + { + E_OK = 0, + E_NO_SPACE = -1; + E_WRITE_FAILED = -2; + }; - RingBuffer(int size) - { - this->size = size + 1; - this->start = 0; - this->end = 0; - this->buffer = new char[this->size]; - } - ~RingBuffer() - { - if (this->buffer) - delete[] this->buffer; - } + RingBuffer(int size) + { + this->size = size + 1; + this->start = 0; + this->end = 0; + this->buffer = new char[this->size]; + } + ~RingBuffer() + { + if (this->buffer) + delete[] this->buffer; + } - int write(char* data, int length) - { - if (available_data() == 0) - { - this->start = this->end = 0; - } + int write(char* data, int length) + { + if (available_data() == 0) + { + this->start = this->end = 0; + } - if (length > available_space()) - { - return E_NO_SPACE; - } + if (length > available_space()) + { + return E_NO_SPACE; + } - void* result = memcpy(ends_at(), data, length); - if (result == nullptr) - { - return E_WRITE_FAILED; - } + void* result = memcpy(ends_at(), data, length); + if (result == nullptr) + { + return E_WRITE_FAILED; + } - // commit write - this->end = (this->end + length) % this->size; - // return length written - return length; - } + // commit write + this->end = (this->end + length) % this->size; + // return length written + return length; + } - int read(char* dest, int length) - { - check_debug(amount <= RingBuffer_available_data(buffer), - "Not enough in the buffer: has %d, needs %d", - RingBuffer_available_data(buffer), amount); + int read(char* dest, int length) + { + check_debug(amount <= RingBuffer_available_data(buffer), + "Not enough in the buffer: has %d, needs %d", + RingBuffer_available_data(buffer), amount); - void *result = memcpy(target, RingBuffer_starts_at(buffer), amount); - check(result != NULL, "Failed to write buffer into data."); + void *result = memcpy(target, RingBuffer_starts_at(buffer), amount); + check(result != NULL, "Failed to write buffer into data."); - // commit read - this->start = (this->start + length) % this->size; + // commit read + this->start = (this->start + length) % this->size; - if (this->end == this->start) - { - this->start = this->end = 0; - } + if (this->end == this->start) + { + this->start = this->end = 0; + } - return length; - } + return length; + } - #define RingBuffer_available_data(B) (((B)->end + 1) % (B)->length - (B)->start - 1) - #define RingBuffer_available_space(B) ((B)->length - (B)->end - 1) +#define RingBuffer_available_data(B) (((B)->end + 1) % (B)->length - (B)->start - 1) +#define RingBuffer_available_space(B) ((B)->length - (B)->end - 1) - int available_data() const - { - return (this->end + 1) % this->size - this->start - 1; - } - int available_space() const - { - return this-> - } + int available_data() const + { + return (this->end + 1) % this->size - this->start - 1; + } + int available_space() const + { + return this-> + } - const char* starts_at() const - { - return this->buffer + this->end; - } - const char* ends_at() const - { - return this->buffer + this->end; - } + const char* starts_at() const + { + return this->buffer + this->end; + } + const char* ends_at() const + { + return this->buffer + this->end; + } - bool full() const - { - return available_data() - this->size == 0; - } - bool empty() const - { - return available_data() == 0; - } + bool full() const + { + return available_data() - this->size == 0; + } + bool empty() const + { + return available_data() == 0; + } - private: - int size; - int start; - int end; - char* buffer; - }; + private: + int size; + int start; + int end; + char* buffer; + }; } #endif diff --git a/api/utility/signal.hpp b/api/utility/signal.hpp index c15d4cc269..35c672f8f0 100644 --- a/api/utility/signal.hpp +++ b/api/utility/signal.hpp @@ -24,42 +24,42 @@ template class signal { public: - //! \brief Callable type of the signal handlers - using handler = std::function; + //! \brief Callable type of the signal handlers + using handler = std::function; - //! \brief Default constructor - explicit signal() = default; + //! \brief Default constructor + explicit signal() = default; - //! \brief Default destructor - ~signal() noexcept = default; + //! \brief Default destructor + ~signal() noexcept = default; - //! \brief Default move constructor - explicit signal(signal&&) noexcept = default; + //! \brief Default move constructor + explicit signal(signal&&) noexcept = default; - //! \brief Default assignment operator - signal& operator=(signal&&) = default; + //! \brief Default assignment operator + signal& operator=(signal&&) = default; - //! \brief Connect a callable object to this signal - void connect(handler&& fn) { - funcs.emplace_back(std::forward(fn)); - } + //! \brief Connect a callable object to this signal + void connect(handler&& fn) { + funcs.emplace_back(std::forward(fn)); + } - //! \brief Emit this signal by executing all connected callable objects - template - void emit(Args&&... args) { - for(auto& fn : funcs) - fn(std::forward(args)...); - } + //! \brief Emit this signal by executing all connected callable objects + template + void emit(Args&&... args) { + for(auto& fn : funcs) + fn(std::forward(args)...); + } private: - // Set of callable objects registered to be called on demand - std::vector funcs; + // Set of callable objects registered to be called on demand + std::vector funcs; - // Avoid copying - signal(signal const&) = delete; + // Avoid copying + signal(signal const&) = delete; - // Avoid assignment - signal& operator=(signal const&) = delete; + // Avoid assignment + signal& operator=(signal const&) = delete; }; //< class signal #endif //< UTILITY_SIGNAL_HPP diff --git a/api/virtio/console.hpp b/api/virtio/console.hpp index 89b622792d..951789bd9b 100644 --- a/api/virtio/console.hpp +++ b/api/virtio/console.hpp @@ -41,7 +41,7 @@ * placed in the receive queue for incoming data and outgoing * characters are placed in the transmit queue. * -**/ + **/ class VirtioCon : public Virtio { @@ -98,7 +98,7 @@ class VirtioCon : public Virtio /** * Handle device IRQ. * Will look for config. changes and service RX/TX queues as necessary. - **/ + **/ void irq_handler(); Virtio::Queue rx; // 0 diff --git a/api/virtio/virtio.hpp b/api/virtio/virtio.hpp index 4ec99d0cd1..c5affa27b4 100644 --- a/api/virtio/virtio.hpp +++ b/api/virtio/virtio.hpp @@ -16,17 +16,17 @@ // limitations under the License. /** - @note This virtio implementation was very much inspired by - SanOS, (C) Michael Ringgaard. All due respect. + @note This virtio implementation was very much inspired by + SanOS, (C) Michael Ringgaard. All due respect. - STANDARD: + STANDARD: - We're aiming to become standards compilant according to this one: + We're aiming to become standards compilant according to this one: - Virtio 1.0, OASIS Committee Specification Draft 03 - (http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.html) + Virtio 1.0, OASIS Committee Specification Draft 03 + (http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.html) - In the following abbreviated to Virtio 1.03 or Virtio std. + In the following abbreviated to Virtio 1.03 or Virtio std. */ #pragma once #ifndef VIRTIO_VIRTIO_HPP @@ -63,7 +63,7 @@ /** A simple scatter-gather list used for Queue::enqueue. ( From sanos, virtio.h - probably Linux originally) - */ +*/ struct scatterlist { void* data; int size; @@ -76,21 +76,21 @@ class Virtio // http://docs.oasis-open.org/virtio/virtio/v1.0/csprd01/virtio-v1.0-csprd01.html#x1-860005 // Virtio device types enum virtiotype_t - { - RESERVED = 0, - NIC, - BLOCK, - CONSOLE, - ENTROPY, - BALLOON, - IO_MEM, - RP_MSG, - SCSI_HOST, - T9P, - WLAN, - RP_SERIAL, - CAIF - }; + { + RESERVED = 0, + NIC, + BLOCK, + CONSOLE, + ENTROPY, + BALLOON, + IO_MEM, + RP_MSG, + SCSI_HOST, + T9P, + WLAN, + RP_SERIAL, + CAIF + }; /** Virtio Queue class. */ class Queue @@ -111,11 +111,11 @@ class Virtio le32 len; /* This marks a buffer as continuing via the next field. */ - #define VIRTQ_DESC_F_NEXT 1 +#define VIRTQ_DESC_F_NEXT 1 /* This marks a buffer as device write-only (otherwise device read-only). */ - #define VIRTQ_DESC_F_WRITE 2 +#define VIRTQ_DESC_F_WRITE 2 /* This means the buffer contains a list of buffer descriptors. */ - #define VIRTQ_DESC_F_INDIRECT 4 +#define VIRTQ_DESC_F_INDIRECT 4 /* The flags as indicated above. */ le16 flags; /* Next field if flags & NEXT */ @@ -148,7 +148,7 @@ class Virtio le16 flags; le16 idx; struct virtq_used_elem ring[ /* Queue Size */]; - /*le16 avail_event; Only if VIRTIO_F_EVENT_IDX */ + /*le16 avail_event; Only if VIRTIO_F_EVENT_IDX */ }; @@ -299,7 +299,7 @@ class Virtio /** Indicate which Virtio version (PCI revision ID) is supported. Currently only Legacy is supported (partially the 1.0 standard) - */ + */ static inline bool version_supported(uint16_t i) { return i <= 0; } diff --git a/etc/batch_apply_editorconfig.sh b/etc/batch_apply_editorconfig.sh old mode 100644 new mode 100755 diff --git a/examples/demo_service/service.cpp b/examples/demo_service/service.cpp index 7acabb6e33..4b69193b60 100644 --- a/examples/demo_service/service.cpp +++ b/examples/demo_service/service.cpp @@ -49,58 +49,58 @@ void Service::start() { auto& server = inet->tcp().bind(80); hw::PIT::instance().onRepeatedTimeout(30s, []{ - printf(" TCP STATUS:\n%s \n", inet->tcp().status().c_str()); - }); + printf(" TCP STATUS:\n%s \n", inet->tcp().status().c_str()); + }); // Add a TCP connection handler - here a hardcoded HTTP-service server.onAccept([](auto conn) -> bool { printf(" @onAccept - Connection attempt from: %s \n", - conn->to_string().c_str()); + conn->to_string().c_str()); return true; // allow all connections - }).onConnect([](auto) { - printf(" @onConnect - Connection successfully established.\n"); + }).onConnect([](auto) { + printf(" @onConnect - Connection successfully established.\n"); - }).onReceive([](auto conn, bool push) { - std::string data = conn->read(1024); - printf(" @onData - PUSH: %d, Data read: \n%s\n", push, data.c_str()); - int color = rand(); - std::stringstream stream; + }).onReceive([](auto conn, bool push) { + std::string data = conn->read(1024); + printf(" @onData - PUSH: %d, Data read: \n%s\n", push, data.c_str()); + int color = rand(); + std::stringstream stream; - /* HTML Fonts */ - std::string ubuntu_medium = "font-family: \'Ubuntu\', sans-serif; font-weight: 500; "; - std::string ubuntu_normal = "font-family: \'Ubuntu\', sans-serif; font-weight: 400; "; - std::string ubuntu_light = "font-family: \'Ubuntu\', sans-serif; font-weight: 300; "; + /* HTML Fonts */ + std::string ubuntu_medium = "font-family: \'Ubuntu\', sans-serif; font-weight: 500; "; + std::string ubuntu_normal = "font-family: \'Ubuntu\', sans-serif; font-weight: 400; "; + std::string ubuntu_light = "font-family: \'Ubuntu\', sans-serif; font-weight: 300; "; - /* HTML */ - stream << "" - << "" - << "" - << "

> 8) << "\">" - << "IncludeOS

" - << "

Now speaks TCP!

" - // .... generate more dynamic content - << "

...and can improvise http. With limitations of course, but it's been easier than expected so far

" - << "

© 2015, Oslo and Akershus University College of Applied Sciences
" - << "\n"; + /* HTML */ + stream << "" + << "" + << "" + << "

> 8) << "\">" + << "IncludeOS

" + << "

Now speaks TCP!

" + // .... generate more dynamic content + << "

...and can improvise http. With limitations of course, but it's been easier than expected so far

" + << "

© 2015, Oslo and Akershus University College of Applied Sciences
" + << "\n"; - /* HTTP-header */ - std::string html = stream.str(); - std::string header="HTTP/1.1 200 OK \n " \ - "Date: Mon, 01 Jan 1970 00:00:01 GMT \n" \ - "Server: IncludeOS prototype 4.0 \n" \ - "Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT \n" \ - "Content-Type: text/html; charset=UTF-8 \n" \ - "Content-Length: "+std::to_string(html.size())+"\n" \ - "Accept-Ranges: bytes\n" \ - "Connection: close\n\n"; + /* HTTP-header */ + std::string html = stream.str(); + std::string header="HTTP/1.1 200 OK \n " \ + "Date: Mon, 01 Jan 1970 00:00:01 GMT \n" \ + "Server: IncludeOS prototype 4.0 \n" \ + "Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT \n" \ + "Content-Type: text/html; charset=UTF-8 \n" \ + "Content-Length: "+std::to_string(html.size())+"\n" \ + "Accept-Ranges: bytes\n" \ + "Connection: close\n\n"; - std::string output{header + html}; - conn->write(output.data(), output.size()); + std::string output{header + html}; + conn->write(output.data(), output.size()); - }).onDisconnect([](auto, auto reason) { - printf(" @onDisconnect - Reason: %s \n", reason.to_string().c_str()); - }); + }).onDisconnect([](auto, auto reason) { + printf(" @onDisconnect - Reason: %s \n", reason.to_string().c_str()); + }); printf("*** TEST SERVICE STARTED *** \n"); } diff --git a/examples/tcp/service.cpp b/examples/tcp/service.cpp index f944aa6fb2..610a7edebf 100644 --- a/examples/tcp/service.cpp +++ b/examples/tcp/service.cpp @@ -16,16 +16,16 @@ // limitations under the License. /* - An example to show incoming and outgoing TCP Connections. - In this example, IncludeOS is listening on port 80. + An example to show incoming and outgoing TCP Connections. + In this example, IncludeOS is listening on port 80. - Data received on port 80 will be redirected to a - outgoing connection to a (in this case) python server (server.py) + Data received on port 80 will be redirected to a + outgoing connection to a (in this case) python server (server.py) - Data received from the python server connection - will be redirected back to the client. + Data received from the python server connection + will be redirected back to the client. - To try it out, use netcat to connect to this IncludeOS instance. + To try it out, use netcat to connect to this IncludeOS instance. */ #include @@ -43,19 +43,19 @@ net::TCP::Socket python_server{ {{10,0,2,2}} , 1337}; // Called when data is received on client (incoming connection) void handle_client_on_receive(Connection_ptr client, Connection_ptr python) { - // Read the request from our client - std::string request = client->read(1024); - printf("Received [Client]: %s\n", request.c_str()); - // Write the request to our python server - python->write(request); + // Read the request from our client + std::string request = client->read(1024); + printf("Received [Client]: %s\n", request.c_str()); + // Write the request to our python server + python->write(request); } // Called when data is received on python (outgoing connection) void handle_python_on_receive(Connection_ptr python, Connection_ptr client) { - // Read the response from our python server - std::string response = python->read(1024); - // Write response to our client - client->write(response); + // Read the response from our python server + std::string response = python->read(1024); + // Write response to our client + client->write(response); } void Service::start() { @@ -74,41 +74,41 @@ void Service::start() { // Set up a TCP server on port 80 auto& server = inet->tcp().bind(80); inet->dhclient()->on_config([&server](auto&) { - printf("Server IP updated: %s\n", server.local().to_string().c_str()); - }); + printf("Server IP updated: %s\n", server.local().to_string().c_str()); + }); printf("Server listening: %s \n", server.local().to_string().c_str()); // When someone connects to our server server.onConnect([](Connection_ptr client) { - printf("Connected [Client]: %s\n", client->to_string().c_str()); - // Make an outgoing connection to our python server - auto outgoing = inet->tcp().connect(python_server); - // When outgoing connection to python sever is established - outgoing->onConnect([client](Connection_ptr python) { - printf("Connected [Python]: %s\n", python->to_string().c_str()); + printf("Connected [Client]: %s\n", client->to_string().c_str()); + // Make an outgoing connection to our python server + auto outgoing = inet->tcp().connect(python_server); + // When outgoing connection to python sever is established + outgoing->onConnect([client](Connection_ptr python) { + printf("Connected [Python]: %s\n", python->to_string().c_str()); - // Setup handlers for when data is received on client and python connection - // When client has data to be read - client->onReceive([python](Connection_ptr client, bool) { - handle_client_on_receive(client, python); - }); + // Setup handlers for when data is received on client and python connection + // When client has data to be read + client->onReceive([python](Connection_ptr client, bool) { + handle_client_on_receive(client, python); + }); - // When python server has data to be read - python->onReceive([client](Connection_ptr python, bool) { - handle_python_on_receive(python, client); - }); + // When python server has data to be read + python->onReceive([client](Connection_ptr python, bool) { + handle_python_on_receive(python, client); + }); - // When client is disconnecting - client->onDisconnect([python](Connection_ptr, Disconnect reason) { - printf("Disconnected [Client]: %s\n", reason.to_string().c_str()); - python->close(); - }); + // When client is disconnecting + client->onDisconnect([python](Connection_ptr, Disconnect reason) { + printf("Disconnected [Client]: %s\n", reason.to_string().c_str()); + python->close(); + }); - // When python is disconnecting - python->onDisconnect([client](Connection_ptr, Disconnect reason) { - printf("Disconnected [Python]: %s\n", reason.to_string().c_str()); - client->close(); - }); - }); // << onConnect (outgoing (python)) - }); // << onConnect (client) + // When python is disconnecting + python->onDisconnect([client](Connection_ptr, Disconnect reason) { + printf("Disconnected [Python]: %s\n", reason.to_string().c_str()); + client->close(); + }); + }); // << onConnect (outgoing (python)) + }); // << onConnect (client) } diff --git a/src/crt/cxx_abi.cpp b/src/crt/cxx_abi.cpp index 911ead7b00..40617afe7f 100644 --- a/src/crt/cxx_abi.cpp +++ b/src/crt/cxx_abi.cpp @@ -22,7 +22,7 @@ * This header is for instantiating and implementing * missing functionality gluing libc++ to the kernel * -**/ + **/ #include extern "C" diff --git a/src/crt/mman.cpp b/src/crt/mman.cpp index d82a15511d..23f99aef44 100644 --- a/src/crt/mman.cpp +++ b/src/crt/mman.cpp @@ -20,15 +20,15 @@ struct mmap_entry_t std::map _mmap_entries; void* mmap(void* addr, size_t length, - int prot, int flags, - int fd, off_t offset) + int prot, int flags, + int fd, off_t offset) { // invalid or misaligned length if (length == 0 || (length & 4095) != 0) - { - errno = EINVAL; - return MAP_FAILED; - } + { + errno = EINVAL; + return MAP_FAILED; + } // associate some VA space with open file @fd // for now just allocate page-aligned on heap @@ -53,15 +53,15 @@ int munmap(void* addr, size_t length) { auto it = _mmap_entries.find(addr); if (it != _mmap_entries.end()) - { - // - assert(it->second.length == length); + { + // + assert(it->second.length == length); - // free and remove the entry - free(it->second.addr); - _mmap_entries.erase(it); - return 0; - } + // free and remove the entry + free(it->second.addr); + _mmap_entries.erase(it); + return 0; + } errno = EINVAL; return -1; } diff --git a/src/debug/ircd.cpp b/src/debug/ircd.cpp index f4ca803615..84068f8a8c 100644 --- a/src/debug/ircd.cpp +++ b/src/debug/ircd.cpp @@ -12,9 +12,9 @@ void Client::split_message(const std::string& msg) printf("[Client]: "); for (auto& str : vec) - { - printf("[%s]", str.c_str()); - } + { + printf("[%s]", str.c_str()); + } printf("\n"); // ignore empty messages if (vec.size() == 0) return; @@ -25,47 +25,47 @@ void Client::split_message(const std::string& msg) void Client::read(const char* buf, size_t len) { while (len > 0) - { - int search = -1; - - for (size_t i = 0; i < len; i++) - if (buf[i] == 13 || buf[i] == 10) - { - search = i; break; - } - // not found: - if (search == -1) - { - // append entire buffer - buffer.append(buf, len); - break; - } - else { - // found CR LF: - if (search != 0) - { - // append to clients buffer - buffer.append(buf, search); - - // move forward in socket buffer - buf += search; - // decrease len - len -= search; - } + int search = -1; + + for (size_t i = 0; i < len; i++) + if (buf[i] == 13 || buf[i] == 10) + { + search = i; break; + } + // not found: + if (search == -1) + { + // append entire buffer + buffer.append(buf, len); + break; + } else - { - buf++; len--; - } + { + // found CR LF: + if (search != 0) + { + // append to clients buffer + buffer.append(buf, search); + + // move forward in socket buffer + buf += search; + // decrease len + len -= search; + } + else + { + buf++; len--; + } - // parse message - if (buffer.size()) - { - split_message(buffer); - buffer.clear(); - } + // parse message + if (buffer.size()) + { + split_message(buffer); + buffer.clear(); + } + } } - } } void Client::send(uint16_t numeric, std::string text) @@ -94,59 +94,59 @@ void Client::send(std::string text) void Client::handle(const std::string&, const std::vector& msg) { - #define TK_CAP "CAP" - #define TK_PASS "PASS" - #define TK_NICK "NICK" - #define TK_USER "USER" +#define TK_CAP "CAP" +#define TK_PASS "PASS" +#define TK_NICK "NICK" +#define TK_USER "USER" const std::string& cmd = msg[0]; if (this->is_reg() == false) - { - if (cmd == TK_CAP) - { - // ignored completely - } - else if (cmd == TK_PASS) { - if (msg.size() > 1) - { - this->passw = msg[1]; - } + if (cmd == TK_CAP) + { + // ignored completely + } + else if (cmd == TK_PASS) + { + if (msg.size() > 1) + { + this->passw = msg[1]; + } + else + { + send(ERR_NEEDMOREPARAMS, cmd + " :Not enough parameters"); + } + } + else if (cmd == TK_NICK) + { + if (msg.size() > 1) + { + this->nick = msg[1]; + welcome(regis | 1); + } + else + { + send(ERR_NEEDMOREPARAMS, cmd + " :Not enough parameters"); + } + } + else if (cmd == TK_USER) + { + if (msg.size() > 1) + { + this->user = msg[1]; + welcome(regis | 2); + } + else + { + send(ERR_NEEDMOREPARAMS, cmd + " :Not enough parameters"); + } + } else - { - send(ERR_NEEDMOREPARAMS, cmd + " :Not enough parameters"); - } + { + send(ERR_NOSUCHCMD, cmd + " :Unknown command"); + } } - else if (cmd == TK_NICK) - { - if (msg.size() > 1) - { - this->nick = msg[1]; - welcome(regis | 1); - } - else - { - send(ERR_NEEDMOREPARAMS, cmd + " :Not enough parameters"); - } - } - else if (cmd == TK_USER) - { - if (msg.size() > 1) - { - this->user = msg[1]; - welcome(regis | 2); - } - else - { - send(ERR_NEEDMOREPARAMS, cmd + " :Not enough parameters"); - } - } - else - { - send(ERR_NOSUCHCMD, cmd + " :Unknown command"); - } - } } #define RPL_WELCOME 1 @@ -162,15 +162,15 @@ void Client::welcome(uint8_t newreg) regis = newreg; // not registered before, but registered now if (!regged && is_reg()) - { - printf("* Registered: %s\n", nickuserhost().c_str()); - send(RPL_WELCOME, ":Welcome to the Internet Relay Network, " + nickuserhost()); - send(RPL_YOURHOST, ":Your host is " + SERVER_NAME + ", running v1.0"); - } + { + printf("* Registered: %s\n", nickuserhost().c_str()); + send(RPL_WELCOME, ":Welcome to the Internet Relay Network, " + nickuserhost()); + send(RPL_YOURHOST, ":Your host is " + SERVER_NAME + ", running v1.0"); + } else if (oldreg == 0) - { - auth_notice(); - } + { + auth_notice(); + } } void Client::auth_notice() { diff --git a/src/debug/ircsplit.hpp b/src/debug/ircsplit.hpp index f9a572a962..e195f79e09 100644 --- a/src/debug/ircsplit.hpp +++ b/src/debug/ircsplit.hpp @@ -10,40 +10,40 @@ split(const std::string& text, std::string& source) if (text.empty()) return retv; // check for source if (text[0] == ':') - { - x = text.find(" ", 1); - source = text.substr(x); - // early return for source-only msg - if (x == std::string::npos) return retv; - p = x+1; - } - // parse remainder - do - { - x = text.find(" ", p+1); - size_t y = text.find(":", x+1); // find last param - - if (y == x+1) - { - // single argument - retv.push_back(text.substr(p, x-p)); - // ending text argument - retv.push_back(text.substr(y+1)); - break; - } - else if (x != std::string::npos) { - // single argument - retv.push_back(text.substr(p, x-p)); + x = text.find(" ", 1); + source = text.substr(x); + // early return for source-only msg + if (x == std::string::npos) return retv; + p = x+1; } - else + // parse remainder + do { - // last argument - retv.push_back(text.substr(p)); - } - p = x+1; + x = text.find(" ", p+1); + size_t y = text.find(":", x+1); // find last param + + if (y == x+1) + { + // single argument + retv.push_back(text.substr(p, x-p)); + // ending text argument + retv.push_back(text.substr(y+1)); + break; + } + else if (x != std::string::npos) + { + // single argument + retv.push_back(text.substr(p, x-p)); + } + else + { + // last argument + retv.push_back(text.substr(p)); + } + p = x+1; - } while (x != std::string::npos); + } while (x != std::string::npos); return retv; } diff --git a/src/debug/test_disk.cpp b/src/debug/test_disk.cpp index 71f0f0630c..c52289d5aa 100644 --- a/src/debug/test_disk.cpp +++ b/src/debug/test_disk.cpp @@ -23,106 +23,106 @@ void Service::start() // mount first valid partition (auto-detect and mount) disk->mount( // or specify partition explicitly in parameter - [] (fs::error_t err) - { - if (err) - { - printf("Could not mount filesystem\n"); - return; - } - // get a reference to the mounted filesystem - auto& fs = disk->fs(); + [] (fs::error_t err) + { + if (err) + { + printf("Could not mount filesystem\n"); + return; + } + // get a reference to the mounted filesystem + auto& fs = disk->fs(); - // check contents of disk - auto dirents = fs::new_shared_vector(); - err = fs.ls("/", dirents); - if (err) - printf("Could not list '/' directory\n"); - else - for (auto& e : *dirents) - { - printf("%s: %s\t of size %llu bytes (CL: %llu)\n", - e.type_string().c_str(), e.name().c_str(), e.size, e.block); - } + // check contents of disk + auto dirents = fs::new_shared_vector(); + err = fs.ls("/", dirents); + if (err) + printf("Could not list '/' directory\n"); + else + for (auto& e : *dirents) + { + printf("%s: %s\t of size %llu bytes (CL: %llu)\n", + e.type_string().c_str(), e.name().c_str(), e.size, e.block); + } - auto ent = fs.stat("/test.txt"); - // validate the stat call - if (ent.is_valid()) - { - // read specific area of file - auto buf = fs.read(ent, 1032, 65); - std::string contents((const char*) buf.buffer.get(), buf.len); - printf("[%s contents (%llu bytes)]:\n%s\n[end]\n\n", - ent.name().c_str(), buf.len, contents.c_str()); + auto ent = fs.stat("/test.txt"); + // validate the stat call + if (ent.is_valid()) + { + // read specific area of file + auto buf = fs.read(ent, 1032, 65); + std::string contents((const char*) buf.buffer.get(), buf.len); + printf("[%s contents (%llu bytes)]:\n%s\n[end]\n\n", + ent.name().c_str(), buf.len, contents.c_str()); - } - else - { - printf("Invalid entity for /test.txt\n"); - } - return; + } + else + { + printf("Invalid entity for /test.txt\n"); + } + return; - disk->fs().ls("/", - [] (fs::error_t err, auto ents) - { - if (err) - { - printf("Could not list '/' directory\n"); - return; - } + disk->fs().ls("/", + [] (fs::error_t err, auto ents) + { + if (err) + { + printf("Could not list '/' directory\n"); + return; + } - for (auto& e : *ents) - { - printf("%s: %s\t of size %llu bytes (CL: %llu)\n", - e.type_string().c_str(), e.name().c_str(), e.size, e.block); + for (auto& e : *ents) + { + printf("%s: %s\t of size %llu bytes (CL: %llu)\n", + e.type_string().c_str(), e.name().c_str(), e.size, e.block); - if (e.is_file()) - { - printf("*** Attempting to read: %s\n", e.name().c_str()); - disk->fs().read(e, 0, e.size, - [e] (fs::error_t err, fs::buffer_t buffer, size_t len) - { - if (err) - { - printf("Failed to read file %s!\n", - e.name().c_str()); - return; - } + if (e.is_file()) + { + printf("*** Attempting to read: %s\n", e.name().c_str()); + disk->fs().read(e, 0, e.size, + [e] (fs::error_t err, fs::buffer_t buffer, size_t len) + { + if (err) + { + printf("Failed to read file %s!\n", + e.name().c_str()); + return; + } - std::string contents((const char*) buffer.get(), len); - printf("[%s contents]:\n%s\nEOF\n\n", - e.name().c_str(), contents.c_str()); - }); - } - } - }); + std::string contents((const char*) buffer.get(), len); + printf("[%s contents]:\n%s\nEOF\n\n", + e.name().c_str(), contents.c_str()); + }); + } + } + }); - disk->fs().stat("/test.txt", - [] (fs::error_t err, const auto& e) - { - if (err) - { - printf("Could not stat %s\n", e.name().c_str()); - return; - } + disk->fs().stat("/test.txt", + [] (fs::error_t err, const auto& e) + { + if (err) + { + printf("Could not stat %s\n", e.name().c_str()); + return; + } - printf("stat: /test.txt is a %s on cluster %llu\n", - e.type_string().c_str(), e.block); - }); - disk->fs().stat("/Sample Pictures/Koala.jpg", - [] (fs::error_t err, const auto& e) - { - if (err) - { - printf("Could not stat %s\n", e.name().c_str()); - return; - } + printf("stat: /test.txt is a %s on cluster %llu\n", + e.type_string().c_str(), e.block); + }); + disk->fs().stat("/Sample Pictures/Koala.jpg", + [] (fs::error_t err, const auto& e) + { + if (err) + { + printf("Could not stat %s\n", e.name().c_str()); + return; + } - printf("stat: %s is a %s on cluster %llu\n", - e.name().c_str(), e.type_string().c_str(), e.block); - }); + printf("stat: %s is a %s on cluster %llu\n", + e.name().c_str(), e.type_string().c_str(), e.block); + }); - }); // disk->auto_detect() + }); // disk->auto_detect() printf("*** TEST SERVICE STARTED *** \n"); } @@ -130,16 +130,16 @@ void Service::start() void list_partitions(decltype(disk) disk) { disk->partitions( - [] (fs::error_t err, auto& parts) - { - if (err) - { - printf("Failed to retrieve volumes on disk\n"); - return; - } + [] (fs::error_t err, auto& parts) + { + if (err) + { + printf("Failed to retrieve volumes on disk\n"); + return; + } - for (auto& part : parts) - printf("[Partition] '%s' at LBA %u\n", - part.name().c_str(), part.lba()); - }); + for (auto& part : parts) + printf("[Partition] '%s' at LBA %u\n", + part.name().c_str(), part.lba()); + }); } diff --git a/src/debug/test_ipv6.cpp b/src/debug/test_ipv6.cpp index 7fe76ff46d..9bb1b0d917 100644 --- a/src/debug/test_ipv6.cpp +++ b/src/debug/test_ipv6.cpp @@ -40,9 +40,9 @@ void Service::start() // basic UDP service net::Inet::ifconfig( - net::ETH0, - ip4, {{255, 255, 255, 0}}, - ip6); + net::ETH0, + ip4, {{255, 255, 255, 0}}, + ip6); net::Inet* inet = net::Inet::up(); @@ -64,37 +64,37 @@ void Service::start() // basic UDP service static const int UDP_PORT = 64; inet->udp6_listen(UDP_PORT, - [=] (std::shared_ptr& pckt) -> int - { - printf("Received UDP6 packet from %s to my listener on port %d\n", - pckt->src().str().c_str(), pckt->dst_port()); + [=] (std::shared_ptr& pckt) -> int + { + printf("Received UDP6 packet from %s to my listener on port %d\n", + pckt->src().str().c_str(), pckt->dst_port()); - std::string data((const char*) pckt->data(), pckt->data_length()); + std::string data((const char*) pckt->data(), pckt->data_length()); - printf("Contents (len=%d):\n%s\n", pckt->data_length(), data.c_str()); + printf("Contents (len=%d):\n%s\n", pckt->data_length(), data.c_str()); - // unfortunately, - // copy the ether src field of the incoming packet - net::Ethernet::addr ether_src = - ((net::Ethernet::header*) pckt->buffer())->src; + // unfortunately, + // copy the ether src field of the incoming packet + net::Ethernet::addr ether_src = + ((net::Ethernet::header*) pckt->buffer())->src; - // create a response packet with destination [ether_src] dst() - std::shared_ptr newpacket = - inet->udp6_create(ether_src, pckt->dst(), UDP_PORT); + // create a response packet with destination [ether_src] dst() + std::shared_ptr newpacket = + inet->udp6_create(ether_src, pckt->dst(), UDP_PORT); - const char* text = "This is the response packet!"; - // copy text into UDP data section - memcpy( newpacket->data(), text, strlen(text) ); - // set new length - newpacket->set_length(strlen(text)); + const char* text = "This is the response packet!"; + // copy text into UDP data section + memcpy( newpacket->data(), text, strlen(text) ); + // set new length + newpacket->set_length(strlen(text)); - // generate checksum for packet before sending - newpacket->gen_checksum(); + // generate checksum for packet before sending + newpacket->gen_checksum(); - // ship it to the ether - inet->udp6_send(newpacket); - return -1; - } - ); + // ship it to the ether + inet->udp6_send(newpacket); + return -1; + } + ); } diff --git a/src/debug/test_service.cpp b/src/debug/test_service.cpp index c8c14099b7..2553927806 100644 --- a/src/debug/test_service.cpp +++ b/src/debug/test_service.cpp @@ -35,19 +35,19 @@ void Service::start() hw::Nic& eth0 = hw::Dev::eth<0,VirtioNet>(); inet = std::make_unique >(eth0); inet->network_config( - {{ 10,0,0,42 }}, // IP - {{ 255,255,255,0 }}, // Netmask - {{ 10,0,0,1 }}, // Gateway - {{ 8,8,8,8 }} ); // DNS + {{ 10,0,0,42 }}, // IP + {{ 255,255,255,0 }}, // Netmask + {{ 10,0,0,1 }}, // Gateway + {{ 8,8,8,8 }} ); // DNS /* - auto& tcp = inet->tcp(); - auto& server = tcp.bind(6667); // IRCd default port - server.onConnect( - [] (auto csock) - { + auto& tcp = inet->tcp(); + auto& server = tcp.bind(6667); // IRCd default port + server.onConnect( + [] (auto csock) + { printf("*** Received connection from %s\n", - csock->remote().to_string().c_str()); + csock->remote().to_string().c_str()); /// create client /// size_t index = clients.size(); @@ -59,22 +59,22 @@ void Service::start() csock->onReceive( [&client] (auto conn, bool) { - char buffer[1024]; - size_t bytes = conn->read(buffer, sizeof(buffer)); + char buffer[1024]; + size_t bytes = conn->read(buffer, sizeof(buffer)); - client.read(buffer, bytes); + client.read(buffer, bytes); }); .onDisconnect( [&client] (auto conn, std::string) { - // remove client from various lists - client.remove(); - /// inform others about disconnect - //client.bcast(TK_QUIT, "Disconnected"); + // remove client from various lists + client.remove(); + /// inform others about disconnect + //client.bcast(TK_QUIT, "Disconnected"); }); - });*/ + });*/ /// terminal /// auto& serial = hw::Serial::port<1> (); @@ -82,12 +82,12 @@ void Service::start() term = std::make_unique (serial); // add 'ifconfig' command term->add( - "ifconfig", "Show information about interfaces", - [] (const std::vector&) -> int - { - term->write("%s\r\n", inet->tcp().status().c_str()); - return 0; - }); + "ifconfig", "Show information about interfaces", + [] (const std::vector&) -> int + { + term->write("%s\r\n", inet->tcp().status().c_str()); + return 0; + }); /// terminal /// printf("*** TEST SERVICE STARTED *** \n"); diff --git a/src/debug/test_tcp.cpp b/src/debug/test_tcp.cpp index 4318d649f4..f42594c305 100644 --- a/src/debug/test_tcp.cpp +++ b/src/debug/test_tcp.cpp @@ -41,18 +41,18 @@ void Service::start() { auto& server = inet->tcp().bind(80); hw::PIT::instance().onTimeout(5s, [server]{ - printf("Server is running: %s \n", server.to_string().c_str()); - }); + printf("Server is running: %s \n", server.to_string().c_str()); + }); server.onPacketReceived([](auto conn, auto packet) { - printf(" Received: %s\n", packet->to_string().c_str()); + printf(" Received: %s\n", packet->to_string().c_str()); - }).onPacketDropped([](auto packet, std::string reason) { - printf(" Dropped: %s - Reason: %s \n", packet->to_string().c_str(), reason.c_str()); + }).onPacketDropped([](auto packet, std::string reason) { + printf(" Dropped: %s - Reason: %s \n", packet->to_string().c_str(), reason.c_str()); - }).onReceive([](auto conn, bool) { - conn->write("Hey"); - }).onConnect([](auto conn) { - printf(" Connected.\n"); - }); + }).onReceive([](auto conn, bool) { + conn->write("Hey"); + }).onConnect([](auto conn) { + printf(" Connected.\n"); + }); } diff --git a/src/fs/disk.cpp b/src/fs/disk.cpp index c7828319c5..f6e8afa24a 100644 --- a/src/fs/disk.cpp +++ b/src/fs/disk.cpp @@ -21,131 +21,131 @@ namespace fs { -Disk::Disk(hw::IDiskDevice& dev) - : device {dev} + Disk::Disk(hw::IDiskDevice& dev) + : device {dev} { // for now we can only assume FAT, anyways filesys.reset(new FAT(device)); } -void Disk::partitions(on_parts_func func) { + void Disk::partitions(on_parts_func func) { - /** Read Master Boot Record (sector 0) */ - device.read(0, - [this, func] (hw::IDiskDevice::buffer_t data) - { - std::vector parts; + /** Read Master Boot Record (sector 0) */ + device.read(0, + [this, func] (hw::IDiskDevice::buffer_t data) + { + std::vector parts; - if (!data) { - func(true, parts); - return; - } + if (!data) { + func(true, parts); + return; + } - // First sector is the Master Boot Record - auto* mbr =(MBR::mbr*) data.get(); + // First sector is the Master Boot Record + auto* mbr =(MBR::mbr*) data.get(); - for (int i {0}; i < 4; ++i) { - // all the partitions are offsets to potential Volume Boot Records - parts.emplace_back( - mbr->part[i].flags, //< flags - mbr->part[i].type, //< id - mbr->part[i].lba_begin, //< LBA - mbr->part[i].sectors); - } + for (int i {0}; i < 4; ++i) { + // all the partitions are offsets to potential Volume Boot Records + parts.emplace_back( + mbr->part[i].flags, //< flags + mbr->part[i].type, //< id + mbr->part[i].lba_begin, //< LBA + mbr->part[i].sectors); + } - func(no_error, parts); - }); -} + func(no_error, parts); + }); + } -void Disk::mount(on_mount_func func) -{ - device.read(0, - [this, func] (hw::IDiskDevice::buffer_t data) + void Disk::mount(on_mount_func func) { - if (!data) { - // TODO: error-case for unable to read MBR - mount(INVALID, func); - return; - } + device.read(0, + [this, func] (hw::IDiskDevice::buffer_t data) + { + if (!data) { + // TODO: error-case for unable to read MBR + mount(INVALID, func); + return; + } - // auto-detect FAT on MBR: - auto* mbr = (MBR::mbr*) data.get(); - MBR::BPB* bpb = mbr->bpb(); + // auto-detect FAT on MBR: + auto* mbr = (MBR::mbr*) data.get(); + MBR::BPB* bpb = mbr->bpb(); - if (bpb->bytes_per_sector >= 512 - && bpb->fa_tables != 0 - && bpb->signature != 0) // check MBR signature too - { - // we have FAT on MBR (and we are assuming mount FAT) - mount(MBR, func); - return; - } + if (bpb->bytes_per_sector >= 512 + && bpb->fa_tables != 0 + && bpb->signature != 0) // check MBR signature too + { + // we have FAT on MBR (and we are assuming mount FAT) + mount(MBR, func); + return; + } - // go through partition list - for (int i = 0; i < 4; i++) - { - if (mbr->part[i].type != 0 // 0 is unused partition - && mbr->part[i].lba_begin != 0 // 0 is MBR anyways - && mbr->part[i].sectors != 0) // 0 means no size, so... - { - mount((partition_t) (VBR1 + i), func); - return; - } - } + // go through partition list + for (int i = 0; i < 4; i++) + { + if (mbr->part[i].type != 0 // 0 is unused partition + && mbr->part[i].lba_begin != 0 // 0 is MBR anyways + && mbr->part[i].sectors != 0) // 0 means no size, so... + { + mount((partition_t) (VBR1 + i), func); + return; + } + } - // no partition was found (TODO: extended partitions) - mount(INVALID, func); - return; - }); -} + // no partition was found (TODO: extended partitions) + mount(INVALID, func); + return; + }); + } -void Disk::mount(partition_t part, on_mount_func func) { + void Disk::mount(partition_t part, on_mount_func func) { - if (part == INVALID) - { - // Something bad happened maybe in auto-detect - // Either way, no partition was found - func(true); - return; - } - else if (part == MBR) - { - // For the MBR case, all we need to do is mount on sector 0 - fs().mount(0, device.size(), func); - } - else - { - /** - * Otherwise, we will have to read the LBA offset - * of the partition to be mounted - */ - device.read(0, - [this, part, func] (hw::IDiskDevice::buffer_t data) - { - if (!data) { - // TODO: error-case for unable to read MBR - func(true); - return; + if (part == INVALID) + { + // Something bad happened maybe in auto-detect + // Either way, no partition was found + func(true); + return; + } + else if (part == MBR) + { + // For the MBR case, all we need to do is mount on sector 0 + fs().mount(0, device.size(), func); } + else + { + /** + * Otherwise, we will have to read the LBA offset + * of the partition to be mounted + */ + device.read(0, + [this, part, func] (hw::IDiskDevice::buffer_t data) + { + if (!data) { + // TODO: error-case for unable to read MBR + func(true); + return; + } - auto* mbr = (MBR::mbr*) data.get(); //< Treat data as MBR - auto pint = static_cast(part - 1); //< Treat VBR1 as index 0 etc. + auto* mbr = (MBR::mbr*) data.get(); //< Treat data as MBR + auto pint = static_cast(part - 1); //< Treat VBR1 as index 0 etc. - /** Get LBA from selected partition */ - auto lba_base = mbr->part[pint].lba_begin; - auto lba_size = mbr->part[pint].sectors; + /** Get LBA from selected partition */ + auto lba_base = mbr->part[pint].lba_begin; + auto lba_size = mbr->part[pint].sectors; - /** - * Call the filesystems mount function - * with lba_begin as base address - */ - fs().mount(lba_base, lba_size, func); - }); + /** + * Call the filesystems mount function + * with lba_begin as base address + */ + fs().mount(lba_base, lba_size, func); + }); + } } -} -std::string Disk::Partition::name() const { - return MBR::id_to_name(id); -} + std::string Disk::Partition::name() const { + return MBR::id_to_name(id); + } } //< namespace fs diff --git a/src/fs/ext4.cpp b/src/fs/ext4.cpp index 7a6e26cd9b..a361e72173 100644 --- a/src/fs/ext4.cpp +++ b/src/fs/ext4.cpp @@ -19,26 +19,26 @@ namespace fs void EXT4::mount(uint64_t start, uint64_t size, on_mount_func on_mount) { printf("Superblock: %u bytes, Block group desc: %u bytes\n", - sizeof(superblock), sizeof(group_desc)); + sizeof(superblock), sizeof(group_desc)); assert(sizeof(superblock) == 1024); assert(sizeof(group_desc) == 64); printf("Inode table: %u\n", - sizeof(inode_table)); + sizeof(inode_table)); // read Master Boot Record (sector 0) device.read(start, - [this, start, size, on_mount] (buffer_t data) - { - auto* mbr = (MBR::mbr*) data.get(); - assert(mbr != nullptr); + [this, start, size, on_mount] (buffer_t data) + { + auto* mbr = (MBR::mbr*) data.get(); + assert(mbr != nullptr); - /// now what? - printf("Mounting EXT4 from LBA %llu to %llu\n", - start, size); + /// now what? + printf("Mounting EXT4 from LBA %llu to %llu\n", + start, size); - init(data.get()); - }); + init(data.get()); + }); } diff --git a/src/fs/fat.cpp b/src/fs/fat.cpp index 361c5dfc81..72a126a5de 100644 --- a/src/fs/fat.cpp +++ b/src/fs/fat.cpp @@ -15,8 +15,8 @@ #define unlikely(x) __builtin_expect(!!(x), 0) inline std::string trim_right_copy( - const std::string& s, - const std::string& delimiters = " \f\n\r\t\v" ) + const std::string& s, + const std::string& delimiters = " \f\n\r\t\v" ) { return s.substr( 0, s.find_last_not_of( delimiters ) + 1 ); } @@ -37,11 +37,11 @@ namespace fs MBR::BPB* bpb = mbr->bpb(); this->sector_size = bpb->bytes_per_sector; if (unlikely(this->sector_size < 512)) - { - printf("Invalid sector size (%u) for FAT32 partition\n", sector_size); - printf("Are you mounting the correct partition?\n"); - panic("FAT32: Invalid sector size"); - } + { + printf("Invalid sector size (%u) for FAT32 partition\n", sector_size); + printf("Are you mounting the correct partition?\n"); + panic("FAT32: Invalid sector size"); + } // Let's begin our incantation // To drive out the demons of old DOS we have to read some PBP values @@ -70,7 +70,7 @@ namespace fs // sectors per FAT (not sure about the rule here) this->sectors_per_fat = bpb->sectors_per_fat; if (this->sectors_per_fat == 0) - this->sectors_per_fat = *(uint32_t*) &mbr->boot[25]; + this->sectors_per_fat = *(uint32_t*) &mbr->boot[25]; // root dir sectors from root entries this->root_dir_sectors = ((bpb->root_entries * 32) + (sector_size - 1)) / sector_size; // calculate index of first data sector @@ -92,28 +92,28 @@ namespace fs // now that we're here, we can determine the actual FAT type // using the official method: if (this->clusters < 4085) - { - this->fat_type = FAT::T_FAT12; - this->root_cluster = 2; - debug("The image is type FAT12, with %u clusters\n", this->clusters); - } + { + this->fat_type = FAT::T_FAT12; + this->root_cluster = 2; + debug("The image is type FAT12, with %u clusters\n", this->clusters); + } else if (this->clusters < 65525) - { - this->fat_type = FAT::T_FAT16; - this->root_cluster = 2; - debug("The image is type FAT16, with %u clusters\n", this->clusters); - } + { + this->fat_type = FAT::T_FAT16; + this->root_cluster = 2; + debug("The image is type FAT16, with %u clusters\n", this->clusters); + } else - { - this->fat_type = FAT::T_FAT32; - this->root_cluster = *(uint32_t*) &mbr->boot[33]; - this->root_cluster = 2; - debug("The image is type FAT32, with %u clusters\n", this->clusters); - //printf("Root dir entries: %u clusters\n", bpb->root_entries); - //assert(bpb->root_entries == 0); - //this->root_dir_sectors = 0; - //this->data_index = bpb->reserved_sectors + bpb->fa_tables * this->sectors_per_fat; - } + { + this->fat_type = FAT::T_FAT32; + this->root_cluster = *(uint32_t*) &mbr->boot[33]; + this->root_cluster = 2; + debug("The image is type FAT32, with %u clusters\n", this->clusters); + //printf("Root dir entries: %u clusters\n", bpb->root_entries); + //assert(bpb->root_entries == 0); + //this->root_dir_sectors = 0; + //this->data_index = bpb->reserved_sectors + bpb->fa_tables * this->sectors_per_fat; + } debug("Root cluster index: %u (sector %u)\n", this->root_cluster, cl_to_sector(root_cluster)); debug("System ID: %.8s\n", bpb->system_id); } @@ -125,149 +125,149 @@ namespace fs // read Partition block device.read(this->lba_base, - [this, on_mount] (buffer_t data) - { - auto* mbr = (MBR::mbr*) data.get(); - assert(mbr != nullptr); + [this, on_mount] (buffer_t data) + { + auto* mbr = (MBR::mbr*) data.get(); + assert(mbr != nullptr); - // verify image signature - debug("OEM name: \t%s\n", mbr->oem_name); - debug("MBR signature: \t0x%x\n", mbr->magic); - assert(mbr->magic == 0xAA55); + // verify image signature + debug("OEM name: \t%s\n", mbr->oem_name); + debug("MBR signature: \t0x%x\n", mbr->magic); + assert(mbr->magic == 0xAA55); - // initialize FAT16 or FAT32 filesystem - init(mbr); + // initialize FAT16 or FAT32 filesystem + init(mbr); - // determine which FAT version is mounted - std::string inf = "ofs: " + std::to_string(lba_base) + - "size: " + std::to_string(lba_size) + - " (" + std::to_string(this->lba_size * sector_size) + " bytes)\n"; + // determine which FAT version is mounted + std::string inf = "ofs: " + std::to_string(lba_base) + + "size: " + std::to_string(lba_size) + + " (" + std::to_string(this->lba_size * sector_size) + " bytes)\n"; - switch (this->fat_type) - { - case FAT::T_FAT12: - INFO("FS", "Mounting FAT12 filesystem"); - break; - case FAT::T_FAT16: - INFO("FS", "Mounting FAT16 filesystem"); - break; - case FAT::T_FAT32: - INFO("FS", "Mounting FAT32 filesystem"); - break; - } - INFO2("[ofs=%u size=%u (%u bytes)]\n", - this->lba_base, this->lba_size, this->lba_size * 512); + switch (this->fat_type) + { + case FAT::T_FAT12: + INFO("FS", "Mounting FAT12 filesystem"); + break; + case FAT::T_FAT16: + INFO("FS", "Mounting FAT16 filesystem"); + break; + case FAT::T_FAT32: + INFO("FS", "Mounting FAT32 filesystem"); + break; + } + INFO2("[ofs=%u size=%u (%u bytes)]\n", + this->lba_base, this->lba_size, this->lba_size * 512); - // on_mount callback - on_mount(no_error); - }); + // on_mount callback + on_mount(no_error); + }); } bool FAT::int_dirent( - uint32_t sector, - const void* data, - dirvec_t dirents) + uint32_t sector, + const void* data, + dirvec_t dirents) { - auto* root = (cl_dir*) data; - bool found_last = false; + auto* root = (cl_dir*) data; + bool found_last = false; - for (int i = 0; i < 16; i++) + for (int i = 0; i < 16; i++) { if (unlikely(root[i].shortname[0] == 0x0)) - { - //printf("end of dir\n"); - found_last = true; - // end of directory - break; - } + { + //printf("end of dir\n"); + found_last = true; + // end of directory + break; + } else if (unlikely(root[i].shortname[0] == 0xE5)) - { - // unused index - } + { + // unused index + } else - { + { // traverse long names, then final cluster // to read all the relevant info if (likely(root[i].is_longname())) - { - auto* L = (cl_long*) &root[i]; - // the last long index is part of a chain of entries - if (L->is_last()) - { - // buffer for long filename - char final_name[256]; - int final_count = 0; + { + auto* L = (cl_long*) &root[i]; + // the last long index is part of a chain of entries + if (L->is_last()) + { + // buffer for long filename + char final_name[256]; + int final_count = 0; - int total = L->long_index(); - // go to the last entry and work backwards - i += total-1; - L += total-1; + int total = L->long_index(); + // go to the last entry and work backwards + i += total-1; + L += total-1; - for (int idx = total; idx > 0; idx--) - { - uint16_t longname[13]; - memcpy(longname+ 0, L->first, 10); - memcpy(longname+ 5, L->second, 12); - memcpy(longname+11, L->third, 4); + for (int idx = total; idx > 0; idx--) + { + uint16_t longname[13]; + memcpy(longname+ 0, L->first, 10); + memcpy(longname+ 5, L->second, 12); + memcpy(longname+11, L->third, 4); - for (int j = 0; j < 13; j++) - { - // 0xFFFF indicates end of name - if (unlikely(longname[j] == 0xFFFF)) break; - // sometimes, invalid stuff are snuck into filenames - if (unlikely(longname[j] == 0x0)) break; + for (int j = 0; j < 13; j++) + { + // 0xFFFF indicates end of name + if (unlikely(longname[j] == 0xFFFF)) break; + // sometimes, invalid stuff are snuck into filenames + if (unlikely(longname[j] == 0x0)) break; - final_name[final_count] = longname[j] & 0xFF; - final_count++; - } - L--; + final_name[final_count] = longname[j] & 0xFF; + final_count++; + } + L--; - if (unlikely(final_count > 240)) - { - debug("Suspicious long name length, breaking...\n"); - break; - } - } + if (unlikely(final_count > 240)) + { + debug("Suspicious long name length, breaking...\n"); + break; + } + } - final_name[final_count] = 0; - debug("Long name: %s\n", final_name); + final_name[final_count] = 0; + debug("Long name: %s\n", final_name); - i++; // skip over the long version - // to the short version for the stats and cluster - auto* D = &root[i]; - std::string dirname(final_name, final_count); - dirname = trim_right_copy(dirname); + i++; // skip over the long version + // to the short version for the stats and cluster + auto* D = &root[i]; + std::string dirname(final_name, final_count); + dirname = trim_right_copy(dirname); - dirents->emplace_back( - D->type(), - dirname, - D->dir_cluster(root_cluster), - sector, // parent block - D->size(), - D->attrib); - } - } + dirents->emplace_back( + D->type(), + dirname, + D->dir_cluster(root_cluster), + sector, // parent block + D->size(), + D->attrib); + } + } else - { - auto* D = &root[i]; - debug("Short name: %.11s\n", D->shortname); + { + auto* D = &root[i]; + debug("Short name: %.11s\n", D->shortname); - std::string dirname((char*) D->shortname, 11); - dirname = trim_right_copy(dirname); + std::string dirname((char*) D->shortname, 11); + dirname = trim_right_copy(dirname); - dirents->emplace_back( - D->type(), - dirname, - D->dir_cluster(root_cluster), - sector, // parent block - D->size(), - D->attrib); - } - } + dirents->emplace_back( + D->type(), + dirname, + D->dir_cluster(root_cluster), + sector, // parent block + D->size(), + D->attrib); + } + } } // directory list - return found_last; + return found_last; } } diff --git a/src/fs/fat_async.cpp b/src/fs/fat_async.cpp index 965a35de98..ca1cb4b1db 100644 --- a/src/fs/fat_async.cpp +++ b/src/fs/fat_async.cpp @@ -15,43 +15,43 @@ namespace fs { void FAT::int_ls( - uint32_t sector, - dirvec_t dirents, - on_internal_ls_func callback) + uint32_t sector, + dirvec_t dirents, + on_internal_ls_func callback) { // list contents of meme sector by sector typedef std::function next_func_t; auto next = std::make_shared (); *next = - [this, sector, callback, dirents, next] (uint32_t sector) - { - debug("int_ls: sec=%u\n", sector); - device.read(sector, - [this, sector, callback, dirents, next] (buffer_t data) + [this, sector, callback, dirents, next] (uint32_t sector) + { + debug("int_ls: sec=%u\n", sector); + device.read(sector, + [this, sector, callback, dirents, next] (buffer_t data) { if (!data) - { - // could not read sector - callback(true, dirents); - return; - } + { + // could not read sector + callback(true, dirents); + return; + } // parse entries in sector bool done = int_dirent(sector, data.get(), dirents); if (done) - { - // execute callback - callback(no_error, dirents); - } + { + // execute callback + callback(no_error, dirents); + } else - { - // go to next sector - (*next)(sector+1); - } + { + // go to next sector + (*next)(sector+1); + } }); // read root dir - }; + }; // start reading sectors asynchronously (*next)(sector); @@ -65,68 +65,68 @@ namespace fs // asynch stack traversal auto next = std::make_shared (); *next = - [this, path, next, callback] (uint32_t cluster) - { - if (path->empty()) + [this, path, next, callback] (uint32_t cluster) { - // attempt to read directory - uint32_t S = this->cl_to_sector(cluster); + if (path->empty()) + { + // attempt to read directory + uint32_t S = this->cl_to_sector(cluster); - // result allocated on heap - auto dirents = std::make_shared> (); + // result allocated on heap + auto dirents = std::make_shared> (); - int_ls(S, dirents, - [callback] (error_t error, dirvec_t ents) - { - callback(error, ents); - }); - return; - } + int_ls(S, dirents, + [callback] (error_t error, dirvec_t ents) + { + callback(error, ents); + }); + return; + } - // retrieve next name - std::string name = path->front(); - path->pop_front(); + // retrieve next name + std::string name = path->front(); + path->pop_front(); - uint32_t S = this->cl_to_sector(cluster); - debug("Current target: %s on cluster %u (sector %u)\n", name.c_str(), cluster, S); + uint32_t S = this->cl_to_sector(cluster); + debug("Current target: %s on cluster %u (sector %u)\n", name.c_str(), cluster, S); - // result allocated on heap - auto dirents = std::make_shared> (); + // result allocated on heap + auto dirents = std::make_shared> (); - // list directory contents - int_ls(S, dirents, - [name, dirents, next, callback] (error_t error, dirvec_t ents) + // list directory contents + int_ls(S, dirents, + [name, dirents, next, callback] (error_t error, dirvec_t ents) { if (unlikely(error)) - { - debug("Could not find: %s\n", name.c_str()); - callback(true, dirents); - return; - } + { + debug("Could not find: %s\n", name.c_str()); + callback(true, dirents); + return; + } // look for name in directory for (auto& e : *ents) - { - if (unlikely(e.name() == name)) - { - // go to this directory, unless its the last name - debug("Found match for %s", name.c_str()); - // enter the matching directory - debug("\t\t cluster: %llu\n", e.block); - // only follow directories - if (e.type() == DIR) - (*next)(e.block); - else - callback(true, dirents); - return; - } - } // for (ents) + { + if (unlikely(e.name() == name)) + { + // go to this directory, unless its the last name + debug("Found match for %s", name.c_str()); + // enter the matching directory + debug("\t\t cluster: %llu\n", e.block); + // only follow directories + if (e.type() == DIR) + (*next)(e.block); + else + callback(true, dirents); + return; + } + } // for (ents) debug("NO MATCH for %s\n", name.c_str()); callback(true, dirents); }); - }; + }; // start by reading root directory (*next)(0); } @@ -137,10 +137,10 @@ namespace fs auto pstk = std::make_shared (path); traverse(pstk, - [on_ls] (error_t error, dirvec_t dirents) - { - on_ls(error, dirents); - }); + [on_ls] (error_t error, dirvec_t dirents) + { + on_ls(error, dirents); + }); } void FAT::read(const Dirent& ent, uint64_t pos, uint64_t n, on_read_func callback) @@ -156,51 +156,51 @@ namespace fs auto next = std::make_shared (); *next = - [this, sector, buffer, callback, next] (size_t start, size_t n, size_t end) - { - if (unlikely(n == end)) + [this, sector, buffer, callback, next] (size_t start, size_t n, size_t end) { - // report back to HQ - debug("DONE start=%lu, current=%lu, total=%lu\n", start, n, end - start); - // create shared buffer - auto buffer_ptr = buffer_t(buffer, std::default_delete()); - // notify caller - callback(no_error, buffer_ptr, end - start); - return; - } + if (unlikely(n == end)) + { + // report back to HQ + debug("DONE start=%lu, current=%lu, total=%lu\n", start, n, end - start); + // create shared buffer + auto buffer_ptr = buffer_t(buffer, std::default_delete()); + // notify caller + callback(no_error, buffer_ptr, end - start); + return; + } - // read the current sector based on position @n - uint32_t current_sector = sector + n / this->sector_size; + // read the current sector based on position @n + uint32_t current_sector = sector + n / this->sector_size; - device.read(current_sector, - [this, start, n, end, buffer, &callback, sector, next] (buffer_t data) + device.read(current_sector, + [this, start, n, end, buffer, &callback, sector, next] (buffer_t data) { if (!data) - { - // general I/O error occurred - debug("Failed to read sector %u for read()", sector); - // cleanup - delete[] buffer; - callback(true, buffer_t(), 0); - return; - } + { + // general I/O error occurred + debug("Failed to read sector %u for read()", sector); + // cleanup + delete[] buffer; + callback(true, buffer_t(), 0); + return; + } uint32_t length = n & (sector_size-1); if (n == start && n > 0) - { - length = sector_size - length; - } + { + length = sector_size - length; + } else - { - length = (n + sector_size) < end ? sector_size : (end - n); - } + { + length = (n + sector_size) < end ? sector_size : (end - n); + } // copy over data memcpy(buffer + n, data.get(), length); // continue reading next sector (*next)(start, n + length, end); }); - }; + }; // start! (*next)(pos, pos, pos + n); @@ -210,52 +210,52 @@ namespace fs { auto path = std::make_shared (strpath); if (unlikely(path->empty())) - { - // there is no possible file to read where path is empty - callback(true, nullptr, 0); - return; - } + { + // there is no possible file to read where path is empty + callback(true, nullptr, 0); + return; + } debug("readFile: %s\n", path->back().c_str()); std::string filename = path->back(); path->pop_back(); traverse(path, - [this, filename, &callback] (error_t error, dirvec_t dirents) - { - if (unlikely(error)) - { - // no path, no file! - callback(error, buffer_t(), 0); - return; - } + [this, filename, &callback] (error_t error, dirvec_t dirents) + { + if (unlikely(error)) + { + // no path, no file! + callback(error, buffer_t(), 0); + return; + } - // find the matching filename in directory - for (auto& ent : *dirents) - { - if (unlikely(ent.name() == filename)) - { - // read this file - read(ent, 0, ent.size, callback); - return; - } - } + // find the matching filename in directory + for (auto& ent : *dirents) + { + if (unlikely(ent.name() == filename)) + { + // read this file + read(ent, 0, ent.size, callback); + return; + } + } - // file not found - callback(true, buffer_t(), 0); - }); + // file not found + callback(true, buffer_t(), 0); + }); } // readFile() void FAT::stat(const std::string& strpath, on_stat_func func) { auto path = std::make_shared (strpath); if (unlikely(path->empty())) - { - // root doesn't have any stat anyways - // Note: could use ATTR_VOLUME_ID in FAT - func(true, Dirent(INVALID_ENTITY, strpath)); - return; - } + { + // root doesn't have any stat anyways + // Note: could use ATTR_VOLUME_ID in FAT + func(true, Dirent(INVALID_ENTITY, strpath)); + return; + } debug("stat: %s\n", path->back().c_str()); // extract file we are looking for @@ -265,28 +265,28 @@ namespace fs auto callback = std::make_shared (func); traverse(path, - [this, filename, callback] (error_t error, dirvec_t dirents) - { - if (unlikely(error)) - { - // no path, no file! - (*callback)(error, Dirent(INVALID_ENTITY, filename)); - return; - } + [this, filename, callback] (error_t error, dirvec_t dirents) + { + if (unlikely(error)) + { + // no path, no file! + (*callback)(error, Dirent(INVALID_ENTITY, filename)); + return; + } - // find the matching filename in directory - for (auto& e : *dirents) - { - if (unlikely(e.name() == filename)) - { - // read this file - (*callback)(no_error, e); - return; - } - } + // find the matching filename in directory + for (auto& e : *dirents) + { + if (unlikely(e.name() == filename)) + { + // read this file + (*callback)(no_error, e); + return; + } + } - // not found - (*callback)(true, Dirent(INVALID_ENTITY, filename)); - }); + // not found + (*callback)(true, Dirent(INVALID_ENTITY, filename)); + }); } } diff --git a/src/fs/fat_sync.cpp b/src/fs/fat_sync.cpp index 6661104929..e1b3af2d58 100644 --- a/src/fs/fat_sync.cpp +++ b/src/fs/fat_sync.cpp @@ -35,11 +35,11 @@ namespace fs // if what we want to read is larger than the rest, exit early if (rest > n) - { - memcpy(result, data.get() + internal_ofs, n); + { + memcpy(result, data.get() + internal_ofs, n); - return Buffer(no_error, buffer_t(result), n); - } + return Buffer(no_error, buffer_t(result), n); + } // otherwise, read to the sector border uint8_t* ptr = result; memcpy(ptr, data.get() + internal_ofs, rest); @@ -49,21 +49,21 @@ namespace fs // copy entire sectors while (n > device.block_size()) - { - data = device.read_sync(sector); + { + data = device.read_sync(sector); - memcpy(ptr, data.get(), device.block_size()); - ptr += device.block_size(); - n -= device.block_size(); - sector += 1; - } + memcpy(ptr, data.get(), device.block_size()); + ptr += device.block_size(); + n -= device.block_size(); + sector += 1; + } // copy remainder if (likely(n > 0)) - { - data = device.read_sync(sector); - memcpy(ptr, data.get(), n); - } + { + data = device.read_sync(sector); + memcpy(ptr, data.get(), n); + } return Buffer(no_error, buffer_t(result), total); } @@ -72,10 +72,10 @@ namespace fs { Path path(strpath); if (unlikely(path.empty())) - { - // there is no possible file to read where path is empty - return Buffer(true, nullptr, 0); - } + { + // there is no possible file to read where path is empty + return Buffer(true, nullptr, 0); + } debug("readFile: %s\n", path.back().c_str()); std::string filename = path.back(); @@ -89,13 +89,13 @@ namespace fs // find the matching filename in directory for (auto& e : *dirents) - { - if (unlikely(e.name() == filename)) { - // read this file - return read(e, 0, e.size); + if (unlikely(e.name() == filename)) + { + // read this file + return read(e, 0, e.size); + } } - } // entry not found return Buffer(true, buffer_t(), 0); } // readFile() @@ -104,15 +104,15 @@ namespace fs { bool done = false; while (!done) - { - // read sector sync - buffer_t data = device.read_sync(sector); - if (!data) return true; - // parse directory into @ents - done = int_dirent(sector, data.get(), ents); - // go to next sector until done - sector++; - } + { + // read sector sync + buffer_t data = device.read_sync(sector); + if (!data) return true; + // parse directory into @ents + done = int_dirent(sector, data.get(), ents); + // go to next sector until done + sector++; + } return no_error; } @@ -125,46 +125,46 @@ namespace fs Dirent found(INVALID_ENTITY); while (!path.empty()) - { - uint32_t S = this->cl_to_sector(cluster); - dirents->clear(); // mui importante - // sync read entire directory - auto err = int_ls(S, dirents); - if (err) return err; - // the name we are looking for - std::string name = path.front(); - path.pop_front(); - - // check for matches in dirents - for (auto& e : *dirents) - if (unlikely(e.name() == name)) { - // go to this directory, unless its the last name - debug("traverse_sync: Found match for %s", name.c_str()); - // enter the matching directory - debug("\t\t cluster: %lu\n", e.block); - // only follow if the name is a directory - if (e.type() == DIR) - { - found = e; - break; - } - else - { - // not dir = error, for now - return true; - } - } // for (ents) + uint32_t S = this->cl_to_sector(cluster); + dirents->clear(); // mui importante + // sync read entire directory + auto err = int_ls(S, dirents); + if (err) return err; + // the name we are looking for + std::string name = path.front(); + path.pop_front(); - // validate result - if (found.type() == INVALID_ENTITY) - { - debug("traverse_sync: NO MATCH for %s\n", name.c_str()); - return true; + // check for matches in dirents + for (auto& e : *dirents) + if (unlikely(e.name() == name)) + { + // go to this directory, unless its the last name + debug("traverse_sync: Found match for %s", name.c_str()); + // enter the matching directory + debug("\t\t cluster: %lu\n", e.block); + // only follow if the name is a directory + if (e.type() == DIR) + { + found = e; + break; + } + else + { + // not dir = error, for now + return true; + } + } // for (ents) + + // validate result + if (found.type() == INVALID_ENTITY) + { + debug("traverse_sync: NO MATCH for %s\n", name.c_str()); + return true; + } + // set next cluster + cluster = found.block; } - // set next cluster - cluster = found.block; - } uint32_t S = this->cl_to_sector(cluster); // read result directory entries into ents @@ -180,10 +180,10 @@ namespace fs { Path path(strpath); if (unlikely(path.empty())) - { - // root doesn't have any stat anyways (except ATTR_VOLUME_ID in FAT) - return Dirent(INVALID_ENTITY); - } + { + // root doesn't have any stat anyways (except ATTR_VOLUME_ID in FAT) + return Dirent(INVALID_ENTITY); + } debug("stat_sync: %s\n", path.back().c_str()); // extract file we are looking for @@ -198,13 +198,13 @@ namespace fs // find the matching filename in directory for (auto& e : *dirents) - { - if (unlikely(e.name() == filename)) { - // return this directory entry - return e; + if (unlikely(e.name() == filename)) + { + // return this directory entry + return e; + } } - } // entry not found return Dirent(INVALID_ENTITY); } diff --git a/src/fs/mbr.cpp b/src/fs/mbr.cpp index 38af37731d..0e1dabc188 100644 --- a/src/fs/mbr.cpp +++ b/src/fs/mbr.cpp @@ -5,74 +5,74 @@ namespace fs std::string MBR::id_to_name(uint8_t id) { switch (id) - { - case 0x00: - return "Empty"; - case 0x01: - return "DOS 12-bit FAT"; - case 0x02: - return "XENIX root"; - case 0x03: - return "XENIX /usr"; - case 0x04: - return "DOS 3.0+ 16-bit FAT"; - case 0x05: - return "DOS 3.3+ Extended Partition"; - case 0x06: - return "DOS 3.31+ 16-bit FAT (32M+)"; - case 0x07: - return "NTFS or exFAT"; - case 0x08: - return "Commodore DOS logical FAT"; - case 0x0b: - return "WIN95 OSR2 FAT32"; - case 0x0c: - return "WIN95 OSR2 FAT32, LBA-mapped"; - case 0x0d: - return "SILICON SAFE"; - case 0x0e: - return "WIN95: DOS 16-bit FAT, LBA-mapped"; - case 0x0f: - return "WIN95: Extended partition, LBA-mapped"; - case 0x11: - return "Hidden DOS 12-bit FAT"; - case 0x12: - return "Configuration utility partition (Compaq)"; - case 0x14: - return "Hidden DOS 16-bit FAT <32M"; - case 0x16: - return "Hidden DOS 16-bit FAT >= 32M"; - case 0x27: - return "Windows RE hidden partition"; - case 0x3c: - return "PartitionMagic recovery partition"; - case 0x82: - return "Linux swap"; - case 0x83: - return "Linux native partition"; - case 0x84: - return "Hibernation partition"; - case 0x85: - return "Linux extended partition"; - case 0x86: - return "FAT16 fault tolerant volume set"; - case 0x87: - return "NTFS fault tolerant volume set"; - case 0x8e: - return "Linux Logical Volume Manager partition"; - case 0x9f: - return "BSDI (BSD/OS)"; - case 0xa6: - return "OpenBSD"; - case 0xa8: - return "Apple MacOS X (BSD-like filesystem)"; - case 0xa9: - return "NetBSD"; - case 0xaf: - return "MacOS X HFS"; - default: - return "Invalid identifier: " + std::to_string(id); - } + { + case 0x00: + return "Empty"; + case 0x01: + return "DOS 12-bit FAT"; + case 0x02: + return "XENIX root"; + case 0x03: + return "XENIX /usr"; + case 0x04: + return "DOS 3.0+ 16-bit FAT"; + case 0x05: + return "DOS 3.3+ Extended Partition"; + case 0x06: + return "DOS 3.31+ 16-bit FAT (32M+)"; + case 0x07: + return "NTFS or exFAT"; + case 0x08: + return "Commodore DOS logical FAT"; + case 0x0b: + return "WIN95 OSR2 FAT32"; + case 0x0c: + return "WIN95 OSR2 FAT32, LBA-mapped"; + case 0x0d: + return "SILICON SAFE"; + case 0x0e: + return "WIN95: DOS 16-bit FAT, LBA-mapped"; + case 0x0f: + return "WIN95: Extended partition, LBA-mapped"; + case 0x11: + return "Hidden DOS 12-bit FAT"; + case 0x12: + return "Configuration utility partition (Compaq)"; + case 0x14: + return "Hidden DOS 16-bit FAT <32M"; + case 0x16: + return "Hidden DOS 16-bit FAT >= 32M"; + case 0x27: + return "Windows RE hidden partition"; + case 0x3c: + return "PartitionMagic recovery partition"; + case 0x82: + return "Linux swap"; + case 0x83: + return "Linux native partition"; + case 0x84: + return "Hibernation partition"; + case 0x85: + return "Linux extended partition"; + case 0x86: + return "FAT16 fault tolerant volume set"; + case 0x87: + return "NTFS fault tolerant volume set"; + case 0x8e: + return "Linux Logical Volume Manager partition"; + case 0x9f: + return "BSDI (BSD/OS)"; + case 0xa6: + return "OpenBSD"; + case 0xa8: + return "Apple MacOS X (BSD-like filesystem)"; + case 0xa9: + return "NetBSD"; + case 0xaf: + return "MacOS X HFS"; + default: + return "Invalid identifier: " + std::to_string(id); + } } diff --git a/src/fs/memdisk.cpp b/src/fs/memdisk.cpp index 6ae3c5e588..83fed8ddab 100644 --- a/src/fs/memdisk.cpp +++ b/src/fs/memdisk.cpp @@ -31,55 +31,55 @@ extern "C" { namespace fs { -MemDisk::MemDisk() noexcept + MemDisk::MemDisk() noexcept : image_start { &_DISK_START_ }, image_end { &_DISK_END_ } {} -void MemDisk::read(block_t blk, on_read_func callback) { - auto* sector_loc = ((char*) image_start) + blk * block_size(); - // Disallow reading memory past disk image - if (unlikely(sector_loc >= image_end)) - { - callback(buffer_t()); return; - } + void MemDisk::read(block_t blk, on_read_func callback) { + auto* sector_loc = ((char*) image_start) + blk * block_size(); + // Disallow reading memory past disk image + if (unlikely(sector_loc >= image_end)) + { + callback(buffer_t()); return; + } - auto* buffer = new uint8_t[block_size()]; - assert( memcpy(buffer, sector_loc, block_size()) == buffer ); + auto* buffer = new uint8_t[block_size()]; + assert( memcpy(buffer, sector_loc, block_size()) == buffer ); - callback( buffer_t(buffer, std::default_delete()) ); -} - -void MemDisk::read(block_t start, block_t count, on_read_func callback) { - auto* start_loc = ((char*) image_start) + start * block_size(); - auto* end_loc = start_loc + count * block_size(); - // Disallow reading memory past disk image - if (unlikely(end_loc >= image_end)) - { - callback(buffer_t()); return; + callback( buffer_t(buffer, std::default_delete()) ); } + + void MemDisk::read(block_t start, block_t count, on_read_func callback) { + auto* start_loc = ((char*) image_start) + start * block_size(); + auto* end_loc = start_loc + count * block_size(); + // Disallow reading memory past disk image + if (unlikely(end_loc >= image_end)) + { + callback(buffer_t()); return; + } - auto* buffer = new uint8_t[count * block_size()]; - assert( memcpy(buffer, start_loc, count * block_size()) == buffer ); + auto* buffer = new uint8_t[count * block_size()]; + assert( memcpy(buffer, start_loc, count * block_size()) == buffer ); - callback( buffer_t(buffer, std::default_delete()) ); -} + callback( buffer_t(buffer, std::default_delete()) ); + } -MemDisk::buffer_t MemDisk::read_sync(block_t blk) -{ - auto* loc = ((char*) image_start) + blk * block_size(); - // Disallow reading memory past disk image - if (unlikely(loc >= image_end)) - return buffer_t(); + MemDisk::buffer_t MemDisk::read_sync(block_t blk) + { + auto* loc = ((char*) image_start) + blk * block_size(); + // Disallow reading memory past disk image + if (unlikely(loc >= image_end)) + return buffer_t(); - auto* buffer = new uint8_t[block_size()]; - assert( memcpy(buffer, loc, block_size()) == buffer ); + auto* buffer = new uint8_t[block_size()]; + assert( memcpy(buffer, loc, block_size()) == buffer ); - return buffer_t(buffer, std::default_delete()); -} + return buffer_t(buffer, std::default_delete()); + } -MemDisk::block_t MemDisk::size() const noexcept { - return ((char*) image_end - (char*) image_start) / SECTOR_SIZE; -} + MemDisk::block_t MemDisk::size() const noexcept { + return ((char*) image_end - (char*) image_start) / SECTOR_SIZE; + } } //< namespace fs diff --git a/src/fs/path.cpp b/src/fs/path.cpp index e124f137ed..45fe6a7612 100644 --- a/src/fs/path.cpp +++ b/src/fs/path.cpp @@ -22,102 +22,102 @@ namespace fs { - static const char PATH_SEPARATOR = '/'; + static const char PATH_SEPARATOR = '/'; - Path::Path() - : Path("/") - { - // uses current directory - } - Path::Path(const std::string& path) - { - // parse full path - this->state = parse(path); + Path::Path() + : Path("/") + { + // uses current directory + } + Path::Path(const std::string& path) + { + // parse full path + this->state = parse(path); - } // Path::Path(std::string) + } // Path::Path(std::string) - std::string Path::to_string() const - { - // build path - //std::stringstream ss; + std::string Path::to_string() const + { + // build path + //std::stringstream ss; std::string ss; - for (const auto& p : this->stk) - { - ss += PATH_SEPARATOR + p; - } - // append path/ to end - ss += PATH_SEPARATOR; - return ss; - } + for (const auto& p : this->stk) + { + ss += PATH_SEPARATOR + p; + } + // append path/ to end + ss += PATH_SEPARATOR; + return ss; + } - int Path::parse(const std::string& path) - { - if (path.empty()) - { - // do nothing? - return 0; - } + int Path::parse(const std::string& path) + { + if (path.empty()) + { + // do nothing? + return 0; + } - std::string buffer(path.size(), 0); - char lastChar = 0; - int bufi = 0; + std::string buffer(path.size(), 0); + char lastChar = 0; + int bufi = 0; - for (size_t i = 0; i < path.size(); i++) - { - if (path[i] == PATH_SEPARATOR) - { - if (lastChar == PATH_SEPARATOR) - { // invalid path containing // (more than one forw-slash) - return -EINVAL; - } - if (bufi) - { - name_added(std::string(buffer, 0, bufi)); - bufi = 0; - } - else if (i == 0) - { - // if the first character is / separator, - // the path is relative to root, so clear stack - stk.clear(); - } - } - else - { - buffer[bufi] = path[i]; - bufi++; - } - lastChar = path[i]; - } // parse path - if (bufi) - { - name_added(std::string(buffer, 0, bufi)); - } + for (size_t i = 0; i < path.size(); i++) + { + if (path[i] == PATH_SEPARATOR) + { + if (lastChar == PATH_SEPARATOR) + { // invalid path containing // (more than one forw-slash) + return -EINVAL; + } + if (bufi) + { + name_added(std::string(buffer, 0, bufi)); + bufi = 0; + } + else if (i == 0) + { + // if the first character is / separator, + // the path is relative to root, so clear stack + stk.clear(); + } + } + else + { + buffer[bufi] = path[i]; + bufi++; + } + lastChar = path[i]; + } // parse path + if (bufi) + { + name_added(std::string(buffer, 0, bufi)); + } return 0; - } + } - void Path::name_added(const std::string& name) - { - //std::cout << "Path: " << toString() << " --> " << name << std::endl; + void Path::name_added(const std::string& name) + { + //std::cout << "Path: " << toString() << " --> " << name << std::endl; - if (name == ".") - { - // same directory - } - /*else if (name == "..") - { - // if the stack is empty we are at root - if (stk.empty()) - { - // trying to go above root is an error (?) - return; - } + if (name == ".") + { + // same directory + } + /*else if (name == "..") + { + // if the stack is empty we are at root + if (stk.empty()) + { + // trying to go above root is an error (?) + return; + } stk.pop_back(); - }*/ - else - { - // otherwise treat as directory - stk.push_back(name); - } - } + }*/ + else + { + // otherwise treat as directory + stk.push_back(name); + } + } } diff --git a/src/hw/cpu_freq_sampling.cpp b/src/hw/cpu_freq_sampling.cpp index c7953a683b..b6899ccf9b 100644 --- a/src/hw/cpu_freq_sampling.cpp +++ b/src/hw/cpu_freq_sampling.cpp @@ -25,83 +25,83 @@ namespace hw { -/** @note C-style code here, since we're dealing with interrupt handling. - The hardware expects a pure function pointer, and asm can't (easily) - call class member functions. */ + /** @note C-style code here, since we're dealing with interrupt handling. + The hardware expects a pure function pointer, and asm can't (easily) + call class member functions. */ -// This is how you provide storage for a static constexpr variable. -constexpr MHz PIT::frequency_; + // This is how you provide storage for a static constexpr variable. + constexpr MHz PIT::frequency_; -extern "C" double _CPUFreq_ = 0; -extern "C" constexpr uint16_t _cpu_sampling_freq_divider_ = KHz(PIT::frequency()).count() * 10; // Run 1 KHz Lowest: 0xffff + extern "C" double _CPUFreq_ = 0; + extern "C" constexpr uint16_t _cpu_sampling_freq_divider_ = KHz(PIT::frequency()).count() * 10; // Run 1 KHz Lowest: 0xffff -static constexpr int do_samples_ = 20; + static constexpr int do_samples_ = 20; -std::vector _cpu_timestamps; -std::vector _cpu_freq_samples; + std::vector _cpu_timestamps; + std::vector _cpu_freq_samples; -constexpr MHz test_frequency(){ - return MHz(PIT::frequency().count() / _cpu_sampling_freq_divider_); -} + constexpr MHz test_frequency(){ + return MHz(PIT::frequency().count() / _cpu_sampling_freq_divider_); + } -MHz calculate_cpu_frequency(){ + MHz calculate_cpu_frequency(){ - // We expect the cpu_sampling_irq_handler to push in samples; - while (_cpu_timestamps.size() < do_samples_) - OS::halt(); + // We expect the cpu_sampling_irq_handler to push in samples; + while (_cpu_timestamps.size() < do_samples_) + OS::halt(); - debug("_cpu_sampling_freq_divider_ : %i \n",_cpu_sampling_freq_divider_); + debug("_cpu_sampling_freq_divider_ : %i \n",_cpu_sampling_freq_divider_); - #ifdef DEBUG - for (auto t : _cpu_timestamps) debug("%lu \n",(uint32_t)t); - #endif +#ifdef DEBUG + for (auto t : _cpu_timestamps) debug("%lu \n",(uint32_t)t); +#endif - // Subtract the time it takes to measure time :-) - auto t1 = OS::cycles_since_boot(); - OS::cycles_since_boot(); - auto t3 = OS::cycles_since_boot(); - auto overhead = (t3 - t1) * 2; + // Subtract the time it takes to measure time :-) + auto t1 = OS::cycles_since_boot(); + OS::cycles_since_boot(); + auto t3 = OS::cycles_since_boot(); + auto overhead = (t3 - t1) * 2; - debug ("Overhead: %lu \n", (uint32_t)overhead); + debug ("Overhead: %lu \n", (uint32_t)overhead); - for (size_t i = 1; i < _cpu_timestamps.size(); i++){ - // Compute delta in cycles - auto cycles = _cpu_timestamps[i] - _cpu_timestamps[i-1] + overhead; - // Cycles pr. second == Hertz - auto freq = cycles / (1 / test_frequency().count()); - _cpu_freq_samples.push_back(freq); - debug("%lu - %lu = Delta: %lu Current PIT-Freq: %f Hz CPU Freq: %f MHz \n", - (uint32_t)_cpu_timestamps[i], (uint32_t)_cpu_timestamps[i-1], - (uint32_t)cycles, Hz(test_frequency()), freq); - } + for (size_t i = 1; i < _cpu_timestamps.size(); i++){ + // Compute delta in cycles + auto cycles = _cpu_timestamps[i] - _cpu_timestamps[i-1] + overhead; + // Cycles pr. second == Hertz + auto freq = cycles / (1 / test_frequency().count()); + _cpu_freq_samples.push_back(freq); + debug("%lu - %lu = Delta: %lu Current PIT-Freq: %f Hz CPU Freq: %f MHz \n", + (uint32_t)_cpu_timestamps[i], (uint32_t)_cpu_timestamps[i-1], + (uint32_t)cycles, Hz(test_frequency()), freq); + } #ifdef DEBUG - double sum = 0; - for (auto freq : _cpu_freq_samples) - sum += freq; - double mean = sum / _cpu_freq_samples.size(); + double sum = 0; + for (auto freq : _cpu_freq_samples) + sum += freq; + double mean = sum / _cpu_freq_samples.size(); #endif - std::sort(_cpu_freq_samples.begin(), _cpu_freq_samples.end()); - double median = _cpu_freq_samples[_cpu_freq_samples.size() / 2]; + std::sort(_cpu_freq_samples.begin(), _cpu_freq_samples.end()); + double median = _cpu_freq_samples[_cpu_freq_samples.size() / 2]; - debug(" MEAN: %f MEDIAN: %f \n",mean, median); - _CPUFreq_ = median; + debug(" MEAN: %f MEDIAN: %f \n",mean, median); + _CPUFreq_ = median; - return MHz(median); + return MHz(median); -} + } -void cpu_sampling_irq_handler(){ + void cpu_sampling_irq_handler(){ - auto t2 = OS::cycles_since_boot(); + auto t2 = OS::cycles_since_boot(); - if (_cpu_timestamps.size() < do_samples_) - _cpu_timestamps.push_back(t2); + if (_cpu_timestamps.size() < do_samples_) + _cpu_timestamps.push_back(t2); - IRQ_manager::eoi(0); - return; -} + IRQ_manager::eoi(0); + return; + } } //< namespace hw diff --git a/src/hw/ide.cpp b/src/hw/ide.cpp index 33dea422dc..1d9c49e50d 100644 --- a/src/hw/ide.cpp +++ b/src/hw/ide.cpp @@ -53,11 +53,11 @@ namespace hw { -IDE::IDE(hw::PCI_Device& pcidev, selector_t sel) : - _pcidev {pcidev}, - _drive {(uint8_t)sel}, - _iobase {0U}, - _nb_blk {0U} + IDE::IDE(hw::PCI_Device& pcidev, selector_t sel) : + _pcidev {pcidev}, + _drive {(uint8_t)sel}, + _iobase {0U}, + _nb_blk {0U} { INFO("IDE","VENDOR_ID : 0x%x, PRODUCT_ID : 0x%x", _pcidev.vendor_id(), _pcidev.product_id()); INFO("IDE","Attaching to PCI addr 0x%x",_pcidev.pci_addr()); @@ -106,171 +106,171 @@ IDE::IDE(hw::PCI_Device& pcidev, selector_t sel) : INFO("IDE", "Initialization complete"); } -struct ide_irq { - ide_irq(uint8_t* buff, IDE::on_read_func call) - : buffer(buff) - , callback(call) - {} - - uint8_t* buffer; // Reading buffer - IDE::on_read_func callback; // IRQ callback -}; - -static int _nb_irqs = 0; // Number of IRQs that we expect -static IDE::on_read_func _current_callback = nullptr; // Callback for the current irq -static std::list _ide_irqs; // IRQ queue - -void IDE::read(block_t blk, on_read_func callback) { - if (blk >= _nb_blk) { - // avoid reading past the disk boundaries - callback(buffer_t()); - return; - } - - set_irq_mode(true); - set_drive(0xE0 | (_drive << 4) | ((blk >> 24) & 0x0F)); - set_nbsectors(1); - set_blocknum(blk); - set_command(IDE_CMD_READ); + struct ide_irq { + ide_irq(uint8_t* buff, IDE::on_read_func call) + : buffer(buff) + , callback(call) + {} + + uint8_t* buffer; // Reading buffer + IDE::on_read_func callback; // IRQ callback + }; + + static int _nb_irqs = 0; // Number of IRQs that we expect + static IDE::on_read_func _current_callback = nullptr; // Callback for the current irq + static std::list _ide_irqs; // IRQ queue + + void IDE::read(block_t blk, on_read_func callback) { + if (blk >= _nb_blk) { + // avoid reading past the disk boundaries + callback(buffer_t()); + return; + } - _current_callback = callback; - _nb_irqs = 1; -} + set_irq_mode(true); + set_drive(0xE0 | (_drive << 4) | ((blk >> 24) & 0x0F)); + set_nbsectors(1); + set_blocknum(blk); + set_command(IDE_CMD_READ); -void IDE::read(block_t blk, block_t count, on_read_func callback) -{ - if (blk + count >= _nb_blk) { - // avoid reading past the disk boundaries - callback(buffer_t()); - return; + _current_callback = callback; + _nb_irqs = 1; } - - set_irq_mode(true); - set_drive(0xE0 | (_drive << 4) | ((blk >> 24) & 0x0F)); - set_nbsectors(count); - set_blocknum(blk); - set_command(IDE_CMD_READ); - - _current_callback = callback; - _nb_irqs = count; -} -IDE::buffer_t IDE::read_sync(block_t blk) -{ - if (blk >= _nb_blk) { - // avoid reading past the disk boundaries - return buffer_t(); + void IDE::read(block_t blk, block_t count, on_read_func callback) + { + if (blk + count >= _nb_blk) { + // avoid reading past the disk boundaries + callback(buffer_t()); + return; + } + + set_irq_mode(true); + set_drive(0xE0 | (_drive << 4) | ((blk >> 24) & 0x0F)); + set_nbsectors(count); + set_blocknum(blk); + set_command(IDE_CMD_READ); + + _current_callback = callback; + _nb_irqs = count; } - set_irq_mode(false); - set_drive(0xE0 | (_drive << 4) | ((blk >> 24) & 0x0F)); - set_nbsectors(1); - set_blocknum(blk); - set_command(IDE_CMD_READ); + IDE::buffer_t IDE::read_sync(block_t blk) + { + if (blk >= _nb_blk) { + // avoid reading past the disk boundaries + return buffer_t(); + } - auto* buffer = new uint8_t[block_size()]; + set_irq_mode(false); + set_drive(0xE0 | (_drive << 4) | ((blk >> 24) & 0x0F)); + set_nbsectors(1); + set_blocknum(blk); + set_command(IDE_CMD_READ); - wait_status_flags(IDE_DRDY, false); + auto* buffer = new uint8_t[block_size()]; + + wait_status_flags(IDE_DRDY, false); - uint16_t* wptr = (uint16_t*) buffer; - uint16_t* wend = (uint16_t*)&buffer[block_size()]; - while (wptr < wend) - *(wptr++) = inw(IDE_DATA); + uint16_t* wptr = (uint16_t*) buffer; + uint16_t* wend = (uint16_t*)&buffer[block_size()]; + while (wptr < wend) + *(wptr++) = inw(IDE_DATA); - // return a shared_ptr wrapper for the buffer - return buffer_t(buffer, std::default_delete()); -} + // return a shared_ptr wrapper for the buffer + return buffer_t(buffer, std::default_delete()); + } -void IDE::wait_status_busy() noexcept { - uint8_t ret; - while (((ret = inb(IDE_STATUS)) & IDE_BUSY) == IDE_BUSY); -} + void IDE::wait_status_busy() noexcept { + uint8_t ret; + while (((ret = inb(IDE_STATUS)) & IDE_BUSY) == IDE_BUSY); + } -void IDE::wait_status_flags(const int flags, const bool set) noexcept { - wait_status_busy(); + void IDE::wait_status_flags(const int flags, const bool set) noexcept { + wait_status_busy(); - auto ret = inb(IDE_STATUS); + auto ret = inb(IDE_STATUS); - for (int i {IDE_TIMEOUT}; i; --i) { - if (set) { - if ((ret & flags) == flags) - break; - } else { - if ((ret & flags) not_eq flags) - break; - } + for (int i {IDE_TIMEOUT}; i; --i) { + if (set) { + if ((ret & flags) == flags) + break; + } else { + if ((ret & flags) not_eq flags) + break; + } - ret = inb(IDE_STATUS); + ret = inb(IDE_STATUS); + } } -} - -void IDE::set_drive(const uint8_t drive) const noexcept { - wait_status_flags(IDE_DRQ, true); - outb(IDE_DRV, drive); -} -void IDE::set_nbsectors(const uint8_t cnt) const noexcept { - wait_status_flags(IDE_DRQ, true); - outb(IDE_SECCNT, cnt); -} + void IDE::set_drive(const uint8_t drive) const noexcept { + wait_status_flags(IDE_DRQ, true); + outb(IDE_DRV, drive); + } -void IDE::set_blocknum(block_t blk) const noexcept { - wait_status_flags(IDE_DRQ, true); - outb(IDE_BLKLO, blk & 0xFF); + void IDE::set_nbsectors(const uint8_t cnt) const noexcept { + wait_status_flags(IDE_DRQ, true); + outb(IDE_SECCNT, cnt); + } - wait_status_flags(IDE_DRQ, true); - outb(IDE_BLKMID, (blk & 0xFF00) >> 8); + void IDE::set_blocknum(block_t blk) const noexcept { + wait_status_flags(IDE_DRQ, true); + outb(IDE_BLKLO, blk & 0xFF); - wait_status_flags(IDE_DRQ, true); - outb(IDE_BLKHI, (blk & 0xFF0000) >> 16); -} + wait_status_flags(IDE_DRQ, true); + outb(IDE_BLKMID, (blk & 0xFF00) >> 8); -void IDE::set_command(const uint16_t command) const noexcept { - wait_status_flags(IDE_DRDY, false); - outb(IDE_CMD, command); -} + wait_status_flags(IDE_DRQ, true); + outb(IDE_BLKHI, (blk & 0xFF0000) >> 16); + } -void IDE::set_irq_mode(const bool on) noexcept { - wait_status_flags(IDE_DRDY, false); - outb(IDE_CTRL_IRQ, on ? 0 : 1); -} + void IDE::set_command(const uint16_t command) const noexcept { + wait_status_flags(IDE_DRDY, false); + outb(IDE_CMD, command); + } -extern "C" void ide_irq_handler() { - if (!_nb_irqs || _current_callback == nullptr) { - IDE::set_irq_mode(false); - IRQ_manager::eoi(IDE_IRQN); - return; + void IDE::set_irq_mode(const bool on) noexcept { + wait_status_flags(IDE_DRDY, false); + outb(IDE_CTRL_IRQ, on ? 0 : 1); } - uint8_t* buffer = new uint8_t[IDE_BLKSZ]; + extern "C" void ide_irq_handler() { + if (!_nb_irqs || _current_callback == nullptr) { + IDE::set_irq_mode(false); + IRQ_manager::eoi(IDE_IRQN); + return; + } - IDE::wait_status_flags(IDE_DRDY, false); + uint8_t* buffer = new uint8_t[IDE_BLKSZ]; - uint16_t* wptr = (uint16_t*) buffer; + IDE::wait_status_flags(IDE_DRDY, false); - for (IDE::block_t i = 0; i < IDE_BLKSZ / sizeof (uint16_t); ++i) - wptr[i] = inw(IDE_DATA); + uint16_t* wptr = (uint16_t*) buffer; - _ide_irqs.push_back(ide_irq(buffer, _current_callback)); - _nb_irqs--; + for (IDE::block_t i = 0; i < IDE_BLKSZ / sizeof (uint16_t); ++i) + wptr[i] = inw(IDE_DATA); - IRQ_manager::register_interrupt(IDE_IRQN); - IRQ_manager::eoi(IDE_IRQN); -} + _ide_irqs.push_back(ide_irq(buffer, _current_callback)); + _nb_irqs--; -extern "C" void ide_irq_entry(); + IRQ_manager::register_interrupt(IDE_IRQN); + IRQ_manager::eoi(IDE_IRQN); + } -void IDE::callback_wrapper() -{ - IDE::on_read_func callback = _ide_irqs.front().callback; - callback(IDE::buffer_t(_ide_irqs.front().buffer, std::default_delete())); - _ide_irqs.pop_front(); -} + extern "C" void ide_irq_entry(); -void IDE::enable_irq_handler() { - auto del(delegate::from(this)); - IRQ_manager::subscribe(IDE_IRQN, del); - IRQ_manager::set_handler(IDE_IRQN + 32, ide_irq_entry); -} + void IDE::callback_wrapper() + { + IDE::on_read_func callback = _ide_irqs.front().callback; + callback(IDE::buffer_t(_ide_irqs.front().buffer, std::default_delete())); + _ide_irqs.pop_front(); + } + + void IDE::enable_irq_handler() { + auto del(delegate::from(this)); + IRQ_manager::subscribe(IDE_IRQN, del); + IRQ_manager::set_handler(IDE_IRQN + 32, ide_irq_entry); + } } //< namespace hw diff --git a/src/hw/nic.cpp b/src/hw/nic.cpp index e6c40ccf1a..74d9df8dbd 100644 --- a/src/hw/nic.cpp +++ b/src/hw/nic.cpp @@ -19,46 +19,46 @@ #include /* -namespace hw { + namespace hw { */ /* -template <> const char* Nic::name(){ + template <> const char* Nic::name(){ //return "Fantastic VirtioNic No.1"; return driver.name(); -} + } */ /* -template <> Nic::Nic(PCI_Device* _dev) + template <> Nic::Nic(PCI_Device* _dev) : pcidev(_dev) //Device(this) -{ + { printf("\n Nic at PCI addr 0x%x scanning for resources\n",_dev->pci_addr()); _dev->probe_resources(); -} + } */ /* -template <> const char* Nic::name(){ + template <> const char* Nic::name(){ return "Specialized E1000 No.1"; -} + } -template <> Nic::Nic(PCI_Device* _dev) + template <> Nic::Nic(PCI_Device* _dev) : pcidev(_dev) //Device(this) -{ + { printf("\n Nic at PCI addr 0x%x scanning for resources\n",_dev->pci_addr()); _dev->probe_resources(); -} + } */ /* -} //< namespace hw + } //< namespace hw */ diff --git a/src/hw/pci_device.cpp b/src/hw/pci_device.cpp index 749363fcff..2a1174856c 100644 --- a/src/hw/pci_device.cpp +++ b/src/hw/pci_device.cpp @@ -24,129 +24,129 @@ namespace hw { -constexpr int NUM_CLASSCODES {19}; - -static const char* classcodes[NUM_CLASSCODES] { - "Too-Old-To-Tell", // 0 - "Mass Storage Controller", // 1 - "Network Controller", // 2 - "Display Controller", // 3 - "Multimedia Controller", // 4 - "Memory Controller", // 5 - "Bridge", // 6 - "Simple communications controllers", - "Base system peripherals", // 8 - "Inupt device", // 9 - "Docking Station", - "Processor", - "Serial Bus Controller", - "Wireless Controller", - "Intelligent I/O Controller", - "Satellite Communication Controller", // 15 - "Encryption/Decryption Controller", // 16 - "Data Acquisition and Signal Processing Controller", // 17 - NULL -}; - -constexpr int SS_BR {3}; - -static const char* bridge_subclasses[SS_BR] { - "Host", - "ISA", - "Other" -}; - -constexpr int SS_NIC {2}; - -static const char* nic_subclasses[SS_NIC] { - "Ethernet", - "Other" -}; - -struct _pci_vendor { - uint16_t id; - const char* name; -} _pci_vendorlist[] { - {0x8086,"Intel Corp."}, - {0x1013,"Cirrus Logic"}, - {0x10EC,"Realtek Semi.Corp."}, - {0x1AF4,"Virtio (Rusty Russell)"}, // Virtio creator - {0x1022,"AMD"}, - {0x0000,NULL} -}; - -static unsigned long pci_size(const unsigned long base, const unsigned long mask) noexcept { - // Find the significant bits - unsigned long size = mask & base; - - // Get the lowest of them to find the decode size - size &= ~(size - 1); - - return size; -} + constexpr int NUM_CLASSCODES {19}; + + static const char* classcodes[NUM_CLASSCODES] { + "Too-Old-To-Tell", // 0 + "Mass Storage Controller", // 1 + "Network Controller", // 2 + "Display Controller", // 3 + "Multimedia Controller", // 4 + "Memory Controller", // 5 + "Bridge", // 6 + "Simple communications controllers", + "Base system peripherals", // 8 + "Inupt device", // 9 + "Docking Station", + "Processor", + "Serial Bus Controller", + "Wireless Controller", + "Intelligent I/O Controller", + "Satellite Communication Controller", // 15 + "Encryption/Decryption Controller", // 16 + "Data Acquisition and Signal Processing Controller", // 17 + NULL + }; + + constexpr int SS_BR {3}; + + static const char* bridge_subclasses[SS_BR] { + "Host", + "ISA", + "Other" + }; + + constexpr int SS_NIC {2}; + + static const char* nic_subclasses[SS_NIC] { + "Ethernet", + "Other" + }; + + struct _pci_vendor { + uint16_t id; + const char* name; + } _pci_vendorlist[] { + {0x8086,"Intel Corp."}, + {0x1013,"Cirrus Logic"}, + {0x10EC,"Realtek Semi.Corp."}, + {0x1AF4,"Virtio (Rusty Russell)"}, // Virtio creator + {0x1022,"AMD"}, + {0x0000,NULL} + }; + + static unsigned long pci_size(const unsigned long base, const unsigned long mask) noexcept { + // Find the significant bits + unsigned long size = mask & base; + + // Get the lowest of them to find the decode size + size &= ~(size - 1); + + return size; + } -uint32_t PCI_Device::iobase() const noexcept { - assert(res_io_ != nullptr); - return res_io_->start_; -}; + uint32_t PCI_Device::iobase() const noexcept { + assert(res_io_ != nullptr); + return res_io_->start_; + }; -void PCI_Device::probe_resources() noexcept { - //Find resources on this PCI device (scan the BAR's) - uint32_t value {PCI::WTF}; + void PCI_Device::probe_resources() noexcept { + //Find resources on this PCI device (scan the BAR's) + uint32_t value {PCI::WTF}; - uint32_t reg {0}; - uint32_t len {0}; + uint32_t reg {0}; + uint32_t len {0}; - for(int bar {0}; bar < 6; ++bar) { - //Read the current BAR register - reg = PCI::CONFIG_BASE_ADDR_0 + (bar << 2); - value = read_dword(reg); + for(int bar {0}; bar < 6; ++bar) { + //Read the current BAR register + reg = PCI::CONFIG_BASE_ADDR_0 + (bar << 2); + value = read_dword(reg); - if (!value) continue; + if (!value) continue; - //Write all 1's to the register, to get the length value (osdev) - write_dword(reg, 0xFFFFFFFF); - len = read_dword(reg); + //Write all 1's to the register, to get the length value (osdev) + write_dword(reg, 0xFFFFFFFF); + len = read_dword(reg); - //Put the value back - write_dword(reg, value); + //Put the value back + write_dword(reg, value); - uint32_t unmasked_val {0}; - uint32_t pci__size {0}; + uint32_t unmasked_val {0}; + uint32_t pci__size {0}; - if (value & 1) { // Resource type IO + if (value & 1) { // Resource type IO - unmasked_val = value & PCI::BASE_ADDRESS_IO_MASK; - pci__size = pci_size(len, PCI::BASE_ADDRESS_IO_MASK & 0xFFFF); + unmasked_val = value & PCI::BASE_ADDRESS_IO_MASK; + pci__size = pci_size(len, PCI::BASE_ADDRESS_IO_MASK & 0xFFFF); - // Add it to resource list - add_resource(new Resource(unmasked_val, pci__size), res_io_); - assert(res_io_ != nullptr); + // Add it to resource list + add_resource(new Resource(unmasked_val, pci__size), res_io_); + assert(res_io_ != nullptr); - } else { //Resource type Mem + } else { //Resource type Mem - unmasked_val = value & PCI::BASE_ADDRESS_MEM_MASK; - pci__size = pci_size(len, PCI::BASE_ADDRESS_MEM_MASK); + unmasked_val = value & PCI::BASE_ADDRESS_MEM_MASK; + pci__size = pci_size(len, PCI::BASE_ADDRESS_MEM_MASK); - //Add it to resource list - add_resource(new Resource(unmasked_val, pci__size), res_mem_); - assert(res_mem_ != nullptr); - } + //Add it to resource list + add_resource(new Resource(unmasked_val, pci__size), res_mem_); + assert(res_mem_ != nullptr); + } + INFO2(""); + INFO2("[ Resource @ BAR %i ]", bar); + INFO2(" Address: 0x%x Size: 0x%x", unmasked_val, pci__size); + INFO2(" Type: %s", value & 1 ? "IO Resource" : "Memory Resource"); + } + INFO2(""); - INFO2("[ Resource @ BAR %i ]", bar); - INFO2(" Address: 0x%x Size: 0x%x", unmasked_val, pci__size); - INFO2(" Type: %s", value & 1 ? "IO Resource" : "Memory Resource"); } - - INFO2(""); -} -PCI_Device::PCI_Device(const uint16_t pci_addr, const uint32_t device_id) noexcept: + PCI_Device::PCI_Device(const uint16_t pci_addr, const uint32_t device_id) noexcept: pci_addr_{pci_addr}, device_id_{device_id} -// Device(Device::PCI) -// Why not inherit Device? Well, I think "PCI devices" are too general to be useful by itself, -// and the "Device" class is Public ABI, so it should only know about stuff that's relevant for the user. + // Device(Device::PCI) + // Why not inherit Device? Well, I think "PCI devices" are too general to be useful by itself, + // and the "Device" class is Public ABI, so it should only know about stuff that's relevant for the user. { //We have device, so probe for details devtype_.reg = read_dword(pci_addr, PCI::CONFIG_CLASS_REV); @@ -159,14 +159,14 @@ PCI_Device::PCI_Device(const uint16_t pci_addr, const uint32_t device_id) noexce switch (devtype_.classcode) { case PCI::BRIDGE: INFO2("+--+ %s %s (0x%x)", - bridge_subclasses[devtype_.subclass < SS_BR ? devtype_.subclass : SS_BR-1], - classcodes[devtype_.classcode],devtype_.subclass); + bridge_subclasses[devtype_.subclass < SS_BR ? devtype_.subclass : SS_BR-1], + classcodes[devtype_.classcode],devtype_.subclass); break; case PCI::NIC: INFO2("+--+ %s %s (0x%x)", - nic_subclasses[devtype_.subclass < SS_NIC ? devtype_.subclass : SS_NIC-1], - classcodes[devtype_.classcode],devtype_.subclass); + nic_subclasses[devtype_.subclass < SS_NIC ? devtype_.subclass : SS_NIC-1], + classcodes[devtype_.classcode],devtype_.subclass); break; default: @@ -179,39 +179,39 @@ PCI_Device::PCI_Device(const uint16_t pci_addr, const uint32_t device_id) noexce } -void PCI_Device::write_dword(const uint8_t reg, const uint32_t value) noexcept { - PCI::msg req; + void PCI_Device::write_dword(const uint8_t reg, const uint32_t value) noexcept { + PCI::msg req; - req.data = 0x80000000; - req.addr = pci_addr_; - req.reg = reg; + req.data = 0x80000000; + req.addr = pci_addr_; + req.reg = reg; - outpd(PCI::CONFIG_ADDR, static_cast(0x80000000) | req.data); - outpd(PCI::CONFIG_DATA, value); -} + outpd(PCI::CONFIG_ADDR, static_cast(0x80000000) | req.data); + outpd(PCI::CONFIG_DATA, value); + } -uint32_t PCI_Device::read_dword(const uint8_t reg) noexcept { - PCI::msg req; + uint32_t PCI_Device::read_dword(const uint8_t reg) noexcept { + PCI::msg req; - req.data = 0x80000000; - req.addr = pci_addr_; - req.reg = reg; + req.data = 0x80000000; + req.addr = pci_addr_; + req.reg = reg; - outpd(PCI::CONFIG_ADDR, static_cast(0x80000000) | req.data); + outpd(PCI::CONFIG_ADDR, static_cast(0x80000000) | req.data); - return inpd(PCI::CONFIG_DATA); -} + return inpd(PCI::CONFIG_DATA); + } -uint32_t PCI_Device::read_dword(const uint16_t pci_addr, const uint8_t reg) noexcept { - PCI::msg req; + uint32_t PCI_Device::read_dword(const uint16_t pci_addr, const uint8_t reg) noexcept { + PCI::msg req; - req.data = 0x80000000; - req.addr = pci_addr; - req.reg = reg; + req.data = 0x80000000; + req.addr = pci_addr; + req.reg = reg; - outpd(PCI::CONFIG_ADDR, static_cast(0x80000000) | req.data); + outpd(PCI::CONFIG_ADDR, static_cast(0x80000000) | req.data); - return inpd(PCI::CONFIG_DATA); -} + return inpd(PCI::CONFIG_DATA); + } } //< namespace hw diff --git a/src/hw/pit.cpp b/src/hw/pit.cpp index cbb26c65f1..503eb42538 100644 --- a/src/hw/pit.cpp +++ b/src/hw/pit.cpp @@ -25,262 +25,262 @@ namespace hw { -// Bit 0-3: Mode 0 - "Interrupt on terminal count" -// Bit 4-5: Both set, access mode "Lobyte / Hibyte" -const uint8_t PIT_mode_register = 0x43; -const uint8_t PIT_chan0 = 0x40; + // Bit 0-3: Mode 0 - "Interrupt on terminal count" + // Bit 4-5: Both set, access mode "Lobyte / Hibyte" + const uint8_t PIT_mode_register = 0x43; + const uint8_t PIT_chan0 = 0x40; -// PIT state -PIT::Mode PIT::current_mode_ = NONE; -PIT::Mode PIT::temp_mode_ = NONE; -uint16_t PIT::current_freq_divider_ = 0; -uint16_t PIT::temp_freq_divider_ = 0; + // PIT state + PIT::Mode PIT::current_mode_ = NONE; + PIT::Mode PIT::temp_mode_ = NONE; + uint16_t PIT::current_freq_divider_ = 0; + uint16_t PIT::temp_freq_divider_ = 0; -uint64_t PIT::IRQ_counter_ = 0; + uint64_t PIT::IRQ_counter_ = 0; -// Used for cpu frequency sampling -extern "C" double _CPUFreq_; -extern "C" uint16_t _cpu_sampling_freq_divider_; -extern "C" void irq_timer_entry(); + // Used for cpu frequency sampling + extern "C" double _CPUFreq_; + extern "C" uint16_t _cpu_sampling_freq_divider_; + extern "C" void irq_timer_entry(); -// Time keeping -uint64_t PIT::millisec_counter = 0; + // Time keeping + uint64_t PIT::millisec_counter = 0; -// The default recurring timer condition -std::function PIT::forever = []{ return true; }; + // The default recurring timer condition + std::function PIT::forever = []{ return true; }; -// Timer ID's -uint32_t PIT::Timer::timers_count_ = 0; + // Timer ID's + uint32_t PIT::Timer::timers_count_ = 0; -using namespace std::chrono; + using namespace std::chrono; -PIT::Timer::Timer(Type t, timeout_handler handler, std::chrono::milliseconds ms, repeat_condition cond) - : type_{t}, id_{++timers_count_}, handler_{handler}, interval_{ms}, cond_{cond} {}; + PIT::Timer::Timer(Type t, timeout_handler handler, std::chrono::milliseconds ms, repeat_condition cond) + : type_{t}, id_{++timers_count_}, handler_{handler}, interval_{ms}, cond_{cond} {}; -void PIT::disable_regular_interrupts() -{ - oneshot(1); -} + void PIT::disable_regular_interrupts() + { + oneshot(1); + } -PIT::~PIT(){} + PIT::~PIT(){} -PIT::PIT(){ - debug(" Instantiating. \n"); + PIT::PIT(){ + debug(" Instantiating. \n"); - auto handler(IRQ_manager::irq_delegate::from(this)); + auto handler(IRQ_manager::irq_delegate::from(this)); - IRQ_manager::subscribe(0, handler); -} + IRQ_manager::subscribe(0, handler); + } -void PIT::estimateCPUFrequency(){ + void PIT::estimateCPUFrequency(){ - debug(" Saving state: curr_freq_div %i \n",current_freq_divider_); - // Save PIT-state - temp_mode_ = current_mode_; - temp_freq_divider_ = current_freq_divider_; + debug(" Saving state: curr_freq_div %i \n",current_freq_divider_); + // Save PIT-state + temp_mode_ = current_mode_; + temp_freq_divider_ = current_freq_divider_; - auto prev_irq_handler = IRQ_manager::get_handler(32); + auto prev_irq_handler = IRQ_manager::get_handler(32); - debug(" Sampling\n"); - IRQ_manager::set_handler(32, cpu_sampling_irq_entry); + debug(" Sampling\n"); + IRQ_manager::set_handler(32, cpu_sampling_irq_entry); - // GO! - set_mode(RATE_GEN); - set_freq_divider(_cpu_sampling_freq_divider_); + // GO! + set_mode(RATE_GEN); + set_freq_divider(_cpu_sampling_freq_divider_); - // BLOCKING call to external measurment. - calculate_cpu_frequency(); + // BLOCKING call to external measurment. + calculate_cpu_frequency(); - debug(" Done. Result: %f \n", _CPUFreq_); + debug(" Done. Result: %f \n", _CPUFreq_); - set_mode(temp_mode_); - set_freq_divider(temp_freq_divider_); + set_mode(temp_mode_); + set_freq_divider(temp_freq_divider_); - IRQ_manager::set_handler(32, prev_irq_handler); -} + IRQ_manager::set_handler(32, prev_irq_handler); + } -MHz PIT::CPUFrequency(){ - if (! _CPUFreq_) - estimateCPUFrequency(); + MHz PIT::CPUFrequency(){ + if (! _CPUFreq_) + estimateCPUFrequency(); - return MHz(_CPUFreq_); -} + return MHz(_CPUFreq_); + } -void PIT::start_timer(Timer t, std::chrono::milliseconds in_msecs){ - if (in_msecs < 1ms) panic("Can't wait less than 1 ms. "); + void PIT::start_timer(Timer t, std::chrono::milliseconds in_msecs){ + if (in_msecs < 1ms) panic("Can't wait less than 1 ms. "); - if (current_mode_ != RATE_GEN) - set_mode(RATE_GEN); + if (current_mode_ != RATE_GEN) + set_mode(RATE_GEN); - if (current_freq_divider_ != millisec_interval) - set_freq_divider(millisec_interval); + if (current_freq_divider_ != millisec_interval) + set_freq_divider(millisec_interval); - auto cycles_pr_millisec = KHz(CPUFrequency()); - debug(" CPU KHz: %f Cycles to wait: %f \n",cycles_pr_millisec.count(), cycles_pr_millisec.count() * in_msecs); + auto cycles_pr_millisec = KHz(CPUFrequency()); + debug(" CPU KHz: %f Cycles to wait: %f \n",cycles_pr_millisec.count(), cycles_pr_millisec.count() * in_msecs); - auto ticks = in_msecs / KHz(current_frequency()).count(); - debug(" PIT KHz: %f * %i = %f ms. \n", - KHz(current_frequency()).count(), (uint32_t)ticks.count(), ((uint32_t)ticks.count() * KHz(current_frequency()).count())); + auto ticks = in_msecs / KHz(current_frequency()).count(); + debug(" PIT KHz: %f * %i = %f ms. \n", + KHz(current_frequency()).count(), (uint32_t)ticks.count(), ((uint32_t)ticks.count() * KHz(current_frequency()).count())); - t.setStart(OS::cycles_since_boot()); - t.setEnd(t.start() + uint64_t(cycles_pr_millisec.count() * in_msecs.count())); + t.setStart(OS::cycles_since_boot()); + t.setEnd(t.start() + uint64_t(cycles_pr_millisec.count() * in_msecs.count())); - auto key = millisec_counter + ticks.count(); + auto key = millisec_counter + ticks.count(); - // We could emplace, but the timer exists allready, and might be a reused one - timers_.insert(std::make_pair(key, t)); + // We could emplace, but the timer exists allready, and might be a reused one + timers_.insert(std::make_pair(key, t)); - debug(" Key: %i id: %i, t.cond()(): %s There are %i timers. \n", - (uint32_t)key, t.id(), t.cond()() ? "true" : "false", timers_.size()); + debug(" Key: %i id: %i, t.cond()(): %s There are %i timers. \n", + (uint32_t)key, t.id(), t.cond()() ? "true" : "false", timers_.size()); -} + } -void PIT::onRepeatedTimeout(std::chrono::milliseconds ms, timeout_handler handler, repeat_condition cond){ - debug(" setting a %i ms. repeating timer \n", (uint32_t)ms.count()); + void PIT::onRepeatedTimeout(std::chrono::milliseconds ms, timeout_handler handler, repeat_condition cond){ + debug(" setting a %i ms. repeating timer \n", (uint32_t)ms.count()); - Timer t(Timer::REPEAT_WHILE, handler, ms, cond); - start_timer(t, ms); -}; + Timer t(Timer::REPEAT_WHILE, handler, ms, cond); + start_timer(t, ms); + }; -void PIT::onTimeout(std::chrono::milliseconds msec, timeout_handler handler){ - Timer t(Timer::ONE_SHOT, handler, msec); + void PIT::onTimeout(std::chrono::milliseconds msec, timeout_handler handler){ + Timer t(Timer::ONE_SHOT, handler, msec); - debug(" setting a %i ms. one-shot timer. Id: %i \n", - (uint32_t)msec.count(), t.id()); + debug(" setting a %i ms. one-shot timer. Id: %i \n", + (uint32_t)msec.count(), t.id()); - start_timer(t, msec); + start_timer(t, msec); -}; + }; -uint8_t PIT::read_back(uint8_t){ - const uint8_t READ_BACK_CMD = 0xc2; + uint8_t PIT::read_back(uint8_t){ + const uint8_t READ_BACK_CMD = 0xc2; - hw::outb(PIT_mode_register, READ_BACK_CMD ); + hw::outb(PIT_mode_register, READ_BACK_CMD ); - auto res = hw::inb(PIT_chan0); + auto res = hw::inb(PIT_chan0); - debug("STATUS: %#x \n", res); + debug("STATUS: %#x \n", res); - return res; + return res; -} + } -void PIT::irq_handler(){ - // All IRQ-handlers has to send EOI - IRQ_manager::eoi(0); + void PIT::irq_handler(){ + // All IRQ-handlers has to send EOI + IRQ_manager::eoi(0); - IRQ_counter_ ++; + IRQ_counter_ ++; - if (current_freq_divider_ == millisec_interval) - millisec_counter++; + if (current_freq_divider_ == millisec_interval) + millisec_counter++; - #ifdef DEBUG - if (millisec_counter % 100 == 0) - OS::rsprint("."); - #endif +#ifdef DEBUG + if (millisec_counter % 100 == 0) + OS::rsprint("."); +#endif - // Iterate over expired timers (we break on the first non-expired) - for (auto it = timers_.begin(); it != timers_.end(); it++) { + // Iterate over expired timers (we break on the first non-expired) + for (auto it = timers_.begin(); it != timers_.end(); it++) { - // Map-keys are sorted. If this timer isn't expired, neither are the rest - if (it->first > millisec_counter) - break; + // Map-keys are sorted. If this timer isn't expired, neither are the rest + if (it->first > millisec_counter) + break; - debug2 ("\n**** Timer type %i, id: %i expired. Running handler **** \n", - it->second.type(), it->second.id()); + debug2 ("\n**** Timer type %i, id: %i expired. Running handler **** \n", + it->second.type(), it->second.id()); - // Execute the handler - it->second.handler()(); + // Execute the handler + it->second.handler()(); - // Re-queue repeating timers - if (it->second.type() == Timer::REPEAT) { - debug2 (" REPEAT: Requeuing the timer \n"); - start_timer(it->second, it->second.interval()); + // Re-queue repeating timers + if (it->second.type() == Timer::REPEAT) { + debug2 (" REPEAT: Requeuing the timer \n"); + start_timer(it->second, it->second.interval()); - }else if (it->second.type() == Timer::REPEAT_WHILE and it->second.cond()()) { - debug2 (" REPEAT_WHILE: Requeuing the timer COND \n"); - start_timer(it->second, it->second.interval()); - } + }else if (it->second.type() == Timer::REPEAT_WHILE and it->second.cond()()) { + debug2 (" REPEAT_WHILE: Requeuing the timer COND \n"); + start_timer(it->second, it->second.interval()); + } - debug2 ("Timer done. Erasing. \n"); + debug2 ("Timer done. Erasing. \n"); - // Escape iterator death - auto remove = it; - it++; + // Escape iterator death + auto remove = it; + it++; - // Erase the timer - timers_.erase(remove); + // Erase the timer + timers_.erase(remove); - // If this was the last timer, we can turn off the clock - if (timers_.empty()){ - // Disable the PIT - oneshot(1); + // If this was the last timer, we can turn off the clock + if (timers_.empty()){ + // Disable the PIT + oneshot(1); - debug2 ("Timers done. PIT disabled for now. \n"); - // Escape iterator death - break; - } + debug2 ("Timers done. PIT disabled for now. \n"); + // Escape iterator death + break; + } - debug2 ("Timers left: %i \n", timers_.size()); + debug2 ("Timers left: %i \n", timers_.size()); - #ifdef DEBUG2 - for (auto t : timers_) - debug2("Key: %i , id: %i, Type: %i", (uint32_t)t.first, t.second.id(), t.second.type()); - #endif +#ifdef DEBUG2 + for (auto t : timers_) + debug2("Key: %i , id: %i, Type: %i", (uint32_t)t.first, t.second.id(), t.second.type()); +#endif - debug2("\n---------------------------\n\n"); - } + debug2("\n---------------------------\n\n"); + } -} + } -void PIT::init(){ - debug(" Initializing @ frequency: %16.16f MHz. Assigning myself to all timer interrupts.\n ", frequency()); - PIT::disable_regular_interrupts(); - IRQ_manager::enable_irq(0); -} + void PIT::init(){ + debug(" Initializing @ frequency: %16.16f MHz. Assigning myself to all timer interrupts.\n ", frequency()); + PIT::disable_regular_interrupts(); + IRQ_manager::enable_irq(0); + } -void PIT::set_mode(Mode mode){ - // Channel is the last two bits in the PIT mode register - // ...we always use channel 0 - auto channel = 0x00; - uint8_t config = mode | LO_HI | channel; - debug(" Setting mode %#x, config: %#x \n", mode, config); + void PIT::set_mode(Mode mode){ + // Channel is the last two bits in the PIT mode register + // ...we always use channel 0 + auto channel = 0x00; + uint8_t config = mode | LO_HI | channel; + debug(" Setting mode %#x, config: %#x \n", mode, config); - hw::outb(PIT_mode_register, config); - current_mode_ = mode; + hw::outb(PIT_mode_register, config); + current_mode_ = mode; -} + } -void PIT::set_freq_divider(uint16_t freq_divider){ - union{ - uint16_t whole; - uint8_t part[2]; - }data{freq_divider}; + void PIT::set_freq_divider(uint16_t freq_divider){ + union{ + uint16_t whole; + uint8_t part[2]; + }data{freq_divider}; - // Send frequency hi/lo to PIT - hw::outb(PIT_chan0, data.part[0]); - hw::outb(PIT_chan0, data.part[1]); + // Send frequency hi/lo to PIT + hw::outb(PIT_chan0, data.part[0]); + hw::outb(PIT_chan0, data.part[1]); - current_freq_divider_ = freq_divider; + current_freq_divider_ = freq_divider; -} + } -void PIT::oneshot(uint16_t t){ + void PIT::oneshot(uint16_t t){ - // Enable 1-shot mode - set_mode(ONE_SHOT); + // Enable 1-shot mode + set_mode(ONE_SHOT); - // Set a frequency for shot - set_freq_divider(t); -} + // Set a frequency for shot + set_freq_divider(t); + } } //< namespace hw diff --git a/src/include/hw/cpu_freq_sampling.hpp b/src/include/hw/cpu_freq_sampling.hpp index 733dde58df..44b902a251 100644 --- a/src/include/hw/cpu_freq_sampling.hpp +++ b/src/include/hw/cpu_freq_sampling.hpp @@ -21,17 +21,17 @@ namespace hw { -/** Proper IRQ-handler for CPU frequency sampling - implemented in interrupts.s - @Note - PIT::estimateCPUFrequency() will register- /de-register this as needed */ -extern "C" void cpu_sampling_irq_handler(); + /** Proper IRQ-handler for CPU frequency sampling - implemented in interrupts.s + @Note + PIT::estimateCPUFrequency() will register- /de-register this as needed */ + extern "C" void cpu_sampling_irq_handler(); -/** CPU frequency sampling. Implemented in hw/cpu_freq_sampling.cpp - @Note this will be automatically called by the oirq-handler */ -extern "C" void cpu_sampling_irq_entry(); + /** CPU frequency sampling. Implemented in hw/cpu_freq_sampling.cpp + @Note this will be automatically called by the oirq-handler */ + extern "C" void cpu_sampling_irq_entry(); -extern "C" void irq_32_entry(); + extern "C" void irq_32_entry(); -extern "C" MHz calculate_cpu_frequency(); + extern "C" MHz calculate_cpu_frequency(); } //< namespace hw diff --git a/src/kernel/cpuid.cpp b/src/kernel/cpuid.cpp index 7982f55c3d..0a38bfb572 100644 --- a/src/kernel/cpuid.cpp +++ b/src/kernel/cpuid.cpp @@ -95,32 +95,32 @@ static cpuid_t cpuid_info(const unsigned int func, const unsigned int subfunc) { cpuid_t info; __asm__ __volatile__ ( - "cpuid" - : "=a"(info.EAX), "=b"(info.EBX), "=c"(info.ECX), "=d"(info.EDX) - : "a"(func), "c"(subfunc) : "%eax", "%ebx", "%ecx", "%edx" - ); + "cpuid" + : "=a"(info.EAX), "=b"(info.EBX), "=c"(info.ECX), "=d"(info.EDX) + : "a"(func), "c"(subfunc) : "%eax", "%ebx", "%ecx", "%edx" + ); return info; } bool CPUID::isAmdCpu() { cpuid_t info = cpuid_info(0, 0); if (memcmp((char *) (&info.EBX), "htuA", 4) == 0 - && memcmp((char *) (&info.EDX), "itne", 4) == 0 - && memcmp((char *) (&info.ECX), "DMAc", 4) == 0) - { + && memcmp((char *) (&info.EDX), "itne", 4) == 0 + && memcmp((char *) (&info.ECX), "DMAc", 4) == 0) + { return true; - } + } return false; } bool CPUID::isIntelCpu() { cpuid_t info = cpuid_info(0, 0); if (memcmp((char *) (&info.EBX), "Genu", 4) == 0 - && memcmp((char *) (&info.EDX), "ineI", 4) == 0 - && memcmp((char *) (&info.ECX), "ntel", 4) == 0) - { + && memcmp((char *) (&info.EDX), "ineI", 4) == 0 + && memcmp((char *) (&info.ECX), "ntel", 4) == 0) + { return true; - } + } return false; } diff --git a/src/kernel/irq_manager.cpp b/src/kernel/irq_manager.cpp index 5cc5859d96..21dbfa2230 100644 --- a/src/kernel/irq_manager.cpp +++ b/src/kernel/irq_manager.cpp @@ -66,39 +66,39 @@ extern "C" } /** Default Exception-handler, which just prints its number */ -#define EXCEPTION_HANDLER(I) \ - void exception_##I##_handler() { \ - printf("\n\n>>>> !!! CPU EXCEPTION %i !!! <<<<<\n", I); \ - printf("Heap end: %#x \n", (uint32_t)&_end); \ - kill(1, 9); \ +#define EXCEPTION_HANDLER(I) \ + void exception_##I##_handler() { \ + printf("\n\n>>>> !!! CPU EXCEPTION %i !!! <<<<<\n", I); \ + printf("Heap end: %#x \n", (uint32_t)&_end); \ + kill(1, 9); \ } void exception_handler() { - #define frp(N, ra) \ - (__builtin_frame_address(N) != nullptr) && \ - (ra = __builtin_return_address(N)) != nullptr +#define frp(N, ra) \ + (__builtin_frame_address(N) != nullptr) && \ + (ra = __builtin_return_address(N)) != nullptr printf("\n"); - #define PRINT_TRACE(N, ra) \ - printf("[%d] Return %p\n", N, ra); +#define PRINT_TRACE(N, ra) \ + printf("[%d] Return %p\n", N, ra); void* ra; if (frp(0, ra)) { - PRINT_TRACE(0, ra); - if (frp(1, ra)) { - PRINT_TRACE(1, ra); - if (frp(2, ra)) { - PRINT_TRACE(2, ra); - if (frp(3, ra)) { - PRINT_TRACE(3, ra); - if (frp(4, ra)) { - PRINT_TRACE(4, ra); - if (frp(5, ra)) { - PRINT_TRACE(5, ra); - if (frp(6, ra)) - PRINT_TRACE(6, ra); - }}}}}} + PRINT_TRACE(0, ra); + if (frp(1, ra)) { + PRINT_TRACE(1, ra); + if (frp(2, ra)) { + PRINT_TRACE(2, ra); + if (frp(3, ra)) { + PRINT_TRACE(3, ra); + if (frp(4, ra)) { + PRINT_TRACE(4, ra); + if (frp(5, ra)) { + PRINT_TRACE(5, ra); + if (frp(6, ra)) + PRINT_TRACE(6, ra); + }}}}}} printf(">>>> !!! CPU EXCEPTION !!! <<<<\n"); extern char _end; @@ -115,19 +115,19 @@ void exception_handler() uint32_t IRQ_manager::irq_counters_[32] {0}; -#define IRQ_HANDLER(I) \ - void irq_##I##_handler() { \ - IRQ_manager::register_interrupt(I); \ +#define IRQ_HANDLER(I) \ + void irq_##I##_handler() { \ + IRQ_manager::register_interrupt(I); \ } /* Macro magic to register default gates */ -#define REG_DEFAULT_EXCPT(I) create_gate(&(idt[I]),exception_entry, \ - default_sel, default_attr ); +#define REG_DEFAULT_EXCPT(I) create_gate(&(idt[I]),exception_entry, \ + default_sel, default_attr ); -#define REG_DEFAULT_IRQ(I) create_gate(&(idt[I + irq_base]),irq_##I##_entry, \ - default_sel, default_attr ); +#define REG_DEFAULT_IRQ(I) create_gate(&(idt[I + irq_base]),irq_##I##_entry, \ + default_sel, default_attr ); - /* EXCEPTIONS */ +/* EXCEPTIONS */ #define EXCEPTION_PAIR(I) void exception_entry(); #define IRQ_PAIR(I) void irq_##I##_entry(); IRQ_HANDLER(I) @@ -191,27 +191,27 @@ void IRQ_manager::init() // Assign the lower 32 IRQ's : Exceptions REG_DEFAULT_EXCPT(0) REG_DEFAULT_EXCPT(1) REG_DEFAULT_EXCPT(2) - REG_DEFAULT_EXCPT(3) REG_DEFAULT_EXCPT(4) REG_DEFAULT_EXCPT(5) - REG_DEFAULT_EXCPT(6) REG_DEFAULT_EXCPT(7) REG_DEFAULT_EXCPT(8) - REG_DEFAULT_EXCPT(9) REG_DEFAULT_EXCPT(10) REG_DEFAULT_EXCPT(11) - REG_DEFAULT_EXCPT(12) REG_DEFAULT_EXCPT(13) REG_DEFAULT_EXCPT(14) - REG_DEFAULT_EXCPT(15) REG_DEFAULT_EXCPT(16) REG_DEFAULT_EXCPT(17) - REG_DEFAULT_EXCPT(18) REG_DEFAULT_EXCPT(19) REG_DEFAULT_EXCPT(20) - // GATES 21-29 are reserved - REG_DEFAULT_EXCPT(30) REG_DEFAULT_EXCPT(31) - INFO2("+ Exception gates set for irq < 32"); + REG_DEFAULT_EXCPT(3) REG_DEFAULT_EXCPT(4) REG_DEFAULT_EXCPT(5) + REG_DEFAULT_EXCPT(6) REG_DEFAULT_EXCPT(7) REG_DEFAULT_EXCPT(8) + REG_DEFAULT_EXCPT(9) REG_DEFAULT_EXCPT(10) REG_DEFAULT_EXCPT(11) + REG_DEFAULT_EXCPT(12) REG_DEFAULT_EXCPT(13) REG_DEFAULT_EXCPT(14) + REG_DEFAULT_EXCPT(15) REG_DEFAULT_EXCPT(16) REG_DEFAULT_EXCPT(17) + REG_DEFAULT_EXCPT(18) REG_DEFAULT_EXCPT(19) REG_DEFAULT_EXCPT(20) + // GATES 21-29 are reserved + REG_DEFAULT_EXCPT(30) REG_DEFAULT_EXCPT(31) + INFO2("+ Exception gates set for irq < 32"); //Redirected IRQ 0 - 15 REG_DEFAULT_IRQ(0) REG_DEFAULT_IRQ(1) REG_DEFAULT_IRQ(3) - REG_DEFAULT_IRQ(4) REG_DEFAULT_IRQ(5) REG_DEFAULT_IRQ(6) - REG_DEFAULT_IRQ(7) REG_DEFAULT_IRQ(8) REG_DEFAULT_IRQ(9) - REG_DEFAULT_IRQ(10) REG_DEFAULT_IRQ(11) REG_DEFAULT_IRQ(12) - REG_DEFAULT_IRQ(13) REG_DEFAULT_IRQ(14) REG_DEFAULT_IRQ(15) - - //Set all irq-gates (> 47) to the default handler - for(int i=48;i 47) to the default handler + for(int i=48;i= 32"); //Load IDT @@ -232,9 +232,9 @@ union addr_union { }; void IRQ_manager::create_gate(IDTDescr* idt_entry, - void (*function_addr)(), - uint16_t segment_sel, - char attributes) { + void (*function_addr)(), + uint16_t segment_sel, + char attributes) { addr_union addr; addr.whole = (uint32_t)function_addr; idt_entry->offset_1 = addr.lo16; @@ -268,7 +268,7 @@ IRQ_manager::irq_delegate IRQ_manager::get_subscriber(uint8_t irq) { } void IRQ_manager::enable_irq(uint8_t irq) { - hw::PIC::enable_irq(irq); + hw::PIC::enable_irq(irq); } int IRQ_manager::timer_interrupts {0}; @@ -325,9 +325,9 @@ void IRQ_manager::notify() { // Spinlock? Well, we can't lock out the IRQ-handler // ... and we don't have a timer interrupt so we can't do blocking locks. if (!irq_counters_[irq]) { - // Remove the IRQ from pending list - irq_pending_ &= ~(1 << irq); - //debug(" IRQ's pending: 0x%lx\n",irq_pending_); + // Remove the IRQ from pending list + irq_pending_ &= ~(1 << irq); + //debug(" IRQ's pending: 0x%lx\n",irq_pending_); } // Critical section end @@ -342,7 +342,7 @@ void IRQ_manager::notify() { } void IRQ_manager::eoi(uint8_t irq) { - hw::PIC::eoi(irq); + hw::PIC::eoi(irq); } void irq_default_handler() { diff --git a/src/kernel/os.cpp b/src/kernel/os.cpp index e4c31c920e..532e9e6eea 100644 --- a/src/kernel/os.cpp +++ b/src/kernel/os.cpp @@ -68,16 +68,16 @@ void OS::start() { /** Estimate CPU frequency - MYINFO("Estimating CPU-frequency"); - INFO2("|"); - INFO2("+--(10 samples, %f sec. interval)", - (hw::PIT::frequency() / _cpu_sampling_freq_divider_).count()); - INFO2("|"); + MYINFO("Estimating CPU-frequency"); + INFO2("|"); + INFO2("+--(10 samples, %f sec. interval)", + (hw::PIT::frequency() / _cpu_sampling_freq_divider_).count()); + INFO2("|"); - // TODO: Debug why actual measurments sometimes causes problems. Issue #246. - cpu_mhz_ = hw::PIT::CPUFrequency(); + // TODO: Debug why actual measurments sometimes causes problems. Issue #246. + cpu_mhz_ = hw::PIT::CPUFrequency(); - INFO2("+--> %f MHz", cpu_mhz_.count()); + INFO2("+--> %f MHz", cpu_mhz_.count()); **/ diff --git a/src/kernel/pci_manager.cpp b/src/kernel/pci_manager.cpp index a0998e590f..e643043ea4 100644 --- a/src/kernel/pci_manager.cpp +++ b/src/kernel/pci_manager.cpp @@ -35,11 +35,11 @@ void PCI_manager::init() { uint32_t id {PCI::WTF}; for (uint16_t pci_addr {0}; pci_addr < 255; ++pci_addr) { - id = hw::PCI_Device::read_dword(pci_addr, PCI::CONFIG_VENDOR); - if (id != PCI::WTF) { - hw::PCI_Device dev {pci_addr, id}; - devices_[dev.classcode()].emplace_back(dev); - } + id = hw::PCI_Device::read_dword(pci_addr, PCI::CONFIG_VENDOR); + if (id != PCI::WTF) { + hw::PCI_Device dev {pci_addr, id}; + devices_[dev.classcode()].emplace_back(dev); + } } // Pretty printing, end of device tree diff --git a/src/kernel/rdrand.cpp b/src/kernel/rdrand.cpp index a24ece1541..aa927244c5 100644 --- a/src/kernel/rdrand.cpp +++ b/src/kernel/rdrand.cpp @@ -25,9 +25,9 @@ bool rdrand16(uint16_t* result) { int res = 0; while (res == 0) - { - res = _rdrand16_step(result); - } + { + res = _rdrand16_step(result); + } return (res == 1); } @@ -35,8 +35,8 @@ bool rdrand32(uint32_t* result) { int res = 0; while (res == 0) - { - res = _rdrand32_step(result); - } + { + res = _rdrand32_step(result); + } return (res == 1); } diff --git a/src/kernel/syscalls.cpp b/src/kernel/syscalls.cpp index 112cd976b1..706fb0288e 100644 --- a/src/kernel/syscalls.cpp +++ b/src/kernel/syscalls.cpp @@ -111,7 +111,7 @@ int read(int UNUSED(file), void* UNUSED(ptr), size_t UNUSED(len)) { int write(int file, const void* ptr, size_t len) { if (file == syscall_fd and not debug_syscalls) { - return len; + return len; } return OS::rsprint((const char*) ptr, len); } diff --git a/src/kernel/terminal.cpp b/src/kernel/terminal.cpp index 8211006cbe..38e97b13ad 100644 --- a/src/kernel/terminal.cpp +++ b/src/kernel/terminal.cpp @@ -32,25 +32,25 @@ Terminal::Terminal(Connection_ptr csock) : Terminal() { csock->read(1024, [this](auto buffer, size_t n){ - this->read((char*)buffer.get(), n); - }); + this->read((char*)buffer.get(), n); + }); /*csock->onReceive( - [this] (auto conn, bool) - { + [this] (auto conn, bool) + { char buffer[1024]; size_t bytes = conn->read(buffer, sizeof(buffer)); this->read(buffer, bytes); - });*/ + });*/ on_write = - [csock] (const char* buffer, size_t len) - { - csock->write(buffer, len); - }; + [csock] (const char* buffer, size_t len) + { + csock->write(buffer, len); + }; on_exit = - [csock] { + [csock] { csock->close(); }; // after setting up everything, show introduction @@ -61,29 +61,29 @@ Terminal::Terminal(hw::Serial& serial) : Terminal() { serial.on_data( - [this, &serial] (char c) - { - this->read(&c, 1); - if (c == CR) - { - c = LF; - this->read(&c, 1); - } - else - { - serial.write(c); - } - }); + [this, &serial] (char c) + { + this->read(&c, 1); + if (c == CR) + { + c = LF; + this->read(&c, 1); + } + else + { + serial.write(c); + } + }); on_write = - [&serial] (const char* buffer, size_t len) - { - for (size_t i = 0; i < len; i++) - serial.write(buffer[i]); - }; + [&serial] (const char* buffer, size_t len) + { + for (size_t i = 0; i < len; i++) + serial.write(buffer[i]); + }; on_exit = - [] { + [] { // do nothing }; // after setting up everything, show introduction @@ -93,86 +93,86 @@ Terminal::Terminal(hw::Serial& serial) void Terminal::read(const char* buf, size_t len) { while (len) - { - if (this->subcmd) - { - // execute options - option(this->subcmd, (uint8_t) *buf); - this->subcmd = 0; - } - else if (this->iac) { - command(*(uint8_t*) buf); - this->iac = false; + if (this->subcmd) + { + // execute options + option(this->subcmd, (uint8_t) *buf); + this->subcmd = 0; + } + else if (this->iac) + { + command(*(uint8_t*) buf); + this->iac = false; + } + else if (*buf == 13 && !newline) + { + newline = true; + } + else if (*buf == 10 && newline) + { + newline = false; + // parse message + run(buffer); + buffer.clear(); + } + else if (*buf == 0) + { + // NOP + } + else if ((uint8_t) *buf == 0xFF) + { + // Interpret as Command + this->iac = true; + } + else + { + buffer.append(buf, 1); + } + buf++; len--; } - else if (*buf == 13 && !newline) - { - newline = true; - } - else if (*buf == 10 && newline) - { - newline = false; - // parse message - run(buffer); - buffer.clear(); - } - else if (*buf == 0) - { - // NOP - } - else if ((uint8_t) *buf == 0xFF) - { - // Interpret as Command - this->iac = true; - } - else - { - buffer.append(buf, 1); - } - buf++; len--; - } } void Terminal::command(uint8_t cmd) { switch (cmd) - { - case 247: // erase char - printf("CMD: Erase char\n"); - break; - case 248: // erase line - printf("CMD: Erase line\n"); - break; - case 250: // Begin - printf("CMD: Begin...\n"); - break; - case 251: // Will USE - case 252: // Won't USE - case 253: // Start USE - case 254: // Stop USE - //printf("CMD: Command %d\n", cmd); - this->subcmd = cmd; - break; - case 255: - //printf("CMD: Command %d\n", cmd); - this->subcmd = cmd; - break; - default: - printf("CMD: Unknown command %d\n", cmd); - } + { + case 247: // erase char + printf("CMD: Erase char\n"); + break; + case 248: // erase line + printf("CMD: Erase line\n"); + break; + case 250: // Begin + printf("CMD: Begin...\n"); + break; + case 251: // Will USE + case 252: // Won't USE + case 253: // Start USE + case 254: // Stop USE + //printf("CMD: Command %d\n", cmd); + this->subcmd = cmd; + break; + case 255: + //printf("CMD: Command %d\n", cmd); + this->subcmd = cmd; + break; + default: + printf("CMD: Unknown command %d\n", cmd); + } } void Terminal::option(uint8_t option, uint8_t cmd) { (void) option; switch (cmd) - { - case 24: // terminal type - break; - default: - //printf("CMD: Unknown cmd %d for option %d\n", cmd, option); - break; - } + { + case 24: // terminal type + break; + default: + //printf("CMD: Unknown cmd %d for option %d\n", cmd, option); + break; + } } std::vector @@ -188,41 +188,41 @@ split(const std::string& text, std::string& command) x = text.find(" "); // early return for cmd-only msg if (x == std::string::npos) - { - command = text; - return retv; - } + { + command = text; + return retv; + } // command is substring command = text.substr(0, x); p = x+1; } // parse remainder do - { - x = text.find(" ", p+1); - size_t y = text.find(":", x+1); // find last param - - if (y == x+1) - { - // single argument - retv.push_back(text.substr(p, x-p)); - // ending text argument - retv.push_back(text.substr(y+1)); - break; - } - else if (x != std::string::npos) { - // single argument - retv.push_back(text.substr(p, x-p)); - } - else - { - // last argument - retv.push_back(text.substr(p)); - } - p = x+1; + x = text.find(" ", p+1); + size_t y = text.find(":", x+1); // find last param + + if (y == x+1) + { + // single argument + retv.push_back(text.substr(p, x-p)); + // ending text argument + retv.push_back(text.substr(y+1)); + break; + } + else if (x != std::string::npos) + { + // single argument + retv.push_back(text.substr(p, x-p)); + } + else + { + // last argument + retv.push_back(text.substr(p)); + } + p = x+1; - } while (x != std::string::npos); + } while (x != std::string::npos); return retv; } @@ -232,20 +232,20 @@ void Terminal::run(const std::string& cmd_string) std::string cmd_name; auto cmd_vec = split(cmd_string, cmd_name); if (cmd_name.size()) - { - printf("Terminal::run(): %s\n", cmd_name.c_str()); - - auto it = commands.find(cmd_name); - if (it != commands.end()) - { - int retv = it->second.main(cmd_vec); - if (retv) write("%s returned: %d\r\n", cmd_name.c_str(), retv); - } - else { - write("No such command: '%s'\r\n", cmd_name.c_str()); + printf("Terminal::run(): %s\n", cmd_name.c_str()); + + auto it = commands.find(cmd_name); + if (it != commands.end()) + { + int retv = it->second.main(cmd_vec); + if (retv) write("%s returned: %d\r\n", cmd_name.c_str(), retv); + } + else + { + write("No such command: '%s'\r\n", cmd_name.c_str()); + } } - } prompt(); } @@ -253,29 +253,29 @@ void Terminal::add_basic_commands() { // ?: add( - "?", "List available commands", - [this] (const std::vector&) -> int - { - for (auto cmd : this->commands) + "?", "List available commands", + [this] (const std::vector&) -> int { - write("%s \t-- %s\r\n", cmd.first.c_str(), cmd.second.desc.c_str()); - } - return 0; - }); + for (auto cmd : this->commands) + { + write("%s \t-- %s\r\n", cmd.first.c_str(), cmd.second.desc.c_str()); + } + return 0; + }); // exit: add( - "exit", "Close the terminal", - [this] (const std::vector&) -> int - { - this->on_exit(); - return 0; - }); + "exit", "Close the terminal", + [this] (const std::vector&) -> int + { + this->on_exit(); + return 0; + }); } void Terminal::intro() { std::string banana = - R"baaa( + R"baaa( ____ ___ | _ \ ___ _ _.' _ `. _ | [_) )' _ `._ _ ___ ! \ | | (_) | _ @@ -285,13 +285,13 @@ void Terminal::intro() !::, `-!_| | | |\ | | | | | \ !_!.' ':;! !::; ":;:!.!.\_!_!_!.!-'-':;:'' '''! ';:' `::;::;' '' ., . - `: .,. `' .::... . .::;::;' - `..:;::;:.. ::;::;:;:;, :;::;' + `: .,. `' .::... . .::;::;' + `..:;::;:.. ::;::;:;:;, :;::;' "-:;::;:;: ':;::;:'' ;.-' ""`---...________...---'"" -> Banana Terminal v1 < -)baaa"; + > Banana Terminal v1 < + )baaa"; write("%s", banana.c_str()); prompt(); diff --git a/src/kernel/terminal_disk.cpp b/src/kernel/terminal_disk.cpp index 03966875aa..77b8586a1c 100644 --- a/src/kernel/terminal_disk.cpp +++ b/src/kernel/terminal_disk.cpp @@ -45,116 +45,116 @@ void Terminal::add_disk_commands(Disk_ptr disk) // add 'cd' command add("cd", "Change current directory", - [this, curdir, disk] (const std::vector& args) -> int - { - // current directory, somehow... - std::string target = "/"; - if (!args.empty()) target = args[0]; + [this, curdir, disk] (const std::vector& args) -> int + { + // current directory, somehow... + std::string target = "/"; + if (!args.empty()) target = args[0]; - Path path(*curdir); - path += target; + Path path(*curdir); + path += target; - int rv = target_directory(disk, path); - if (rv) - { - this->write("cd: %s: No such file or directory\r\n", target.c_str()); - return rv; - } - *curdir = path.to_string(); - return 0; - }); + int rv = target_directory(disk, path); + if (rv) + { + this->write("cd: %s: No such file or directory\r\n", target.c_str()); + return rv; + } + *curdir = path.to_string(); + return 0; + }); // add 'ls' command add("ls", "List files in a folder", - [this, curdir, disk] (const std::vector& args) -> int - { - // current directory, somehow... - Path path(*curdir); - if (!args.empty()) path += args[0]; - - int rv = target_directory(disk, path); - if (rv) + [this, curdir, disk] (const std::vector& args) -> int { - this->write("ls: %s: No such file or directory\r\n", path.to_string().c_str()); - return rv; - } + // current directory, somehow... + Path path(*curdir); + if (!args.empty()) path += args[0]; - std::string target = path.to_string(); + int rv = target_directory(disk, path); + if (rv) + { + this->write("ls: %s: No such file or directory\r\n", path.to_string().c_str()); + return rv; + } - auto& fs = disk->fs(); - auto vec = fs::new_shared_vector(); - auto err = fs.ls(target, vec); - if (!err) - { - this->write("%s \t%s \t%s \t%s\r\n", - "Name", "Size", "Type", "Sector"); - for (auto& ent : *vec) - { - this->write("%s \t%llu \t%s \t%llu\r\n", - ent.name().c_str(), ent.size, ent.type_string().c_str(), ent.block); - } - this->write("Total %u\r\n", vec->size()); - return 0; - } - else - { - this->write("Could not list %s\r\n", args[0].c_str()); - return 1; - } - }); + std::string target = path.to_string(); + + auto& fs = disk->fs(); + auto vec = fs::new_shared_vector(); + auto err = fs.ls(target, vec); + if (!err) + { + this->write("%s \t%s \t%s \t%s\r\n", + "Name", "Size", "Type", "Sector"); + for (auto& ent : *vec) + { + this->write("%s \t%llu \t%s \t%llu\r\n", + ent.name().c_str(), ent.size, ent.type_string().c_str(), ent.block); + } + this->write("Total %u\r\n", vec->size()); + return 0; + } + else + { + this->write("Could not list %s\r\n", args[0].c_str()); + return 1; + } + }); // add 'stat' command add("stat", "List file information", - [this, disk] (const std::vector& args) -> int - { - if (!args.empty()) - { - auto& fs = disk->fs(); - auto ent = fs.stat(args[0]); - if (ent.is_valid()) - { - this->write("%s \t%s \t%s \t%s\r\n", - "Name", "Size", "Type", "Sector"); - this->write("%s \t%llu \t%s \t%llu\r\n", - ent.name().c_str(), ent.size, ent.type_string().c_str(), ent.block); - return 0; - } - else - { - this->write("stat: Cannot stat '%s'\r\n", args[0].c_str()); - return 1; - } - } - else + [this, disk] (const std::vector& args) -> int { - this->write("%s\r\n", "stat: Not enough arguments"); - return 1; - } - }); + if (!args.empty()) + { + auto& fs = disk->fs(); + auto ent = fs.stat(args[0]); + if (ent.is_valid()) + { + this->write("%s \t%s \t%s \t%s\r\n", + "Name", "Size", "Type", "Sector"); + this->write("%s \t%llu \t%s \t%llu\r\n", + ent.name().c_str(), ent.size, ent.type_string().c_str(), ent.block); + return 0; + } + else + { + this->write("stat: Cannot stat '%s'\r\n", args[0].c_str()); + return 1; + } + } + else + { + this->write("%s\r\n", "stat: Not enough arguments"); + return 1; + } + }); // add 'cat' command add("cat", "Concatenate files and print", - [this, disk] (const std::vector& args) -> int - { - auto& fs = disk->fs(); - - for (const auto& file : args) + [this, disk] (const std::vector& args) -> int { - // get file information - auto ent = fs.stat(file); - if (!ent.is_valid()) - { - this->write("cat: '%s': No such file or directory\r\n", file.c_str()); - return 1; - } - // read file contents - auto buf = fs.read(ent, 0, ent.size); - if (!buf.buffer) - { - this->write("cat: '%s': I/O error\r\n", file.c_str()); - return 1; - } - // write to terminal client - std::string buffer((char*) buf.buffer.get(), buf.len); - this->write("%s\r\n", buffer.c_str()); - } - return 0; - }); + auto& fs = disk->fs(); + + for (const auto& file : args) + { + // get file information + auto ent = fs.stat(file); + if (!ent.is_valid()) + { + this->write("cat: '%s': No such file or directory\r\n", file.c_str()); + return 1; + } + // read file contents + auto buf = fs.read(ent, 0, ent.size); + if (!buf.buffer) + { + this->write("cat: '%s': I/O error\r\n", file.c_str()); + return 1; + } + // write to terminal client + std::string buffer((char*) buf.buffer.get(), buf.len); + this->write("%s\r\n", buffer.c_str()); + } + return 0; + }); } diff --git a/src/kernel/vga.cpp b/src/kernel/vga.cpp index e820fc1328..d48340b320 100644 --- a/src/kernel/vga.cpp +++ b/src/kernel/vga.cpp @@ -25,10 +25,10 @@ static uint16_t make_vgaentry(const char c, const uint8_t color) noexcept { return c16 | color16 << 8; } const uint16_t ConsoleVGA::DEFAULT_ENTRY = - make_vgaentry(32, make_color(COLOR_LIGHT_GREY, COLOR_BLACK)); + make_vgaentry(32, make_color(COLOR_LIGHT_GREY, COLOR_BLACK)); ConsoleVGA::ConsoleVGA() noexcept: - row{0}, column{0} +row{0}, column{0} { this->color = make_color(COLOR_WHITE, COLOR_BLACK); this->buffer = reinterpret_cast(0xB8000); diff --git a/src/net/arp.cpp b/src/net/arp.cpp index 46666b9eb0..ed43f967e2 100644 --- a/src/net/arp.cpp +++ b/src/net/arp.cpp @@ -27,205 +27,205 @@ namespace net { -static void ignore(Packet_ptr UNUSED(pckt)) { - debug2(" linklayer> Empty handler - DROP!\n"); -} + static void ignore(Packet_ptr UNUSED(pckt)) { + debug2(" linklayer> Empty handler - DROP!\n"); + } // Initialize -Arp::Arp(net::Inet& inet) noexcept: + Arp::Arp(net::Inet& inet) noexcept: inet_ {inet}, - mac_ (inet.link_addr()), - linklayer_out_ {ignore} + mac_ (inet.link_addr()), + linklayer_out_ {ignore} {} -void Arp::bottom(Packet_ptr pckt) { - debug2(" got %i bytes of data\n", pckt->size()); + void Arp::bottom(Packet_ptr pckt) { + debug2(" got %i bytes of data\n", pckt->size()); - header* hdr = reinterpret_cast(pckt->buffer()); + header* hdr = reinterpret_cast(pckt->buffer()); - debug2("Have valid cache? %s\n", is_valid_cached(hdr->sipaddr) ? "YES" : "NO"); - cache(hdr->sipaddr, hdr->shwaddr); + debug2("Have valid cache? %s\n", is_valid_cached(hdr->sipaddr) ? "YES" : "NO"); + cache(hdr->sipaddr, hdr->shwaddr); - switch(hdr->opcode) { + switch(hdr->opcode) { - case H_request: { - debug2("\t ARP REQUEST: "); - debug2("%s is looking for %s\n", - hdr->sipaddr.str().c_str(), - hdr->dipaddr.str().c_str()); + case H_request: { + debug2("\t ARP REQUEST: "); + debug2("%s is looking for %s\n", + hdr->sipaddr.str().c_str(), + hdr->dipaddr.str().c_str()); - if (hdr->dipaddr == inet_.ip_addr()) { - arp_respond(hdr); - } else { - debug2("\t NO MATCH for My IP (%s). DROP!\n", - inet_.ip_addr().str().c_str()); + if (hdr->dipaddr == inet_.ip_addr()) { + arp_respond(hdr); + } else { + debug2("\t NO MATCH for My IP (%s). DROP!\n", + inet_.ip_addr().str().c_str()); + } + break; } - break; - } - case H_reply: { - debug2("\t ARP REPLY: %s belongs to %s\n", - hdr->sipaddr.str().c_str(), hdr->shwaddr.str().c_str()); - - auto waiting = waiting_packets_.find(hdr->sipaddr); - - if (waiting != waiting_packets_.end()) { - debug("Had a packet waiting for this IP. Sending\n"); - transmit(waiting->second); - waiting_packets_.erase(waiting); + case H_reply: { + debug2("\t ARP REPLY: %s belongs to %s\n", + hdr->sipaddr.str().c_str(), hdr->shwaddr.str().c_str()); + + auto waiting = waiting_packets_.find(hdr->sipaddr); + + if (waiting != waiting_packets_.end()) { + debug("Had a packet waiting for this IP. Sending\n"); + transmit(waiting->second); + waiting_packets_.erase(waiting); + } + break; } - break; - } - default: - debug2("\t UNKNOWN OPCODE\n"); - break; - } //< switch(hdr->opcode) -} + default: + debug2("\t UNKNOWN OPCODE\n"); + break; + } //< switch(hdr->opcode) + } -void Arp::cache(IP4::addr ip, Ethernet::addr mac) { - debug2("Caching IP %s for %s\n", ip.str().c_str(), mac.str().c_str()); + void Arp::cache(IP4::addr ip, Ethernet::addr mac) { + debug2("Caching IP %s for %s\n", ip.str().c_str(), mac.str().c_str()); - auto entry = cache_.find(ip); + auto entry = cache_.find(ip); - if (entry != cache_.end()) { - debug2("Cached entry found: %s recorded @ %llu. Updating timestamp\n", - entry->second.mac_.str().c_str(), entry->second.timestamp_); + if (entry != cache_.end()) { + debug2("Cached entry found: %s recorded @ %llu. Updating timestamp\n", + entry->second.mac_.str().c_str(), entry->second.timestamp_); - // Update - entry->second.update(); + // Update + entry->second.update(); - } else { - cache_[ip] = mac; // Insert + } else { + cache_[ip] = mac; // Insert + } } -} -bool Arp::is_valid_cached(IP4::addr ip) { - auto entry = cache_.find(ip); + bool Arp::is_valid_cached(IP4::addr ip) { + auto entry = cache_.find(ip); - if (entry != cache_.end()) { - debug("Cached entry, mac: %s time: %llu Expiry: %llu\n", - entry->second.mac_.str().c_str(), - entry->second.timestamp_, entry->second.timestamp_ + cache_exp_t_); - debug("Time now: %llu\n", static_cast(OS::uptime())); - } + if (entry != cache_.end()) { + debug("Cached entry, mac: %s time: %llu Expiry: %llu\n", + entry->second.mac_.str().c_str(), + entry->second.timestamp_, entry->second.timestamp_ + cache_exp_t_); + debug("Time now: %llu\n", static_cast(OS::uptime())); + } - return entry != cache_.end() - and (entry->second.timestamp_ + cache_exp_t_ > static_cast(OS::uptime())); -} + return entry != cache_.end() + and (entry->second.timestamp_ + cache_exp_t_ > static_cast(OS::uptime())); + } -extern "C" { - unsigned long ether_crc(int length, unsigned char *data); -} + extern "C" { + unsigned long ether_crc(int length, unsigned char *data); + } -void Arp::arp_respond(header* hdr_in) { - debug2("\t IP Match. Constructing ARP Reply\n"); + void Arp::arp_respond(header* hdr_in) { + debug2("\t IP Match. Constructing ARP Reply\n"); - // Populate ARP-header - auto res = std::static_pointer_cast(inet_.createPacket(sizeof(header))); - res->init(mac_, inet_.ip_addr()); + // Populate ARP-header + auto res = std::static_pointer_cast(inet_.createPacket(sizeof(header))); + res->init(mac_, inet_.ip_addr()); - res->set_dest_mac(hdr_in->shwaddr); - res->set_dest_ip(hdr_in->sipaddr); - res->set_opcode(H_reply); + res->set_dest_mac(hdr_in->shwaddr); + res->set_dest_ip(hdr_in->sipaddr); + res->set_opcode(H_reply); - debug2("\t My IP: %s belongs to My Mac: %s\n", - res->source_ip().str().c_str(), res->source_mac().str().c_str()); + debug2("\t My IP: %s belongs to My Mac: %s\n", + res->source_ip().str().c_str(), res->source_mac().str().c_str()); - linklayer_out_(res); -} + linklayer_out_(res); + } -void Arp::transmit(Packet_ptr pckt) { - assert(pckt->size()); + void Arp::transmit(Packet_ptr pckt) { + assert(pckt->size()); - /** Get destination IP from IP header */ - IP4::ip_header* iphdr = reinterpret_cast(pckt->buffer() - + sizeof(Ethernet::header)); - IP4::addr sip = iphdr->saddr; - IP4::addr dip = pckt->next_hop(); + /** Get destination IP from IP header */ + IP4::ip_header* iphdr = reinterpret_cast(pckt->buffer() + + sizeof(Ethernet::header)); + IP4::addr sip = iphdr->saddr; + IP4::addr dip = pckt->next_hop(); - debug2(" physical> Transmitting %i bytes to %s\n", - pckt->size(), dip.str().c_str()); + debug2(" physical> Transmitting %i bytes to %s\n", + pckt->size(), dip.str().c_str()); - Ethernet::addr dest_mac; + Ethernet::addr dest_mac; - if (iphdr->daddr == IP4::INADDR_BCAST) { - // When broadcasting our source IP should be either - // our own IP or 0.0.0.0 + if (iphdr->daddr == IP4::INADDR_BCAST) { + // When broadcasting our source IP should be either + // our own IP or 0.0.0.0 - if (sip != inet_.ip_addr() && sip != IP4::INADDR_ANY) { - debug2(" Dropping outbound broadcast packet due to " - "invalid source IP %s\n", sip.str().c_str()); - return; - } - // mui importante - dest_mac = Ethernet::addr::BROADCAST_FRAME; + if (sip != inet_.ip_addr() && sip != IP4::INADDR_ANY) { + debug2(" Dropping outbound broadcast packet due to " + "invalid source IP %s\n", sip.str().c_str()); + return; + } + // mui importante + dest_mac = Ethernet::addr::BROADCAST_FRAME; - } else { - if (sip != inet_.ip_addr()) { - debug2(" physical> Not bound to source IP %s. My IP is %s. DROP!\n", - sip.str().c_str(), inet_.ip_addr().str().c_str()); - return; - } + } else { + if (sip != inet_.ip_addr()) { + debug2(" physical> Not bound to source IP %s. My IP is %s. DROP!\n", + sip.str().c_str(), inet_.ip_addr().str().c_str()); + return; + } - // If we don't have a cached IP, perform address resolution - if (!is_valid_cached(dip)) { + // If we don't have a cached IP, perform address resolution + if (!is_valid_cached(dip)) { arp_resolver_(pckt); return; - } + } - // Get MAC from cache - dest_mac = cache_[dip].mac_; + // Get MAC from cache + dest_mac = cache_[dip].mac_; + } + + /** Attach next-hop mac and ethertype to ethernet header */ + Ethernet::header* ethhdr = reinterpret_cast(pckt->buffer()); + ethhdr->src = mac_; + ethhdr->dest = dest_mac; + ethhdr->type = Ethernet::ETH_IP4; + + debug2(" physical> Sending packet to %s\n", mac_.str().c_str()); + linklayer_out_(pckt); + } + + void Arp::await_resolution(Packet_ptr pckt, IP4::addr) { + auto queue = waiting_packets_.find(pckt->next_hop()); + + if (queue != waiting_packets_.end()) { + debug(" Packets already queueing for this IP\n"); + queue->second->chain(pckt); + } else { + debug(" This is the first packet going to that IP\n"); + waiting_packets_.emplace(std::make_pair(pckt->next_hop(), pckt)); + } } + + void Arp::arp_resolve(Packet_ptr pckt) { + debug(" %s\n", pckt->next_hop().str().c_str()); + + await_resolution(pckt, pckt->next_hop()); + + auto req = view_packet_as(inet_.createPacket(sizeof(header))); + req->init(mac_, inet_.ip_addr()); - /** Attach next-hop mac and ethertype to ethernet header */ - Ethernet::header* ethhdr = reinterpret_cast(pckt->buffer()); - ethhdr->src = mac_; - ethhdr->dest = dest_mac; - ethhdr->type = Ethernet::ETH_IP4; - - debug2(" physical> Sending packet to %s\n", mac_.str().c_str()); - linklayer_out_(pckt); -} - -void Arp::await_resolution(Packet_ptr pckt, IP4::addr) { - auto queue = waiting_packets_.find(pckt->next_hop()); - - if (queue != waiting_packets_.end()) { - debug(" Packets already queueing for this IP\n"); - queue->second->chain(pckt); - } else { - debug(" This is the first packet going to that IP\n"); - waiting_packets_.emplace(std::make_pair(pckt->next_hop(), pckt)); - } -} - -void Arp::arp_resolve(Packet_ptr pckt) { - debug(" %s\n", pckt->next_hop().str().c_str()); - - await_resolution(pckt, pckt->next_hop()); - - auto req = view_packet_as(inet_.createPacket(sizeof(header))); - req->init(mac_, inet_.ip_addr()); - - req->set_dest_mac(Ethernet::addr::BROADCAST_FRAME); - req->set_dest_ip(pckt->next_hop()); - req->set_opcode(H_request); - - linklayer_out_(req); -} - -void Arp::hh_map(Packet_ptr pckt) { - (void) pckt; - debug("ARP-resolution using the HH-hack"); - /** - // Fixed mac prefix - mac.minor = 0x01c0; //Big-endian c001 - // Destination IP - mac.major = dip.whole; - debug("ARP cache missing. Guessing Mac %s from next-hop IP: %s (dest.ip: %s)", - mac.str().c_str(), dip.str().c_str(), iphdr->daddr.str().c_str()); - **/ -} + req->set_dest_mac(Ethernet::addr::BROADCAST_FRAME); + req->set_dest_ip(pckt->next_hop()); + req->set_opcode(H_request); + + linklayer_out_(req); + } + + void Arp::hh_map(Packet_ptr pckt) { + (void) pckt; + debug("ARP-resolution using the HH-hack"); + /** + // Fixed mac prefix + mac.minor = 0x01c0; //Big-endian c001 + // Destination IP + mac.major = dip.whole; + debug("ARP cache missing. Guessing Mac %s from next-hop IP: %s (dest.ip: %s)", + mac.str().c_str(), dip.str().c_str(), iphdr->daddr.str().c_str()); + **/ + } } //< namespace net diff --git a/src/net/buffer_store.cpp b/src/net/buffer_store.cpp index 16000a4fef..8b575538e4 100644 --- a/src/net/buffer_store.cpp +++ b/src/net/buffer_store.cpp @@ -24,16 +24,16 @@ namespace net { -BufferStore::BufferStore(size_t num, size_t bufsize, size_t device_offset ) : - bufcount_ {num}, - bufsize_ {bufsize}, - device_offset_ {device_offset}, - pool_ {static_cast(memalign(PAGE_SIZE, num * bufsize))} + BufferStore::BufferStore(size_t num, size_t bufsize, size_t device_offset ) : + bufcount_ {num}, + bufsize_ {bufsize}, + device_offset_ {device_offset}, + pool_ {static_cast(memalign(PAGE_SIZE, num * bufsize))} { assert(pool_); debug (" Creating buffer store of %i * %i bytes.\n", - num, bufsize); + num, bufsize); for (buffer_t b = pool_; b < pool_ + (num * bufsize); b += bufsize) available_buffers_.push_back(b); @@ -42,62 +42,62 @@ BufferStore::BufferStore(size_t num, size_t bufsize, size_t device_offset ) : available_buffers_.size(), pool_, pool_ + (bufcount_ * bufsize_)); } -BufferStore::~BufferStore() { - free(pool_); -} + BufferStore::~BufferStore() { + free(pool_); + } -/** - * @todo : We (think we) want a list of pools, that we increase as needed. - */ -void BufferStore::increaseStorage() { - panic(" Storage pool full! Don't know how to increase pool size yet.\n"); -} + /** + * @todo : We (think we) want a list of pools, that we increase as needed. + */ + void BufferStore::increaseStorage() { + panic(" Storage pool full! Don't know how to increase pool size yet.\n"); + } -BufferStore::buffer_t BufferStore::get_raw_buffer() { - if (available_buffers_.empty()) - increaseStorage(); + BufferStore::buffer_t BufferStore::get_raw_buffer() { + if (available_buffers_.empty()) + increaseStorage(); - auto buf = available_buffers_.front(); - available_buffers_.pop_front(); + auto buf = available_buffers_.front(); + available_buffers_.pop_front(); - debug2(" Provisioned a buffer. %i buffers remaining.\n", - available_buffers_.size()); - - return buf; -} - -BufferStore::buffer_t BufferStore::get_offset_buffer() { - return get_raw_buffer() + device_offset_; -} - -void BufferStore::release_raw_buffer(buffer_t b, size_t bufsize) { - debug2(" Trying to release %i sized buffer @%p.\n", bufsize, b); - // Make sure the buffer comes from here. Otherwise, ignore it. - if (address_is_from_pool(b) - and address_is_bufstart(b) - and bufsize == bufsize_) - { - available_buffers_.push_back(b); - debug(" Releasing %p. %i available buffers.\n", b, available_buffers_.size()); - return; - } - - debug(" IGNORING buffer @%p. It isn't mine.\n", b); -} - -void BufferStore::release_offset_buffer(buffer_t b, size_t bufsize) { - debug2(" Trying to release %i + %i sized buffer @%p.\n", bufsize, device_offset_, b); - // Make sure the buffer comes from here. Otherwise, ignore it. - if (address_is_from_pool(b) - and address_is_offset_bufstart(b) - and bufsize == bufsize_ - device_offset_) - { - available_buffers_.push_back(b - device_offset_); - debug(" Releasing %p. %i available buffers.\n", b, available_buffers_.size()); - return; - } - - debug(" IGNORING buffer @%p. It isn't mine.\n", b); -} + debug2(" Provisioned a buffer. %i buffers remaining.\n", + available_buffers_.size()); + + return buf; + } + + BufferStore::buffer_t BufferStore::get_offset_buffer() { + return get_raw_buffer() + device_offset_; + } + + void BufferStore::release_raw_buffer(buffer_t b, size_t bufsize) { + debug2(" Trying to release %i sized buffer @%p.\n", bufsize, b); + // Make sure the buffer comes from here. Otherwise, ignore it. + if (address_is_from_pool(b) + and address_is_bufstart(b) + and bufsize == bufsize_) + { + available_buffers_.push_back(b); + debug(" Releasing %p. %i available buffers.\n", b, available_buffers_.size()); + return; + } + + debug(" IGNORING buffer @%p. It isn't mine.\n", b); + } + + void BufferStore::release_offset_buffer(buffer_t b, size_t bufsize) { + debug2(" Trying to release %i + %i sized buffer @%p.\n", bufsize, device_offset_, b); + // Make sure the buffer comes from here. Otherwise, ignore it. + if (address_is_from_pool(b) + and address_is_offset_bufstart(b) + and bufsize == bufsize_ - device_offset_) + { + available_buffers_.push_back(b - device_offset_); + debug(" Releasing %p. %i available buffers.\n", b, available_buffers_.size()); + return; + } + + debug(" IGNORING buffer @%p. It isn't mine.\n", b); + } } //< namespace net diff --git a/src/net/dhcp/dh4client.cpp b/src/net/dhcp/dh4client.cpp index 9e2f8740f0..94d5341fa8 100644 --- a/src/net/dhcp/dh4client.cpp +++ b/src/net/dhcp/dh4client.cpp @@ -220,29 +220,29 @@ namespace net socket.bcast(IP4::INADDR_ANY, DHCP_DEST_PORT, packet, packetlen); socket.onRead( - [this] (Socket& sock, IP4::addr addr, UDP::port_t port, - const char* data, int len) -> int - { - (void) addr; - if (port == DHCP_DEST_PORT) - { - // we have got a DHCP Offer - debug("Received possible DHCP OFFER from %s:%d\n", - addr.str().c_str(), DHCP_DEST_PORT); - this->offer(sock, data, len); - } - return -1; - }); + [this] (Socket& sock, IP4::addr addr, UDP::port_t port, + const char* data, int len) -> int + { + (void) addr; + if (port == DHCP_DEST_PORT) + { + // we have got a DHCP Offer + debug("Received possible DHCP OFFER from %s:%d\n", + addr.str().c_str(), DHCP_DEST_PORT); + this->offer(sock, data, len); + } + return -1; + }); } const dhcp_option_t* get_option(const uint8_t* options, uint8_t code) { const dhcp_option_t* opt = (const dhcp_option_t*) options; while (opt->code != code && opt->code != DHO_END) - { - // go to next option - opt = (const dhcp_option_t*) (((const uint8_t*) opt) + 2 + opt->length); - } + { + // go to next option + opt = (const dhcp_option_t*) (((const uint8_t*) opt) + 2 + opt->length); + } return opt; } @@ -260,68 +260,68 @@ namespace net opt = get_option(dhcp->options, DHO_DHCP_MESSAGE_TYPE); if (opt->code == DHO_DHCP_MESSAGE_TYPE) - { - // verify that the type is indeed DHCPOFFER - debug("Found DHCP message type %d (DHCP Offer = %d)\n", - opt->val[0], DHCPOFFER); + { + // verify that the type is indeed DHCPOFFER + debug("Found DHCP message type %d (DHCP Offer = %d)\n", + opt->val[0], DHCPOFFER); - // ignore when not a DHCP Offer - if (opt->val[0] != DHCPOFFER) return; - } + // ignore when not a DHCP Offer + if (opt->val[0] != DHCPOFFER) return; + } // ignore message when DHCP message type is missing else return; // the offered IP address: this->ipaddr = dhcp->yiaddr; MYINFO("IP ADDRESS: \t%s", - this->ipaddr.str().c_str()); + this->ipaddr.str().c_str()); opt = get_option(dhcp->options, DHO_SUBNET_MASK); if (opt->code == DHO_SUBNET_MASK) - { - memcpy(&this->netmask, opt->val, sizeof(IP4::addr)); - MYINFO("SUBNET MASK: \t%s", - this->netmask.str().c_str()); - } + { + memcpy(&this->netmask, opt->val, sizeof(IP4::addr)); + MYINFO("SUBNET MASK: \t%s", + this->netmask.str().c_str()); + } opt = get_option(dhcp->options, DHO_DHCP_LEASE_TIME); if (opt->code == DHO_DHCP_LEASE_TIME) - { - memcpy(&this->lease_time, opt->val, sizeof(this->lease_time)); - MYINFO("LEASE TIME: \t%u mins", this->lease_time / 60); - } + { + memcpy(&this->lease_time, opt->val, sizeof(this->lease_time)); + MYINFO("LEASE TIME: \t%u mins", this->lease_time / 60); + } // now validate the offer, checking for minimum information opt = get_option(dhcp->options, DHO_ROUTERS); if (opt->code == DHO_ROUTERS) - { - memcpy(&this->router, opt->val, sizeof(IP4::addr)); - MYINFO("GATEWAY: \t%s", - this->router.str().c_str()); - } + { + memcpy(&this->router, opt->val, sizeof(IP4::addr)); + MYINFO("GATEWAY: \t%s", + this->router.str().c_str()); + } // assume that the server we received the request from is the gateway else - { - opt = get_option(dhcp->options, DHO_DHCP_SERVER_IDENTIFIER); - if (opt->code == DHO_DHCP_SERVER_IDENTIFIER) { - memcpy(&this->router, opt->val, sizeof(IP4::addr)); - MYINFO("GATEWAY: \t%s", - this->router.str().c_str()); + opt = get_option(dhcp->options, DHO_DHCP_SERVER_IDENTIFIER); + if (opt->code == DHO_DHCP_SERVER_IDENTIFIER) + { + memcpy(&this->router, opt->val, sizeof(IP4::addr)); + MYINFO("GATEWAY: \t%s", + this->router.str().c_str()); + } + // silently ignore when both ROUTER and SERVER_ID is missing + else return; } - // silently ignore when both ROUTER and SERVER_ID is missing - else return; - } opt = get_option(dhcp->options, DHO_DOMAIN_NAME_SERVERS); if (opt->code == DHO_DOMAIN_NAME_SERVERS) - { - memcpy(&this->dns_server, opt->val, sizeof(IP4::addr)); - } + { + memcpy(&this->dns_server, opt->val, sizeof(IP4::addr)); + } else - { // just try using ROUTER as DNS server - this->dns_server = this->router; - } + { // just try using ROUTER as DNS server + this->dns_server = this->router; + } MYINFO("DNS SERVER: \t%s", this->dns_server.str().c_str()); // we can accept the offer now by requesting the IP! @@ -396,19 +396,19 @@ namespace net // set our onRead function to point to a hopeful DHCP ACK! sock.onRead( - [this] (Socket&, IP4::addr addr, UDP::port_t port, - const char* data, int len) -> int - { - (void) addr; - if (port == DHCP_DEST_PORT) - { - // we have hopefully got a DHCP Ack - debug("\tReceived DHCP ACK from %s:%d\n", - addr.str().c_str(), DHCP_DEST_PORT); - this->acknowledge(data, len); - } - return -1; - }); + [this] (Socket&, IP4::addr addr, UDP::port_t port, + const char* data, int len) -> int + { + (void) addr; + if (port == DHCP_DEST_PORT) + { + // we have hopefully got a DHCP Ack + debug("\tReceived DHCP ACK from %s:%d\n", + addr.str().c_str(), DHCP_DEST_PORT); + this->acknowledge(data, len); + } + return -1; + }); // send our DHCP Request sock.bcast(IP4::INADDR_ANY, DHCP_DEST_PORT, packet, packetlen); @@ -428,14 +428,14 @@ namespace net opt = get_option(dhcp->options, DHO_DHCP_MESSAGE_TYPE); if (opt->code == DHO_DHCP_MESSAGE_TYPE) - { - // verify that the type is indeed DHCPOFFER - debug("\tFound DHCP message type %d (DHCP Ack = %d)\n", - opt->val[0], DHCPACK); + { + // verify that the type is indeed DHCPOFFER + debug("\tFound DHCP message type %d (DHCP Ack = %d)\n", + opt->val[0], DHCPACK); - // ignore when not a DHCP Offer - if (opt->val[0] != DHCPACK) return; - } + // ignore when not a DHCP Offer + if (opt->val[0] != DHCPACK) return; + } // ignore message when DHCP message type is missing else return; diff --git a/src/net/dns/client.cpp b/src/net/dns/client.cpp index 3b8fffa4fb..d17d9d570b 100644 --- a/src/net/dns/client.cpp +++ b/src/net/dns/client.cpp @@ -39,14 +39,14 @@ namespace net // wait for response // FIXME: WE DO NOT CHECK TRANSACTION IDS HERE (yet), GOD HELP US ALL sock.onRead( [this, hostname, request, func] - (Socket&, IP4::addr, UDP::port_t, const char* data, int) mutable -> int - { - // original request ID = this->id; - request.parseResponse(data); + (Socket&, IP4::addr, UDP::port_t, const char* data, int) mutable -> int + { + // original request ID = this->id; + request.parseResponse(data); - // fire onResolve event - func(this->stack, hostname, request.getFirstIP4()); - return -1; - }); + // fire onResolve event + func(this->stack, hostname, request.getFirstIP4()); + return -1; + }); } } diff --git a/src/net/dns/dns.cpp b/src/net/dns/dns.cpp index a1e6a39537..56f28e6c0d 100644 --- a/src/net/dns/dns.cpp +++ b/src/net/dns/dns.cpp @@ -32,12 +32,12 @@ namespace net std::string resp; while (*(tmp)!=0) - { - int len = *tmp++; - resp.append((char*) tmp, len); - resp.append("."); - tmp += len; - } + { + int len = *tmp++; + resp.append((char*) tmp, len); + resp.append("."); + tmp += len; + } return resp; } @@ -79,7 +79,7 @@ namespace net // initial response size unsigned short packetlen = sizeof(header) + - sizeof(question) + parsed_query.size() + 1; + sizeof(question) + parsed_query.size() + 1; // set DNS QR to RESPONSE hdr.qr = DNS_QR_RESPONSE; @@ -91,45 +91,45 @@ namespace net std::vector* addrs = lookup(parsed_query); if (addrs == nullptr) - { - // not found - debug("*** Could not find: %s", parsed_query.c_str()); - hdr.ans_count = 0; - hdr.rcode = DNS::NO_ERROR; - } + { + // not found + debug("*** Could not find: %s", parsed_query.c_str()); + hdr.ans_count = 0; + hdr.rcode = DNS::NO_ERROR; + } else - { - debug("*** Found %lu results for %s", addrs->size(), parsed_query.c_str()); - // append answers - for (auto addr : *addrs) { - debug("*** Result: %s", addr.str().c_str()); - // add query - int qlen = parsed_query.size() + 1; - memcpy(buffer, query, qlen); - buffer += qlen; - packetlen += qlen; // (!) + debug("*** Found %lu results for %s", addrs->size(), parsed_query.c_str()); + // append answers + for (auto addr : *addrs) + { + debug("*** Result: %s", addr.str().c_str()); + // add query + int qlen = parsed_query.size() + 1; + memcpy(buffer, query, qlen); + buffer += qlen; + packetlen += qlen; // (!) - // add resource record - rr_data* data = (rr_data*) buffer; + // add resource record + rr_data* data = (rr_data*) buffer; - data->type = htons(DNS_TYPE_A); - data->_class = htons(DNS_CLASS_INET); - data->ttl = htons(0x7FFF); // just because - data->data_len = htons(sizeof(IP4::addr)); - buffer += sizeof(rr_data); + data->type = htons(DNS_TYPE_A); + data->_class = htons(DNS_CLASS_INET); + data->ttl = htons(0x7FFF); // just because + data->data_len = htons(sizeof(IP4::addr)); + buffer += sizeof(rr_data); - // add resource itself - *((IP4::addr*) buffer) = addr; // IPv4 address - buffer += sizeof(IP4::addr); + // add resource itself + *((IP4::addr*) buffer) = addr; // IPv4 address + buffer += sizeof(IP4::addr); - packetlen += sizeof(rr_data) + sizeof(IP4::addr); // (!) - } // addr + packetlen += sizeof(rr_data) + sizeof(IP4::addr); // (!) + } // addr - // set dns header answer count (!) - hdr.ans_count = htons((addrs->size() & 0xFFFF)); - hdr.rcode = DNS::NO_ERROR; - } + // set dns header answer count (!) + hdr.ans_count = htons((addrs->size() & 0xFFFF)); + hdr.rcode = DNS::NO_ERROR; + } return packetlen; } @@ -160,7 +160,7 @@ namespace net dns->auth_count = 0; dns->add_count = 0; - // point to the query portion + // point to the query portion char* qname = buffer + sizeof(DNS::header); // convert host to dns name format @@ -197,7 +197,7 @@ namespace net for (int i = 0; i < ntohs(dns->auth_count); i++) auth.emplace_back(reader, buffer); - // parse additional + // parse additional for (int i = 0; i < ntohs(dns->add_count); i++) addit.emplace_back(reader, buffer); @@ -231,24 +231,24 @@ namespace net // convert www.google.com to 3www6google3com void DNS::Request::dnsNameFormat(char* dns) { - int lock = 0; + int lock = 0; - std::string copy = this->hostname + "."; - int len = copy.size(); + std::string copy = this->hostname + "."; + int len = copy.size(); - for(int i = 0; i < len; i++) + for(int i = 0; i < len; i++) { - if (copy[i] == '.') + if (copy[i] == '.') { - *dns++ = i - lock; - for(; lock < i; lock++) + *dns++ = i - lock; + for(; lock < i; lock++) { - *dns++ = copy[lock]; + *dns++ = copy[lock]; } - lock++; + lock++; } } - *dns++ = '\0'; + *dns++ = '\0'; } DNS::Request::rr_t::rr_t(const char*& reader, const char* buffer) @@ -263,54 +263,54 @@ namespace net // if its an ipv4 address if (ntohs(resource.type) == DNS_TYPE_A) - { - int len = ntohs(resource.data_len); + { + int len = ntohs(resource.data_len); - this->rdata = std::string(reader, len); - reader += len; - } + this->rdata = std::string(reader, len); + reader += len; + } else - { - this->rdata = readName(reader, buffer, stop); - reader += stop; - } + { + this->rdata = readName(reader, buffer, stop); + reader += stop; + } } IP4::addr DNS::Request::rr_t::getIP4() const { switch (ntohs(resource.type)) - { - case DNS_TYPE_A: - { - IP4::addr* addr = (IP4::addr*) rdata.c_str(); - return *addr; - } - case DNS_TYPE_ALIAS: - case DNS_TYPE_NS: - default: - return IP4::addr{{0}}; - } + { + case DNS_TYPE_A: + { + IP4::addr* addr = (IP4::addr*) rdata.c_str(); + return *addr; + } + case DNS_TYPE_ALIAS: + case DNS_TYPE_NS: + default: + return IP4::addr{{0}}; + } } void DNS::Request::rr_t::print() { printf("Name: %s ", name.c_str()); switch (ntohs(resource.type)) - { - case DNS_TYPE_A: { - IP4::addr* addr = (IP4::addr*) rdata.c_str(); - printf("has IPv4 address: %s", addr->str().c_str()); + case DNS_TYPE_A: + { + IP4::addr* addr = (IP4::addr*) rdata.c_str(); + printf("has IPv4 address: %s", addr->str().c_str()); + } + break; + case DNS_TYPE_ALIAS: + printf("has alias: %s", rdata.c_str()); + break; + case DNS_TYPE_NS: + printf("has authoritative nameserver : %s", rdata.c_str()); + break; + default: + printf("has unknown resource type: %d", ntohs(resource.type)); } - break; - case DNS_TYPE_ALIAS: - printf("has alias: %s", rdata.c_str()); - break; - case DNS_TYPE_NS: - printf("has authoritative nameserver : %s", rdata.c_str()); - break; - default: - printf("has unknown resource type: %d", ntohs(resource.type)); - } printf("\n"); } @@ -325,22 +325,22 @@ namespace net unsigned char* ureader = (unsigned char*) reader; while (*ureader) - { - if (*ureader >= 192) - { - offset = (*ureader) * 256 + *(ureader+1) - 49152; // = 11000000 00000000 - ureader = (unsigned char*) buffer + offset - 1; - jumped = true; // we have jumped to another location so counting wont go up! - } - else { - name[p++] = *ureader; - } - ureader++; + if (*ureader >= 192) + { + offset = (*ureader) * 256 + *(ureader+1) - 49152; // = 11000000 00000000 + ureader = (unsigned char*) buffer + offset - 1; + jumped = true; // we have jumped to another location so counting wont go up! + } + else + { + name[p++] = *ureader; + } + ureader++; - // if we havent jumped to another location then we can count up - if (jumped == false) count++; - } + // if we havent jumped to another location then we can count up + if (jumped == false) count++; + } name.resize(p); // number of steps we actually moved forward in the packet @@ -351,16 +351,16 @@ namespace net int len = p; // same as name.size() int i; for(i = 0; i < len; i++) - { - p = name[i]; - - for(unsigned j = 0; j < p; j++) { - name[i] = name[i+1]; - i++; + p = name[i]; + + for(unsigned j = 0; j < p; j++) + { + name[i] = name[i+1]; + i++; + } + name[i] = '.'; } - name[i] = '.'; - } name[i - 1] = '\0'; // remove the last dot return name; diff --git a/src/net/ethernet.cpp b/src/net/ethernet.cpp index 42dc4aaf28..75af7441e2 100644 --- a/src/net/ethernet.cpp +++ b/src/net/ethernet.cpp @@ -26,90 +26,90 @@ namespace net { -// uint16_t(0x0000), uint32_t(0x01000000) -const Ethernet::addr Ethernet::addr::MULTICAST_FRAME {{0,0,0x01,0,0,0}}; + // uint16_t(0x0000), uint32_t(0x01000000) + const Ethernet::addr Ethernet::addr::MULTICAST_FRAME {{0,0,0x01,0,0,0}}; -// uint16_t(0xFFFF), uint32_t(0xFFFFFFFF) -const Ethernet::addr Ethernet::addr::BROADCAST_FRAME {{0xff,0xff,0xff,0xff,0xff,0xff}}; + // uint16_t(0xFFFF), uint32_t(0xFFFFFFFF) + const Ethernet::addr Ethernet::addr::BROADCAST_FRAME {{0xff,0xff,0xff,0xff,0xff,0xff}}; -// uint16_t(0x3333), uint32_t(0x01000000) -const Ethernet::addr Ethernet::addr::IPv6mcast_01 {{0x33,0x33,0x01,0,0,0}}; + // uint16_t(0x3333), uint32_t(0x01000000) + const Ethernet::addr Ethernet::addr::IPv6mcast_01 {{0x33,0x33,0x01,0,0,0}}; -// uint16_t(0x3333), uint32_t(0x02000000) -const Ethernet::addr Ethernet::addr::IPv6mcast_02 {{0x33,0x33,0x02,0,0,0}}; + // uint16_t(0x3333), uint32_t(0x02000000) + const Ethernet::addr Ethernet::addr::IPv6mcast_02 {{0x33,0x33,0x02,0,0,0}}; -static void ignore(Packet_ptr UNUSED(pckt)) noexcept { - debug(" Ignoring data (no real handler)\n"); -} + static void ignore(Packet_ptr UNUSED(pckt)) noexcept { + debug(" Ignoring data (no real handler)\n"); + } -Ethernet::Ethernet(addr mac) noexcept + Ethernet::Ethernet(addr mac) noexcept : mac_(mac), ip4_handler_{ignore}, ip6_handler_{ignore}, arp_handler_{ignore} {} -void Ethernet::transmit(Packet_ptr pckt) { - header* hdr = reinterpret_cast(pckt->buffer()); - - // Verify ethernet header - assert(hdr->dest.major != 0 || hdr->dest.minor !=0); - assert(hdr->type != 0); - - // Add source address - hdr->src = mac_; - - debug2(" Transmitting %i b, from %s -> %s. Type: %i\n", - pckt->size(), mac_.str().c_str(), hdr->dest.str().c_str(), hdr->type); - - physical_out_(pckt); -} + void Ethernet::transmit(Packet_ptr pckt) { + header* hdr = reinterpret_cast(pckt->buffer()); -void Ethernet::bottom(Packet_ptr pckt) { - assert(pckt->size() > 0); + // Verify ethernet header + assert(hdr->dest.major != 0 || hdr->dest.minor !=0); + assert(hdr->type != 0); - header* eth = reinterpret_cast(pckt->buffer()); + // Add source address + hdr->src = mac_; - /** Do we pass on ethernet headers? As for now, yes. - data += sizeof(header); - len -= sizeof(header); - */ - debug2(" %s => %s , Eth.type: 0x%x ", - eth->src.str().c_str(), eth->dest.str().c_str(), eth->type); + debug2(" Transmitting %i b, from %s -> %s. Type: %i\n", + pckt->size(), mac_.str().c_str(), hdr->dest.str().c_str(), hdr->type); - switch(eth->type) { - case ETH_IP4: - debug2("IPv4 packet\n"); - ip4_handler_(pckt); - break; - - case ETH_IP6: - debug2("IPv6 packet\n"); - ip6_handler_(pckt); - break; - - case ETH_ARP: - debug2("ARP packet\n"); - arp_handler_(pckt); - break; - - case ETH_WOL: - debug2("Wake-on-LAN packet\n"); - break; - - case ETH_VLAN: - debug("VLAN tagged frame (not yet supported)"); - break; + physical_out_(pckt); + } - default: - // This might be 802.3 LLC traffic - if (net::ntohs(eth->type) > 1500) { - debug(" UNKNOWN ethertype 0x%x\n", ntohs(eth->type)); - }else { - debug2("IEEE802.3 Length field: 0x%x\n", ntohs(eth->type)); + void Ethernet::bottom(Packet_ptr pckt) { + assert(pckt->size() > 0); + + header* eth = reinterpret_cast(pckt->buffer()); + + /** Do we pass on ethernet headers? As for now, yes. + data += sizeof(header); + len -= sizeof(header); + */ + debug2(" %s => %s , Eth.type: 0x%x ", + eth->src.str().c_str(), eth->dest.str().c_str(), eth->type); + + switch(eth->type) { + case ETH_IP4: + debug2("IPv4 packet\n"); + ip4_handler_(pckt); + break; + + case ETH_IP6: + debug2("IPv6 packet\n"); + ip6_handler_(pckt); + break; + + case ETH_ARP: + debug2("ARP packet\n"); + arp_handler_(pckt); + break; + + case ETH_WOL: + debug2("Wake-on-LAN packet\n"); + break; + + case ETH_VLAN: + debug("VLAN tagged frame (not yet supported)"); + break; + + default: + // This might be 802.3 LLC traffic + if (net::ntohs(eth->type) > 1500) { + debug(" UNKNOWN ethertype 0x%x\n", ntohs(eth->type)); + }else { + debug2("IEEE802.3 Length field: 0x%x\n", ntohs(eth->type)); + } + break; } - break; } -} } // namespace net diff --git a/src/net/inet.cpp b/src/net/inet.cpp index a22428e9e3..760c9a2931 100644 --- a/src/net/inet.cpp +++ b/src/net/inet.cpp @@ -22,10 +22,10 @@ namespace net { Inet::Inet() : - //_eth(eth0.mac()),_arp(eth0.mac(),ip) - _ip4(_ip4_list[0],_netmask_list[0]), _udp(_ip4_list[0]), - _ip6(_ip6_list[0]), - _icmp6(_ip6_list[0]), _udp6(_ip6_list[0]) + //_eth(eth0.mac()),_arp(eth0.mac(),ip) + _ip4(_ip4_list[0],_netmask_list[0]), _udp(_ip4_list[0]), + _ip6(_ip6_list[0]), + _icmp6(_ip6_list[0]), _udp6(_ip6_list[0]) { // For now we're just using the one interface auto& eth0 = Dev::eth<0,VirtioNet>(); diff --git a/src/net/inet_common.cpp b/src/net/inet_common.cpp index e5b135f7d5..e96efc4a44 100644 --- a/src/net/inet_common.cpp +++ b/src/net/inet_common.cpp @@ -23,27 +23,27 @@ namespace net { -// Should be pretty much like the example in RFC 1071, -// but using a uinon for readability -uint16_t checksum(void* data, size_t len) noexcept { + // Should be pretty much like the example in RFC 1071, + // but using a uinon for readability + uint16_t checksum(void* data, size_t len) noexcept { - uint16_t* buf = reinterpret_cast(data); + uint16_t* buf = reinterpret_cast(data); - union sum { - uint32_t whole; - uint16_t part[2]; - } sum32 {0}; + union sum { + uint32_t whole; + uint16_t part[2]; + } sum32 {0}; - // Iterate in short int steps. - for (uint16_t* i = buf; i < (buf + len / 2); ++i) - sum32.whole += *i; + // Iterate in short int steps. + for (uint16_t* i = buf; i < (buf + len / 2); ++i) + sum32.whole += *i; - // odd-length case - if (len & 1) { - sum32.whole += reinterpret_cast(buf)[len - 1]; - } + // odd-length case + if (len & 1) { + sum32.whole += reinterpret_cast(buf)[len - 1]; + } - return ~(sum32.part[0] + sum32.part[1]); -} + return ~(sum32.part[0] + sum32.part[1]); + } } //< namespace net diff --git a/src/net/ip4.cpp b/src/net/ip4.cpp index 537e8da023..ad962b5ba0 100644 --- a/src/net/ip4.cpp +++ b/src/net/ip4.cpp @@ -24,10 +24,10 @@ namespace net { -const IP4::addr IP4::INADDR_ANY {{0,0,0,0}}; -const IP4::addr IP4::INADDR_BCAST {{0xff,0xff,0xff,0xff}}; + const IP4::addr IP4::INADDR_ANY {{0,0,0,0}}; + const IP4::addr IP4::INADDR_BCAST {{0xff,0xff,0xff,0xff}}; -IP4::IP4(Inet& inet) noexcept: + IP4::IP4(Inet& inet) noexcept: stack_{inet} { // Default gateway is addr 1 in the subnet. @@ -35,79 +35,79 @@ IP4::IP4(Inet& inet) noexcept: // gateway_.whole = (local_ip_.whole & netmask_.whole) | DEFAULT_GATEWAY; } -void IP4::bottom(Packet_ptr pckt) { - debug2(" got the data.\n"); + void IP4::bottom(Packet_ptr pckt) { + debug2(" got the data.\n"); - auto data = pckt->buffer(); - ip_header* hdr = &reinterpret_cast(data)->ip_hdr; + auto data = pckt->buffer(); + ip_header* hdr = &reinterpret_cast(data)->ip_hdr; - debug2("\t Source IP: %s Dest.IP: %s\n", - hdr->saddr.str().c_str(), hdr->daddr.str().c_str()); + debug2("\t Source IP: %s Dest.IP: %s\n", + hdr->saddr.str().c_str(), hdr->daddr.str().c_str()); - switch(hdr->protocol){ - case IP4_ICMP: - debug2("\t Type: ICMP\n"); - icmp_handler_(pckt); - break; - case IP4_UDP: - debug2("\t Type: UDP\n"); - udp_handler_(pckt); - break; - case IP4_TCP: - tcp_handler_(pckt); - debug2("\t Type: TCP\n"); - break; - default: - debug("\t Type: UNKNOWN %i\n", hdr->protocol); - break; + switch(hdr->protocol){ + case IP4_ICMP: + debug2("\t Type: ICMP\n"); + icmp_handler_(pckt); + break; + case IP4_UDP: + debug2("\t Type: UDP\n"); + udp_handler_(pckt); + break; + case IP4_TCP: + tcp_handler_(pckt); + debug2("\t Type: TCP\n"); + break; + default: + debug("\t Type: UNKNOWN %i\n", hdr->protocol); + break; + } } -} -uint16_t IP4::checksum(ip_header* hdr) { - return net::checksum(reinterpret_cast(hdr), sizeof(ip_header)); -} + uint16_t IP4::checksum(ip_header* hdr) { + return net::checksum(reinterpret_cast(hdr), sizeof(ip_header)); + } -void IP4::transmit(Packet_ptr pckt) { - assert(pckt->size() > sizeof(IP4::full_header)); + void IP4::transmit(Packet_ptr pckt) { + assert(pckt->size() > sizeof(IP4::full_header)); - full_header* full_hdr = reinterpret_cast(pckt->buffer()); - ip_header* hdr = &full_hdr->ip_hdr; + full_header* full_hdr = reinterpret_cast(pckt->buffer()); + ip_header* hdr = &full_hdr->ip_hdr; - auto ip4_pckt = std::static_pointer_cast(pckt); - ip4_pckt->make_flight_ready(); + auto ip4_pckt = std::static_pointer_cast(pckt); + ip4_pckt->make_flight_ready(); - // Create local and target subnets - addr target, local; - target.whole = hdr->daddr.whole & stack_.netmask().whole; - local.whole = stack_.ip_addr().whole & stack_.netmask().whole; + // Create local and target subnets + addr target, local; + target.whole = hdr->daddr.whole & stack_.netmask().whole; + local.whole = stack_.ip_addr().whole & stack_.netmask().whole; - // Compare subnets to know where to send packet - pckt->next_hop(target == local ? hdr->daddr : stack_.router()); + // Compare subnets to know where to send packet + pckt->next_hop(target == local ? hdr->daddr : stack_.router()); - debug(" Next hop for %s, (netmask %s, local IP: %s, gateway: %s) == %s\n", - hdr->daddr.str().c_str(), - stack_.netmask().str().c_str(), - stack_.ip_addr().str().c_str(), - stack_.router().str().c_str(), - target == local ? "DIRECT" : "GATEWAY"); + debug(" Next hop for %s, (netmask %s, local IP: %s, gateway: %s) == %s\n", + hdr->daddr.str().c_str(), + stack_.netmask().str().c_str(), + stack_.ip_addr().str().c_str(), + stack_.router().str().c_str(), + target == local ? "DIRECT" : "GATEWAY"); - debug(" my ip: %s, Next hop: %s, Packet size: %i IP4-size: %i\n", - stack_.ip_addr().str().c_str(), - pckt->next_hop().str().c_str(), - pckt->size(), - ip4_pckt->ip4_segment_size() - ); + debug(" my ip: %s, Next hop: %s, Packet size: %i IP4-size: %i\n", + stack_.ip_addr().str().c_str(), + pckt->next_hop().str().c_str(), + pckt->size(), + ip4_pckt->ip4_segment_size() + ); - linklayer_out_(pckt); -} + linklayer_out_(pckt); + } -// Empty handler for delegates initialization -void ignore_ip4_up(Packet_ptr UNUSED(pckt)) { - debug(" Empty handler. Ignoring.\n"); -} + // Empty handler for delegates initialization + void ignore_ip4_up(Packet_ptr UNUSED(pckt)) { + debug(" Empty handler. Ignoring.\n"); + } -void ignore_ip4_down(Packet_ptr UNUSED(pckt)) { - debug("Link layer> No handler - DROP!\n"); -} + void ignore_ip4_down(Packet_ptr UNUSED(pckt)) { + debug("Link layer> No handler - DROP!\n"); + } } //< namespace net diff --git a/src/net/ip4/icmpv4.cpp b/src/net/ip4/icmpv4.cpp index 5a7b4a113f..3f9e897135 100644 --- a/src/net/ip4/icmpv4.cpp +++ b/src/net/ip4/icmpv4.cpp @@ -24,68 +24,68 @@ namespace net { -ICMPv4::ICMPv4(Inet& inet) : - inet_{inet} + ICMPv4::ICMPv4(Inet& inet) : + inet_{inet} {} -void ICMPv4::bottom(Packet_ptr pckt) { - if (pckt->size() < sizeof(full_header)) // Drop if not a full header - return; + void ICMPv4::bottom(Packet_ptr pckt) { + if (pckt->size() < sizeof(full_header)) // Drop if not a full header + return; - full_header* full_hdr = reinterpret_cast(pckt->buffer()); - icmp_header* hdr = &full_hdr->icmp_hdr; + full_header* full_hdr = reinterpret_cast(pckt->buffer()); + icmp_header* hdr = &full_hdr->icmp_hdr; #ifdef DEBUG - auto ip_address = full_hdr->ip_hdr.saddr.str().c_str(); + auto ip_address = full_hdr->ip_hdr.saddr.str().c_str(); #endif - switch(hdr->type) { - case (ICMP_ECHO): - debug(" PING from %s\n", ip_address); - ping_reply(full_hdr, pckt->size()); - break; - case (ICMP_ECHO_REPLY): - debug(" PING Reply from %s\n", ip_address); - break; + switch(hdr->type) { + case (ICMP_ECHO): + debug(" PING from %s\n", ip_address); + ping_reply(full_hdr, pckt->size()); + break; + case (ICMP_ECHO_REPLY): + debug(" PING Reply from %s\n", ip_address); + break; + } } -} -void ICMPv4::ping_reply(full_header* full_hdr, uint16_t size) { - auto packet_ptr = inet_.createPacket(size); - auto buf = packet_ptr->buffer(); + void ICMPv4::ping_reply(full_header* full_hdr, uint16_t size) { + auto packet_ptr = inet_.createPacket(size); + auto buf = packet_ptr->buffer(); - icmp_header* hdr = &reinterpret_cast(buf)->icmp_hdr; - hdr->type = ICMP_ECHO_REPLY; - hdr->code = 0; - hdr->identifier = full_hdr->icmp_hdr.identifier; - hdr->sequence = full_hdr->icmp_hdr.sequence; + icmp_header* hdr = &reinterpret_cast(buf)->icmp_hdr; + hdr->type = ICMP_ECHO_REPLY; + hdr->code = 0; + hdr->identifier = full_hdr->icmp_hdr.identifier; + hdr->sequence = full_hdr->icmp_hdr.sequence; - debug(" Rest of header IN: 0x%lx OUT: 0x%lx\n", - full_hdr->icmp_hdr.rest, hdr->rest); + debug(" Rest of header IN: 0x%lx OUT: 0x%lx\n", + full_hdr->icmp_hdr.rest, hdr->rest); - debug(" Transmitting answer\n"); + debug(" Transmitting answer\n"); - // Populate response IP header - auto ip4_pckt = std::static_pointer_cast(packet_ptr); - ip4_pckt->init(); - ip4_pckt->set_src(full_hdr->ip_hdr.daddr); - ip4_pckt->set_dst(full_hdr->ip_hdr.saddr); - ip4_pckt->set_protocol(IP4::IP4_ICMP); + // Populate response IP header + auto ip4_pckt = std::static_pointer_cast(packet_ptr); + ip4_pckt->init(); + ip4_pckt->set_src(full_hdr->ip_hdr.daddr); + ip4_pckt->set_dst(full_hdr->ip_hdr.saddr); + ip4_pckt->set_protocol(IP4::IP4_ICMP); - // Copy payload from old to new packet - uint8_t* payload = reinterpret_cast(hdr) + sizeof(icmp_header); - uint8_t* source = reinterpret_cast(&full_hdr->icmp_hdr) + sizeof(icmp_header); - memcpy(payload, source, size - sizeof(full_header)); + // Copy payload from old to new packet + uint8_t* payload = reinterpret_cast(hdr) + sizeof(icmp_header); + uint8_t* source = reinterpret_cast(&full_hdr->icmp_hdr) + sizeof(icmp_header); + memcpy(payload, source, size - sizeof(full_header)); - hdr->checksum = 0; - hdr->checksum = net::checksum(reinterpret_cast(hdr), - size - sizeof(full_header) + sizeof(icmp_header)); + hdr->checksum = 0; + hdr->checksum = net::checksum(reinterpret_cast(hdr), + size - sizeof(full_header) + sizeof(icmp_header)); - network_layer_out_(packet_ptr); -} + network_layer_out_(packet_ptr); + } -void icmp_default_out(Packet_ptr UNUSED(pckt)) { - debug(" No handler. DROP!\n"); -} + void icmp_default_out(Packet_ptr UNUSED(pckt)) { + debug(" No handler. DROP!\n"); + } } //< namespace net diff --git a/src/net/ip4/udp.cpp b/src/net/ip4/udp.cpp index 7ef9208f86..9517873299 100644 --- a/src/net/ip4/udp.cpp +++ b/src/net/ip4/udp.cpp @@ -23,70 +23,70 @@ namespace net { -void UDP::bottom(Packet_ptr pckt) -{ - debug(" Got data"); - std::shared_ptr udp = + void UDP::bottom(Packet_ptr pckt) + { + debug(" Got data"); + std::shared_ptr udp = std::static_pointer_cast (pckt); - debug("\t Source port: %i, Dest. Port: %i Length: %i\n", - udp->src_port(), udp->dst_port(), udp->length()); + debug("\t Source port: %i, Dest. Port: %i Length: %i\n", + udp->src_port(), udp->dst_port(), udp->length()); - auto it = ports_.find(udp->dst_port()); - if (it != ports_.end()) - { - debug(" Someone's listening to this port. Forwarding...\n"); - it->second.internal_read(udp); - } + auto it = ports_.find(udp->dst_port()); + if (it != ports_.end()) + { + debug(" Someone's listening to this port. Forwarding...\n"); + it->second.internal_read(udp); + } - debug(" Nobody's listening to this port. Drop!\n"); -} + debug(" Nobody's listening to this port. Drop!\n"); + } -UDP::Socket& UDP::bind(UDP::port_t port) -{ - debug(" Binding to port %i\n", port); - /// ... !!! - auto it = ports_.find(port); - if (it == ports_.end()) { - // create new socket - auto res = ports_.emplace( - std::piecewise_construct, - std::forward_as_tuple(port), - std::forward_as_tuple(stack_, port)); - it = res.first; + UDP::Socket& UDP::bind(UDP::port_t port) + { + debug(" Binding to port %i\n", port); + /// ... !!! + auto it = ports_.find(port); + if (it == ports_.end()) { + // create new socket + auto res = ports_.emplace( + std::piecewise_construct, + std::forward_as_tuple(port), + std::forward_as_tuple(stack_, port)); + it = res.first; + } + return it->second; } - return it->second; -} -UDP::Socket& UDP::bind() { + UDP::Socket& UDP::bind() { - if (ports_.size() >= 0xfc00) - panic("UPD Socket: All ports taken!"); + if (ports_.size() >= 0xfc00) + panic("UPD Socket: All ports taken!"); - debug("UDP finding free ephemeral port\n"); - while (ports_.find(++current_port_) != ports_.end()) - if (current_port_ == 0) current_port_ = 1025; // prevent automatic ports under 1024 + debug("UDP finding free ephemeral port\n"); + while (ports_.find(++current_port_) != ports_.end()) + if (current_port_ == 0) current_port_ = 1025; // prevent automatic ports under 1024 - debug("UDP binding to %i port\n", current_port_); - return bind(current_port_); -} + debug("UDP binding to %i port\n", current_port_); + return bind(current_port_); + } -void UDP::transmit(std::shared_ptr udp) { - debug2(" Transmitting %i bytes (seg=%i) from %s to %s:%i\n", - udp->length(), udp->ip4_segment_size(), - udp->src().str().c_str(), - udp->dst().str().c_str(), udp->dst_port()); + void UDP::transmit(std::shared_ptr udp) { + debug2(" Transmitting %i bytes (seg=%i) from %s to %s:%i\n", + udp->length(), udp->ip4_segment_size(), + udp->src().str().c_str(), + udp->dst().str().c_str(), udp->dst_port()); - assert(udp->length() >= sizeof(UDP::udp_header)); - assert(udp->protocol() == IP4::IP4_UDP); + assert(udp->length() >= sizeof(UDP::udp_header)); + assert(udp->protocol() == IP4::IP4_UDP); - Packet_ptr pckt = Packet::packet(udp); - network_layer_out_(pckt); -} + Packet_ptr pckt = Packet::packet(udp); + network_layer_out_(pckt); + } -void ignore_udp(Packet_ptr) -{ - debug("Network> No handler - DROP!\n"); -} + void ignore_udp(Packet_ptr) + { + debug("Network> No handler - DROP!\n"); + } } //< namespace net diff --git a/src/net/ip4/udp_socket.cpp b/src/net/ip4/udp_socket.cpp index 46ebfbc8fd..a5eea02023 100644 --- a/src/net/ip4/udp_socket.cpp +++ b/src/net/ip4/udp_socket.cpp @@ -29,7 +29,7 @@ namespace net } void Socket::packet_init(std::shared_ptr p, - addr srcIP, addr destIP, port port, uint16_t length) + addr srcIP, addr destIP, port port, uint16_t length) { p->init(); p->header().sport = htons(this->l_port); @@ -42,7 +42,7 @@ namespace net } int Socket::internal_write(addr srcIP, addr destIP, - port port, const uint8_t* buffer, int length) + port port, const uint8_t* buffer, int length) { // the maximum we can write per packet: const int WRITE_MAX = stack.MTU() - PacketUDP::HEADERS_SIZE; @@ -50,47 +50,47 @@ namespace net int rem = length; while (rem >= WRITE_MAX) - { - // create some packet p (and convert it to PacketUDP) - auto p = stack.createPacket(stack.MTU()); - // fill buffer (at payload position) - memcpy(p->buffer() + PacketUDP::HEADERS_SIZE, buffer, WRITE_MAX); + { + // create some packet p (and convert it to PacketUDP) + auto p = stack.createPacket(stack.MTU()); + // fill buffer (at payload position) + memcpy(p->buffer() + PacketUDP::HEADERS_SIZE, buffer, WRITE_MAX); - // initialize packet with several infos - auto p2 = std::static_pointer_cast(p); - packet_init(p2, srcIP, destIP, port, WRITE_MAX); - // ship the packet - stack.udp().transmit(p2); + // initialize packet with several infos + auto p2 = std::static_pointer_cast(p); + packet_init(p2, srcIP, destIP, port, WRITE_MAX); + // ship the packet + stack.udp().transmit(p2); - // next buffer part - buffer += WRITE_MAX; rem -= WRITE_MAX; - } + // next buffer part + buffer += WRITE_MAX; rem -= WRITE_MAX; + } if (rem) - { - // copy remainder - size_t size = PacketUDP::HEADERS_SIZE + rem; + { + // copy remainder + size_t size = PacketUDP::HEADERS_SIZE + rem; - // create some packet p - auto p = stack.createPacket(size); - memcpy(p->buffer() + PacketUDP::HEADERS_SIZE, buffer, rem); + // create some packet p + auto p = stack.createPacket(size); + memcpy(p->buffer() + PacketUDP::HEADERS_SIZE, buffer, rem); - // initialize packet with several infos - auto p2 = std::static_pointer_cast(p); - packet_init(p2, srcIP, destIP, port, rem); - // ship the packet - stack.udp().transmit(p2); - } + // initialize packet with several infos + auto p2 = std::static_pointer_cast(p); + packet_init(p2, srcIP, destIP, port, rem); + // ship the packet + stack.udp().transmit(p2); + } return length; } // internal_write() int Socket::sendto(addr destIP, port port, - const void* buffer, int len) + const void* buffer, int len) { return internal_write(local_addr(), destIP, port, (const uint8_t*) buffer, len); } int Socket::bcast(addr srcIP, port port, - const void* buffer, int len) + const void* buffer, int len) { return internal_write(srcIP, IP4::INADDR_BCAST, port, (const uint8_t*) buffer, len); diff --git a/src/net/ip6/icmp6.cpp b/src/net/ip6/icmp6.cpp index b58907e3b1..f36c2e18da 100644 --- a/src/net/ip6/icmp6.cpp +++ b/src/net/ip6/icmp6.cpp @@ -44,92 +44,92 @@ namespace net std::string ICMPv6::code_string(uint8_t type, uint8_t code) { switch (type) - { - /// error codes /// - case 1: - /// delivery problems /// - switch (code) { - case 0: - return "No route to destination"; + /// error codes /// case 1: - return "Communication with dest administratively prohibited"; + /// delivery problems /// + switch (code) + { + case 0: + return "No route to destination"; + case 1: + return "Communication with dest administratively prohibited"; + case 2: + return "Beyond scope of source address"; + case 3: + return "Address unreachable"; + case 4: + return "Port unreachable"; + case 5: + return "Source address failed ingress/egress policy"; + case 6: + return "Reject route to destination"; + case 7: + return "Error in source routing header"; + default: + return "ERROR Invalid ICMP type"; + } case 2: - return "Beyond scope of source address"; + /// size problems /// + return "Packet too big"; + case 3: - return "Address unreachable"; + /// time problems /// + switch (code) + { + case 0: + return "Hop limit exceeded in traffic"; + case 1: + return "Fragment reassembly time exceeded"; + default: + return "ERROR Invalid ICMP code"; + } case 4: - return "Port unreachable"; - case 5: - return "Source address failed ingress/egress policy"; - case 6: - return "Reject route to destination"; - case 7: - return "Error in source routing header"; - default: - return "ERROR Invalid ICMP type"; - } - case 2: - /// size problems /// - return "Packet too big"; + /// parameter problems /// + switch (code) + { + case 0: + return "Erroneous header field"; + case 1: + return "Unrecognized next header"; + case 2: + return "Unrecognized IPv6 option"; + default: + return "ERROR Invalid ICMP code"; + } - case 3: - /// time problems /// - switch (code) - { - case 0: - return "Hop limit exceeded in traffic"; - case 1: - return "Fragment reassembly time exceeded"; - default: - return "ERROR Invalid ICMP code"; - } - case 4: - /// parameter problems /// - switch (code) - { - case 0: - return "Erroneous header field"; - case 1: - return "Unrecognized next header"; - case 2: - return "Unrecognized IPv6 option"; - default: - return "ERROR Invalid ICMP code"; - } - - /// echo feature /// - case ECHO_REQUEST: - return "Echo request"; - case ECHO_REPLY: - return "Echo reply"; + /// echo feature /// + case ECHO_REQUEST: + return "Echo request"; + case ECHO_REPLY: + return "Echo reply"; - /// multicast feature /// - case 130: - return "Multicast listener query"; - case 131: - return "Multicast listener report"; - case 132: - return "Multicast listener done"; + /// multicast feature /// + case 130: + return "Multicast listener query"; + case 131: + return "Multicast listener report"; + case 132: + return "Multicast listener done"; - /// neighbor discovery protocol /// - case ND_ROUTER_SOL: - return "NDP Router solicitation request"; - case ND_ROUTER_ADV: - return "NDP Router advertisement"; - case ND_NEIGHB_SOL: - return "NDP Neighbor solicitation request"; - case ND_NEIGHB_ADV: - return "NDP Neighbor advertisement"; - case ND_REDIRECT: - return "NDP Redirect message"; + /// neighbor discovery protocol /// + case ND_ROUTER_SOL: + return "NDP Router solicitation request"; + case ND_ROUTER_ADV: + return "NDP Router advertisement"; + case ND_NEIGHB_SOL: + return "NDP Neighbor solicitation request"; + case ND_NEIGHB_ADV: + return "NDP Neighbor advertisement"; + case ND_REDIRECT: + return "NDP Redirect message"; - case 143: - return "Multicast Listener Discovery (MLDv2) reports (RFC 3810)"; + case 143: + return "Multicast Listener Discovery (MLDv2) reports (RFC 3810)"; - default: - return "Unknown type: " + std::to_string((int) type); - } + default: + return "Unknown type: " + std::to_string((int) type); + } } int ICMPv6::bottom(Packet_ptr pckt) @@ -139,27 +139,27 @@ namespace net type_t type = icmp->type(); if (listeners.find(type) != listeners.end()) - { - return listeners[type](*this, icmp); - } + { + return listeners[type](*this, icmp); + } else - { - debug(">>> IPv6 -> ICMPv6 bottom (no handler installed)\n"); - debug("ICMPv6 type %d: %s\n", - (int) icmp->type(), code_string(icmp->type(), icmp->code()).c_str()); + { + debug(">>> IPv6 -> ICMPv6 bottom (no handler installed)\n"); + debug("ICMPv6 type %d: %s\n", + (int) icmp->type(), code_string(icmp->type(), icmp->code()).c_str()); - /* - // show correct checksum - intptr_t chksum = icmp->checksum(); - debug("ICMPv6 checksum: %p \n",(void*) chksum); + /* + // show correct checksum + intptr_t chksum = icmp->checksum(); + debug("ICMPv6 checksum: %p \n",(void*) chksum); - // show our recalculated checksum - icmp->header().checksum_ = 0; - chksum = checksum(icmp); - debug("ICMPv6 our estimate: %p \n", (void*) chksum ); - */ - return -1; - } + // show our recalculated checksum + icmp->header().checksum_ = 0; + chksum = checksum(icmp); + debug("ICMPv6 our estimate: %p \n", (void*) chksum ); + */ + return -1; + } } int ICMPv6::transmit(std::shared_ptr& pckt) { @@ -189,18 +189,18 @@ namespace net //assert(hdr.next() == 58); // ICMPv6 /** - RFC 4443 - 2.3. Message Checksum Calculation + RFC 4443 + 2.3. Message Checksum Calculation - The checksum is the 16-bit one's complement of the one's complement - sum of the entire ICMPv6 message, starting with the ICMPv6 message - type field, and prepended with a "pseudo-header" of IPv6 header - fields, as specified in [IPv6, Section 8.1]. The Next Header value - used in the pseudo-header is 58. (The inclusion of a pseudo-header - in the ICMPv6 checksum is a change from IPv4; see [IPv6] for the - rationale for this change.) + The checksum is the 16-bit one's complement of the one's complement + sum of the entire ICMPv6 message, starting with the ICMPv6 message + type field, and prepended with a "pseudo-header" of IPv6 header + fields, as specified in [IPv6, Section 8.1]. The Next Header value + used in the pseudo-header is 58. (The inclusion of a pseudo-header + in the ICMPv6 checksum is a change from IPv4; see [IPv6] for the + rationale for this change.) - For computing the checksum, the checksum field is first set to zero. + For computing the checksum, the checksum field is first set to zero. **/ union { @@ -214,7 +214,7 @@ namespace net uint16_t* it_end = it + sizeof(pseudo_header) / 2; while (it < it_end) - sum.whole += *(it++); + sum.whole += *(it++); // compute sum of data it = (uint16_t*) pckt->payload(); @@ -243,21 +243,21 @@ namespace net icmp->type = ICMPv6::ECHO_REPLY; if (pckt->dst().is_multicast()) - { - // We won't be changing source address for multicast ping - debug("Was multicast ping6: no change for source and dest\n"); - } + { + // We won't be changing source address for multicast ping + debug("Was multicast ping6: no change for source and dest\n"); + } else - { - printf("Normal ping6: source is us\n"); - printf("src is %s\n", pckt->src().str().c_str()); - printf("dst is %s\n", pckt->dst().str().c_str()); + { + printf("Normal ping6: source is us\n"); + printf("src is %s\n", pckt->src().str().c_str()); + printf("dst is %s\n", pckt->dst().str().c_str()); - printf("multicast is %s\n", IP6::addr::link_all_nodes.str().c_str()); - // normal ping: send packet to source, from us - pckt->set_dst(pckt->src()); - pckt->set_src(caller.local_ip()); - } + printf("multicast is %s\n", IP6::addr::link_all_nodes.str().c_str()); + // normal ping: send packet to source, from us + pckt->set_dst(pckt->src()); + pckt->set_src(caller.local_ip()); + } // calculate and set checksum // NOTE: do this after changing packet contents! icmp->checksum = 0; @@ -288,9 +288,9 @@ namespace net // ether-broadcast an IPv6 packet to all routers // IPv6mcast_02: 33:33:00:00:00:02 auto pckt = IP6::create( - IP6::PROTO_ICMPv6, - Ethernet::addr::IPv6mcast_02, - IP6::addr::link_unspecified); + IP6::PROTO_ICMPv6, + Ethernet::addr::IPv6mcast_02, + IP6::addr::link_unspecified); // RFC4861 4.1. Router Solicitation Message Format pckt->set_hoplimit(255); diff --git a/src/net/ip6/ip6.cpp b/src/net/ip6/ip6.cpp index 029f3657a3..8ff9de8e1d 100644 --- a/src/net/ip6/ip6.cpp +++ b/src/net/ip6/ip6.cpp @@ -47,35 +47,35 @@ namespace net uint8_t IP6::parse6(uint8_t*& reader, uint8_t next) { switch (next) - { - case PROTO_HOPOPT: - case PROTO_OPTSv6: - { - debug(">>> IPv6 options header %s", protocol_name(next).c_str()); + { + case PROTO_HOPOPT: + case PROTO_OPTSv6: + { + debug(">>> IPv6 options header %s", protocol_name(next).c_str()); - options_header& opts = *(options_header*) reader; - reader += opts.size(); + options_header& opts = *(options_header*) reader; + reader += opts.size(); - debug("OPTSv6 size: %d\n", opts.size()); - debug("OPTSv6 ext size: %d\n", opts.extended()); + debug("OPTSv6 size: %d\n", opts.size()); + debug("OPTSv6 ext size: %d\n", opts.extended()); - next = opts.next(); - debug("OPTSv6 next: %s\n", protocol_name(next).c_str()); - } break; - case PROTO_ICMPv6: - break; - case PROTO_UDP: - break; + next = opts.next(); + debug("OPTSv6 next: %s\n", protocol_name(next).c_str()); + } break; + case PROTO_ICMPv6: + break; + case PROTO_UDP: + break; - default: - debug("Not parsing: %s\n", protocol_name(next).c_str()); - } + default: + debug("Not parsing: %s\n", protocol_name(next).c_str()); + } return next; } - void IP6::bottom(Packet_ptr pckt) - { + void IP6::bottom(Packet_ptr pckt) + { debug(">>> IPv6 packet:"); @@ -92,20 +92,20 @@ namespace net uint8_t next = hdr.next(); while (next != PROTO_NoNext) - { - auto it = proto_handlers.find(next); - if (it != proto_handlers.end()) { - // forward packet to handler - pckt->set_payload(reader); - it->second(pckt); + auto it = proto_handlers.find(next); + if (it != proto_handlers.end()) + { + // forward packet to handler + pckt->set_payload(reader); + it->second(pckt); + } + else + // just print information + next = parse6(reader, next); } - else - // just print information - next = parse6(reader, next); - } - }; + }; static const std::string lut = "0123456789abcdef"; @@ -117,12 +117,12 @@ namespace net const uint8_t* octet = i8; for (int i = 0; i < 16; i++) - { - ret[counter++] = lut[(octet[i] & 0xF0) >> 4]; - ret[counter++] = lut[(octet[i] & 0x0F) >> 0]; - if (i & 1) - ret[counter++] = ':'; - } + { + ret[counter++] = lut[(octet[i] & 0xF0) >> 4]; + ret[counter++] = lut[(octet[i] & 0x0F) >> 0]; + if (i & 1) + ret[counter++] = ':'; + } ret.resize(counter-1); return ret; } @@ -138,7 +138,7 @@ namespace net } std::shared_ptr IP6::create(uint8_t proto, - Ethernet::addr ether_dest, const IP6::addr& ip6_dest) + Ethernet::addr ether_dest, const IP6::addr& ip6_dest) { // arbitrarily big buffer uint8_t* data = new uint8_t[1500]; diff --git a/src/net/ip6/udp6.cpp b/src/net/ip6/udp6.cpp index e89aaf33dd..550fa7aad4 100644 --- a/src/net/ip6/udp6.cpp +++ b/src/net/ip6/udp6.cpp @@ -35,10 +35,10 @@ namespace net // check for listeners on dst port if (listeners.find(port) != listeners.end()) - { - // make the call to the listener on that port - return listeners[port](P6); - } + { + // make the call to the listener on that port + return listeners[port](P6); + } // was not forwarded, so just return -1 debug("... dumping packet, no listeners\n"); return -1; @@ -83,7 +83,7 @@ namespace net // normally we would start at &icmp_echo::type, but // it is after all the first element of the icmp message memcpy(data + sizeof(UDPv6::pseudo_header), this->payload(), - datalen - sizeof(UDPv6::pseudo_header)); + datalen - sizeof(UDPv6::pseudo_header)); // calculate csum and free data on return header().chksum = net::checksum(data, datalen); @@ -91,7 +91,7 @@ namespace net } std::shared_ptr UDPv6::create( - Ethernet::addr ether_dest, const IP6::addr& ip6_dest, UDPv6::port_t port) + Ethernet::addr ether_dest, const IP6::addr& ip6_dest, UDPv6::port_t port) { auto packet = IP6::create(IP6::PROTO_UDP, ether_dest, ip6_dest); auto udp_packet = view_packet_as (packet); diff --git a/src/net/tcp.cpp b/src/net/tcp.cpp index d58f9da6c1..518ac7c191 100644 --- a/src/net/tcp.cpp +++ b/src/net/tcp.cpp @@ -24,165 +24,165 @@ using namespace net; TCP::TCP(IPStack& inet) : - inet_(inet), - listeners_(), - connections_(), + inet_(inet), + listeners_(), + connections_(), write_queue(), - MAX_SEG_LIFETIME(30s) + MAX_SEG_LIFETIME(30s) { inet.on_transmit_queue_available(transmit_avail_delg::from(this)); } /* - Note: There is different approaches to how to handle listeners & connections. - Need to discuss and decide for the best one. + Note: There is different approaches to how to handle listeners & connections. + Need to discuss and decide for the best one. - Best solution(?): - Preallocate a pool with listening connections. - When threshold is reach, remove/add new ones, similar to TCP window. + Best solution(?): + Preallocate a pool with listening connections. + When threshold is reach, remove/add new ones, similar to TCP window. - Current solution: - Simple. + Current solution: + Simple. */ TCP::Connection& TCP::bind(Port port) { - auto listen_conn_it = listeners_.find(port); - // Already a listening socket. - if(listen_conn_it != listeners_.end()) { - throw TCPException{"Port is already taken."}; - } - auto& connection = (listeners_.emplace(port, Connection{*this, port})).first->second; - debug(" Bound to port %i \n", port); - connection.open(false); - return connection; + auto listen_conn_it = listeners_.find(port); + // Already a listening socket. + if(listen_conn_it != listeners_.end()) { + throw TCPException{"Port is already taken."}; + } + auto& connection = (listeners_.emplace(port, Connection{*this, port})).first->second; + debug(" Bound to port %i \n", port); + connection.open(false); + return connection; } /* - Active open a new connection to the given remote. + Active open a new connection to the given remote. - @WARNING: Callback is added when returned (TCP::connect(...).onSuccess(...)), - and open() is called before callback is added. + @WARNING: Callback is added when returned (TCP::connect(...).onSuccess(...)), + and open() is called before callback is added. */ TCP::Connection_ptr TCP::connect(Socket remote) { - std::shared_ptr connection = add_connection(free_port(), remote); - connection->open(true); - return connection; + std::shared_ptr connection = add_connection(free_port(), remote); + connection->open(true); + return connection; } /* - Active open a new connection to the given remote. + Active open a new connection to the given remote. */ void TCP::connect(Socket remote, Connection::ConnectCallback callback) { - auto connection = add_connection(free_port(), remote); - connection->onConnect(callback).open(true); + auto connection = add_connection(free_port(), remote); + connection->onConnect(callback).open(true); } TCP::Seq TCP::generate_iss() { - // Do something to get a iss. - return rand(); + // Do something to get a iss. + return rand(); } /* - TODO: Check if there is any ports free. + TODO: Check if there is any ports free. */ TCP::Port TCP::free_port() { - if(++current_ephemeral_ == 0) - current_ephemeral_ = 1025; - // Avoid giving a port that is bound to a service. - while(listeners_.find(current_ephemeral_) != listeners_.end()) - current_ephemeral_++; + if(++current_ephemeral_ == 0) + current_ephemeral_ = 1025; + // Avoid giving a port that is bound to a service. + while(listeners_.find(current_ephemeral_) != listeners_.end()) + current_ephemeral_++; - return current_ephemeral_; + return current_ephemeral_; } uint16_t TCP::checksum(TCP::Packet_ptr packet) { - // TCP header - TCP::Header* tcp_hdr = &(packet->header()); - // Pseudo header - TCP::Pseudo_header pseudo_hdr; - - int tcp_length = packet->tcp_length(); - - pseudo_hdr.saddr.whole = packet->src().whole; - pseudo_hdr.daddr.whole = packet->dst().whole; - pseudo_hdr.zero = 0; - pseudo_hdr.proto = IP4::IP4_TCP; - pseudo_hdr.tcp_length = htons(tcp_length); - - union { - uint32_t whole; - uint16_t part[2]; - } sum; - - sum.whole = 0; - - // Compute sum of pseudo header - for (uint16_t* it = (uint16_t*)&pseudo_hdr; it < (uint16_t*)&pseudo_hdr + sizeof(pseudo_hdr)/2; it++) - sum.whole += *it; - - // Compute sum sum the actual header and data - for (uint16_t* it = (uint16_t*)tcp_hdr; it < (uint16_t*)tcp_hdr + tcp_length/2; it++) - sum.whole+= *it; - - // The odd-numbered case - if (tcp_length & 1) { - debug(" ODD number of bytes. 0-pading \n"); - union { - uint16_t whole; - uint8_t part[2]; - } last_chunk; - last_chunk.part[0] = ((uint8_t*)tcp_hdr)[tcp_length - 1]; - last_chunk.part[1] = 0; - sum.whole += last_chunk.whole; - } - - debug2("header()); + // Pseudo header + TCP::Pseudo_header pseudo_hdr; + + int tcp_length = packet->tcp_length(); + + pseudo_hdr.saddr.whole = packet->src().whole; + pseudo_hdr.daddr.whole = packet->dst().whole; + pseudo_hdr.zero = 0; + pseudo_hdr.proto = IP4::IP4_TCP; + pseudo_hdr.tcp_length = htons(tcp_length); + + union { + uint32_t whole; + uint16_t part[2]; + } sum; + + sum.whole = 0; + + // Compute sum of pseudo header + for (uint16_t* it = (uint16_t*)&pseudo_hdr; it < (uint16_t*)&pseudo_hdr + sizeof(pseudo_hdr)/2; it++) + sum.whole += *it; + + // Compute sum sum the actual header and data + for (uint16_t* it = (uint16_t*)tcp_hdr; it < (uint16_t*)tcp_hdr + tcp_length/2; it++) + sum.whole+= *it; + + // The odd-numbered case + if (tcp_length & 1) { + debug(" ODD number of bytes. 0-pading \n"); + union { + uint16_t whole; + uint8_t part[2]; + } last_chunk; + last_chunk.part[0] = ((uint8_t*)tcp_hdr)[tcp_length - 1]; + last_chunk.part[1] = 0; + sum.whole += last_chunk.whole; + } + + debug2("(packet_ptr); - debug(" TCP Packet received - Source: %s, Destination: %s \n", - packet->source().to_string().c_str(), packet->destination().to_string().c_str()); - - // Do checksum - if(checksum(packet)) { - debug(" TCP Packet Checksum != 0 \n"); - } - - Connection::Tuple tuple { packet->dst_port(), packet->source() }; - - // Try to find the receiver - auto conn_it = connections_.find(tuple); - // Connection found - if(conn_it != connections_.end()) { - debug(" Connection found: %s \n", conn_it->second->to_string().c_str()); - conn_it->second->segment_arrived(packet); - } - // No connection found - else { - // Is there a listener? - auto listen_conn_it = listeners_.find(packet->dst_port()); - debug(" No connection found - looking for listener..\n"); - // Listener found => Create listening Connection - if(listen_conn_it != listeners_.end()) { - auto& listen_conn = listen_conn_it->second; - debug(" Listener found: %s ...\n", listen_conn.to_string().c_str()); - auto connection = (connections_.emplace(tuple, std::make_shared(listen_conn)).first->second); - // Set remote - connection->set_remote(packet->source()); - debug(" ... Creating connection: %s \n", connection->to_string().c_str()); - - connection->segment_arrived(packet); - } - // No listener found - else { - drop(packet); - } - } + // Translate into a TCP::Packet. This will be used inside the TCP-scope. + auto packet = std::static_pointer_cast(packet_ptr); + debug(" TCP Packet received - Source: %s, Destination: %s \n", + packet->source().to_string().c_str(), packet->destination().to_string().c_str()); + + // Do checksum + if(checksum(packet)) { + debug(" TCP Packet Checksum != 0 \n"); + } + + Connection::Tuple tuple { packet->dst_port(), packet->source() }; + + // Try to find the receiver + auto conn_it = connections_.find(tuple); + // Connection found + if(conn_it != connections_.end()) { + debug(" Connection found: %s \n", conn_it->second->to_string().c_str()); + conn_it->second->segment_arrived(packet); + } + // No connection found + else { + // Is there a listener? + auto listen_conn_it = listeners_.find(packet->dst_port()); + debug(" No connection found - looking for listener..\n"); + // Listener found => Create listening Connection + if(listen_conn_it != listeners_.end()) { + auto& listen_conn = listen_conn_it->second; + debug(" Listener found: %s ...\n", listen_conn.to_string().c_str()); + auto connection = (connections_.emplace(tuple, std::make_shared(listen_conn)).first->second); + // Set remote + connection->set_remote(packet->source()); + debug(" ... Creating connection: %s \n", connection->to_string().c_str()); + + connection->segment_arrived(packet); + } + // No listener found + else { + drop(packet); + } + } } void TCP::process_write_queue(size_t packets) { @@ -209,54 +209,54 @@ size_t TCP::send(Connection_ptr conn, Connection::WriteBuffer& buffer) { } /* - Show all connections for TCP as a string. + Show all connections for TCP as a string. - Format: - [Protocol][Recv][Send][Local][Remote][State] + Format: + [Protocol][Recv][Send][Local][Remote][State] - TODO: Make sure Recv, Send, In, Out is correct and add them to output. Also, alignment? + TODO: Make sure Recv, Send, In, Out is correct and add them to output. Also, alignment? */ string TCP::status() const { - // Write all connections in a cute list. - stringstream ss; - ss << "LISTENING SOCKETS:\n"; - for(auto listen_it : listeners_) { - ss << listen_it.second.to_string() << "\n"; - } - ss << "\nCONNECTIONS:\n" << "Proto\tRecv\tSend\tIn\tOut\tLocal\t\t\tRemote\t\t\tState\n"; - for(auto con_it : connections_) { - auto& c = *(con_it.second); - ss << "tcp4\t" - << " " << "\t" << " " << "\t" - << " " << "\t" << " " << "\t" - << c.local().to_string() << "\t\t" << c.remote().to_string() << "\t\t" - << c.state().to_string() << "\n"; - } - return ss.str(); + // Write all connections in a cute list. + stringstream ss; + ss << "LISTENING SOCKETS:\n"; + for(auto listen_it : listeners_) { + ss << listen_it.second.to_string() << "\n"; + } + ss << "\nCONNECTIONS:\n" << "Proto\tRecv\tSend\tIn\tOut\tLocal\t\t\tRemote\t\t\tState\n"; + for(auto con_it : connections_) { + auto& c = *(con_it.second); + ss << "tcp4\t" + << " " << "\t" << " " << "\t" + << " " << "\t" << " " << "\t" + << c.local().to_string() << "\t\t" << c.remote().to_string() << "\t\t" + << c.state().to_string() << "\n"; + } + return ss.str(); } TCP::Connection_ptr TCP::add_connection(Port local_port, TCP::Socket remote) { - return (connections_.emplace( - Connection::Tuple{ local_port, remote }, - std::make_shared(*this, local_port, remote)) - ).first->second; + return (connections_.emplace( + Connection::Tuple{ local_port, remote }, + std::make_shared(*this, local_port, remote)) + ).first->second; } void TCP::close_connection(TCP::Connection& conn) { - debug(" Closing connection: %s \n", conn.to_string().c_str()); - connections_.erase(conn.tuple()); - debug2(" TCP Status: \n%s \n", status().c_str()); + debug(" Closing connection: %s \n", conn.to_string().c_str()); + connections_.erase(conn.tuple()); + debug2(" TCP Status: \n%s \n", status().c_str()); } void TCP::drop(TCP::Packet_ptr) { - //debug(" Packet was dropped - no recipient: %s \n", packet->destination().to_string().c_str()); + //debug(" Packet was dropped - no recipient: %s \n", packet->destination().to_string().c_str()); } void TCP::transmit(TCP::Packet_ptr packet) { - // Translate into a net::Packet_ptr and send away. - // Generate checksum. - packet->set_checksum(TCP::checksum(packet)); - //packet->set_checksum(checksum(packet)); - _network_layer_out(packet); + // Translate into a net::Packet_ptr and send away. + // Generate checksum. + packet->set_checksum(TCP::checksum(packet)); + //packet->set_checksum(checksum(packet)); + _network_layer_out(packet); } diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index 562a425165..154f048742 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -26,39 +26,39 @@ using Connection = TCP::Connection; using namespace std; /* - This is most likely used in a ACTIVE open + This is most likely used in a ACTIVE open */ Connection::Connection(TCP& host, Port local_port, Socket remote) : - host_(host), - local_port_(local_port), - remote_(remote), - state_(&Connection::Closed::instance()), - prev_state_(state_), - control_block(), + host_(host), + local_port_(local_port), + remote_(remote), + state_(&Connection::Closed::instance()), + prev_state_(state_), + control_block(), read_request(), - time_wait_started(0) + time_wait_started(0) { } /* - This is most likely used in a PASSIVE open + This is most likely used in a PASSIVE open */ Connection::Connection(TCP& host, Port local_port) : - host_(host), - local_port_(local_port), - remote_(TCP::Socket()), - state_(&Connection::Closed::instance()), - prev_state_(state_), - control_block(), + host_(host), + local_port_(local_port), + remote_(TCP::Socket()), + state_(&Connection::Closed::instance()), + prev_state_(state_), + control_block(), read_request(), - time_wait_started(0) + time_wait_started(0) { } void Connection::read(ReadBuffer buffer, ReadCallback callback) { - try { + try { state_->receive(*this, buffer); read_request.callback = callback; } @@ -161,7 +161,7 @@ size_t Connection::send(const char* buffer, size_t remaining, size_t& packet_cou remaining -= written; debug2(" Packet Limit: %u - Written: %u - Remaining: %u - Packet count: %u\n", - packet_limit, written, remaining, packet_count); + packet_limit, written, remaining, packet_count); // If last packet, add PUSH. if(!remaining and PUSH) @@ -182,7 +182,7 @@ void Connection::write_queue_on_connect() { auto written = send(buf); buf.advance(written); if(buf.remaining) - return; + return; write_queue.front().second(buf.offset); write_queue.pop(); } @@ -197,246 +197,246 @@ void Connection::write_queue_reset() { } void Connection::open(bool active) { - try { - debug(" Trying to open Connection...\n"); - state_->open(*this, active); - } - // No remote host, or state isnt valid for opening. - catch (TCPException e) { - debug(" Cannot open Connection. \n"); - signal_error(e); - } + try { + debug(" Trying to open Connection...\n"); + state_->open(*this, active); + } + // No remote host, or state isnt valid for opening. + catch (TCPException e) { + debug(" Cannot open Connection. \n"); + signal_error(e); + } } void Connection::close() { - debug(" Active close on connection. \n"); - try { - state_->close(*this); - if(is_state(Closed::instance())) - signal_close(); - } catch(TCPException err) { - signal_error(err); - } + debug(" Active close on connection. \n"); + try { + state_->close(*this); + if(is_state(Closed::instance())) + signal_close(); + } catch(TCPException err) { + signal_error(err); + } } /* Local:Port Remote:Port (STATE) */ string Connection::to_string() const { - ostringstream os; - os << local().to_string() << " " << remote_.to_string() << " (" << state_->to_string() << ")"; - return os.str(); + ostringstream os; + os << local().to_string() << " " << remote_.to_string() << " (" << state_->to_string() << ")"; + return os.str(); } void Connection::segment_arrived(TCP::Packet_ptr incoming) { - signal_packet_received(incoming); - - if(incoming->has_options()) { - try { - parse_options(incoming); - } - catch(TCPBadOptionException err) { - printf(" %s \n", err.what()); - } - } - - // Change window accordingly. TODO: Not sure if this is how you do it. - control_block.SND.WND = incoming->win(); - - // Let state handle what to do when incoming packet arrives, and modify the outgoing packet. - switch(state_->handle(*this, incoming)) { - case State::OK: { - // Do nothing. - break; - } - case State::CLOSED: { - debug(" State handle finished with CLOSED. We're done, ask host() to delete the connection. \n"); - signal_close(); - break; - }; - case State::CLOSE: { - debug(" State handle finished with CLOSE. onDisconnect has been called, close the connection. \n"); - state_->close(*this); - break; - }; - } + signal_packet_received(incoming); + + if(incoming->has_options()) { + try { + parse_options(incoming); + } + catch(TCPBadOptionException err) { + printf(" %s \n", err.what()); + } + } + + // Change window accordingly. TODO: Not sure if this is how you do it. + control_block.SND.WND = incoming->win(); + + // Let state handle what to do when incoming packet arrives, and modify the outgoing packet. + switch(state_->handle(*this, incoming)) { + case State::OK: { + // Do nothing. + break; + } + case State::CLOSED: { + debug(" State handle finished with CLOSED. We're done, ask host() to delete the connection. \n"); + signal_close(); + break; + }; + case State::CLOSE: { + debug(" State handle finished with CLOSE. onDisconnect has been called, close the connection. \n"); + state_->close(*this); + break; + }; + } } bool Connection::is_listening() const { - return is_state(Listen::instance()); + return is_state(Listen::instance()); } Connection::~Connection() { - // Do all necessary clean up. - // Free up buffers etc. - debug2(" Bye bye... \n"); + // Do all necessary clean up. + // Free up buffers etc. + debug2(" Bye bye... \n"); } TCP::Packet_ptr Connection::create_outgoing_packet() { - auto packet = std::static_pointer_cast((host_.inet_).createPacket(TCP::Packet::HEADERS_SIZE)); + auto packet = std::static_pointer_cast((host_.inet_).createPacket(TCP::Packet::HEADERS_SIZE)); - packet->init(); - // Set Source (local == the current connection) - packet->set_source(local()); - // Set Destination (remote) - packet->set_destination(remote_); + packet->init(); + // Set Source (local == the current connection) + packet->set_source(local()); + // Set Destination (remote) + packet->set_destination(remote_); - packet->set_win_size(control_block.SND.WND); + packet->set_win_size(control_block.SND.WND); - // Set SEQ and ACK - I think this is OK.. - packet->set_seq(control_block.SND.NXT).set_ack(control_block.RCV.NXT); - debug(" Outgoing packet created: %s \n", packet->to_string().c_str()); + // Set SEQ and ACK - I think this is OK.. + packet->set_seq(control_block.SND.NXT).set_ack(control_block.RCV.NXT); + debug(" Outgoing packet created: %s \n", packet->to_string().c_str()); - return packet; + return packet; } void Connection::transmit(TCP::Packet_ptr packet) { - debug(" Transmitting: %s \n", packet->to_string().c_str()); - host_.transmit(packet); - // Don't think we would like to retransmit reset packets..? - //if(!packet->isset(RST)) - // add_retransmission(packet); + debug(" Transmitting: %s \n", packet->to_string().c_str()); + host_.transmit(packet); + // Don't think we would like to retransmit reset packets..? + //if(!packet->isset(RST)) + // add_retransmission(packet); } TCP::Seq Connection::generate_iss() { - return host_.generate_iss(); + return host_.generate_iss(); } void Connection::set_state(State& state) { - prev_state_ = state_; - state_ = &state; - debug(" %s => %s \n", - prev_state_->to_string().c_str(), state_->to_string().c_str()); + prev_state_ = state_; + state_ = &state; + debug(" %s => %s \n", + prev_state_->to_string().c_str(), state_->to_string().c_str()); } void Connection::add_retransmission(TCP::Packet_ptr packet) { - debug2(" Packet added to retransmission. \n"); - auto self = shared_from_this(); - hw::PIT::instance().onTimeout(RTO(), [packet, self] { - // Packet hasnt been ACKed. - if(packet->seq() > self->tcb().SND.UNA) { - debug(" Packet unacknowledge, retransmitting...\n"); - self->transmit(packet); - } else { - debug2(" Packet acknowledged %s \n", packet->to_string().c_str()); - // Signal user? - } - }); + debug2(" Packet added to retransmission. \n"); + auto self = shared_from_this(); + hw::PIT::instance().onTimeout(RTO(), [packet, self] { + // Packet hasnt been ACKed. + if(packet->seq() > self->tcb().SND.UNA) { + debug(" Packet unacknowledge, retransmitting...\n"); + self->transmit(packet); + } else { + debug2(" Packet acknowledged %s \n", packet->to_string().c_str()); + // Signal user? + } + }); } /* - Next compute a Smoothed Round Trip Time (SRTT) as: + Next compute a Smoothed Round Trip Time (SRTT) as: - SRTT = ( ALPHA * SRTT ) + ((1-ALPHA) * RTT) + SRTT = ( ALPHA * SRTT ) + ((1-ALPHA) * RTT) - and based on this, compute the retransmission timeout (RTO) as: + and based on this, compute the retransmission timeout (RTO) as: - RTO = min[UBOUND,max[LBOUND,(BETA*SRTT)]] + RTO = min[UBOUND,max[LBOUND,(BETA*SRTT)]] - where UBOUND is an upper bound on the timeout (e.g., 1 minute), - LBOUND is a lower bound on the timeout (e.g., 1 second), ALPHA is - a smoothing factor (e.g., .8 to .9), and BETA is a delay variance - factor (e.g., 1.3 to 2.0). + where UBOUND is an upper bound on the timeout (e.g., 1 minute), + LBOUND is a lower bound on the timeout (e.g., 1 second), ALPHA is + a smoothing factor (e.g., .8 to .9), and BETA is a delay variance + factor (e.g., 1.3 to 2.0). */ std::chrono::milliseconds Connection::RTO() const { - return 1s; + return 1s; } void Connection::start_time_wait_timeout() { - debug2(" Time Wait timer started. \n"); - time_wait_started = OS::cycles_since_boot(); - auto timeout = 2 * host().MSL(); // 60 seconds - // Passing "this"..? - hw::PIT::instance().onTimeout(timeout,[this, timeout] { - // The timer hasnt been updated - if( OS::cycles_since_boot() >= (time_wait_started + timeout.count()) ) { - signal_close(); - } else { - debug2(" time_wait_started has been updated. \n"); - } - }); + debug2(" Time Wait timer started. \n"); + time_wait_started = OS::cycles_since_boot(); + auto timeout = 2 * host().MSL(); // 60 seconds + // Passing "this"..? + hw::PIT::instance().onTimeout(timeout,[this, timeout] { + // The timer hasnt been updated + if( OS::cycles_since_boot() >= (time_wait_started + timeout.count()) ) { + signal_close(); + } else { + debug2(" time_wait_started has been updated. \n"); + } + }); } void Connection::signal_close() { - debug(" It's time to delete this connection. \n"); - host_.close_connection(*this); + debug(" It's time to delete this connection. \n"); + host_.close_connection(*this); } std::string Connection::TCB::to_string() const { - ostringstream os; - os << "SND" - << " .UNA = " << SND.UNA - << " .NXT = " << SND.NXT - << " .WND = " << SND.WND - << " .UP = " << SND.UP - << " .WL1 = " << SND.WL1 - << " .WL2 = " << SND.WL2 - << " ISS = " << ISS - << "\n RCV" - << " .NXT = " << RCV.NXT - << " .WND = " << RCV.WND - << " .UP = " << RCV.UP - << " IRS = " << IRS; - return os.str(); + ostringstream os; + os << "SND" + << " .UNA = " << SND.UNA + << " .NXT = " << SND.NXT + << " .WND = " << SND.WND + << " .UP = " << SND.UP + << " .WL1 = " << SND.WL1 + << " .WL2 = " << SND.WL2 + << " ISS = " << ISS + << "\n RCV" + << " .NXT = " << RCV.NXT + << " .WND = " << RCV.WND + << " .UP = " << RCV.UP + << " IRS = " << IRS; + return os.str(); } void Connection::parse_options(TCP::Packet_ptr packet) { - assert(packet->has_options()); - debug(" Parsing options. Offset: %u, Options: %u \n", - packet->offset(), packet->options_length()); - - auto* opt = packet->options(); - - while((char*)opt < packet->data()) { - - auto* option = (TCP::Option*)opt; - - switch(option->kind) { - - case Option::END: { - return; - } - - case Option::NOP: { - opt++; - break; - } - - case Option::MSS: { - // unlikely - if(option->length != 4) - throw TCPBadOptionException{Option::MSS, "length != 4"}; - // unlikely - if(!packet->isset(SYN)) - throw TCPBadOptionException{Option::MSS, "Non-SYN packet"}; - - auto* opt_mss = (Option::opt_mss*)option; - uint16_t mss = ntohs(opt_mss->mss); - control_block.SND.MSS = mss; - debug2(" MSS: %u \n", mss); - opt += option->length; - break; - } - - default: - return; - } - } + assert(packet->has_options()); + debug(" Parsing options. Offset: %u, Options: %u \n", + packet->offset(), packet->options_length()); + + auto* opt = packet->options(); + + while((char*)opt < packet->data()) { + + auto* option = (TCP::Option*)opt; + + switch(option->kind) { + + case Option::END: { + return; + } + + case Option::NOP: { + opt++; + break; + } + + case Option::MSS: { + // unlikely + if(option->length != 4) + throw TCPBadOptionException{Option::MSS, "length != 4"}; + // unlikely + if(!packet->isset(SYN)) + throw TCPBadOptionException{Option::MSS, "Non-SYN packet"}; + + auto* opt_mss = (Option::opt_mss*)option; + uint16_t mss = ntohs(opt_mss->mss); + control_block.SND.MSS = mss; + debug2(" MSS: %u \n", mss); + opt += option->length; + break; + } + + default: + return; + } + } } void Connection::add_option(TCP::Option::Kind kind, TCP::Packet_ptr packet) { - switch(kind) { - - case Option::MSS: { - packet->add_option(host_.MSS()); - debug2(" Packet: %s - MSS: %u\n", - packet->to_string().c_str(), ntohs(*(uint16_t*)(packet->options()+2))); - break; - } - default: - break; - } + switch(kind) { + + case Option::MSS: { + packet->add_option(host_.MSS()); + debug2(" Packet: %s - MSS: %u\n", + packet->to_string().c_str(), ntohs(*(uint16_t*)(packet->options()+2))); + break; + } + default: + break; + } } diff --git a/src/net/tcp_connection_states.cpp b/src/net/tcp_connection_states.cpp index bf50259cdb..03d0ba5a46 100644 --- a/src/net/tcp_connection_states.cpp +++ b/src/net/tcp_connection_states.cpp @@ -21,7 +21,7 @@ using namespace std; ///////////////////////////////////////////////////////////////////// /* - COMMON STATE FUNCTIONS + COMMON STATE FUNCTIONS These functions are helper functions and used by more than one state. */ @@ -29,20 +29,20 @@ using namespace std; ///////////////////////////////////////////////////////////////////// /* - 1. Check Sequence number. + 1. Check Sequence number. Used for checking if the sequence number is acceptable. [RFC 793]: - SYN-RECEIVED STATE - ESTABLISHED STATE - FIN-WAIT-1 STATE + SYN-RECEIVED STATE + ESTABLISHED STATE + FIN-WAIT-1 STATE FIN-WAIT-2 STATE - CLOSE-WAIT STATE - CLOSING STATE - LAST-ACK STATE - TIME-WAIT STATE + CLOSE-WAIT STATE + CLOSING STATE + LAST-ACK STATE + TIME-WAIT STATE Segments are processed in sequence. Initial tests on arrival are used to discard old duplicates, but further processing is @@ -57,14 +57,14 @@ using namespace std; Length Window ------- ------- ------------------------------------------- - 0 0 SEG.SEQ = RCV.NXT + 0 0 SEG.SEQ = RCV.NXT - 0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND + 0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND - >0 0 not acceptable + >0 0 not acceptable - >0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND - or RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND + >0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND + or RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND If the RCV.WND is zero, no segments will be acceptable, but special allowance should be made to accept valid ACKs, URGs and @@ -74,7 +74,7 @@ using namespace std; should be sent in reply (unless the RST bit is set, if so drop the segment and return): - + After sending the acknowledgment, drop the unacceptable segment and return. @@ -91,68 +91,68 @@ using namespace std; // TODO: Optimize this one. It checks for the same things. bool Connection::State::check_seq(Connection& tcp, TCP::Packet_ptr in) { - auto& tcb = tcp.tcb(); - bool acceptable = false; - debug2(" TCB: %s \n",tcb.to_string().c_str()); - // #1 - if( in->seq() == tcb.RCV.NXT ) { - acceptable = true; - } - // #2 - else if( tcb.RCV.NXT <= in->seq() and in->seq() < tcb.RCV.NXT + tcb.RCV.WND ) { - acceptable = true; - } - // #3 (INVALID) - else if( in->seq() + in->data_length()-1 > tcb.RCV.NXT+tcb.RCV.WND ) { - acceptable = false; - } - // #4 - else if( (tcb.RCV.NXT <= in->seq() and in->seq() < tcb.RCV.NXT + tcb.RCV.WND) - or ( tcb.RCV.NXT <= in->seq()+in->data_length()-1 and in->seq()+in->data_length()-1 < tcb.RCV.NXT+tcb.RCV.WND ) ) { - acceptable = true; - } - /* - If an incoming segment is not acceptable, an acknowledgment - should be sent in reply (unless the RST bit is set, if so drop - the segment and return): - - - - After sending the acknowledgment, drop the unacceptable segment - and return. - */ - if(!acceptable) { - if(!in->isset(RST)) { - auto packet = tcp.outgoing_packet(); + auto& tcb = tcp.tcb(); + bool acceptable = false; + debug2(" TCB: %s \n",tcb.to_string().c_str()); + // #1 + if( in->seq() == tcb.RCV.NXT ) { + acceptable = true; + } + // #2 + else if( tcb.RCV.NXT <= in->seq() and in->seq() < tcb.RCV.NXT + tcb.RCV.WND ) { + acceptable = true; + } + // #3 (INVALID) + else if( in->seq() + in->data_length()-1 > tcb.RCV.NXT+tcb.RCV.WND ) { + acceptable = false; + } + // #4 + else if( (tcb.RCV.NXT <= in->seq() and in->seq() < tcb.RCV.NXT + tcb.RCV.WND) + or ( tcb.RCV.NXT <= in->seq()+in->data_length()-1 and in->seq()+in->data_length()-1 < tcb.RCV.NXT+tcb.RCV.WND ) ) { + acceptable = true; + } + /* + If an incoming segment is not acceptable, an acknowledgment + should be sent in reply (unless the RST bit is set, if so drop + the segment and return): + + + + After sending the acknowledgment, drop the unacceptable segment + and return. + */ + if(!acceptable) { + if(!in->isset(RST)) { + auto packet = tcp.outgoing_packet(); packet->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); - tcp.transmit(packet); - } - tcp.drop(in, "Unacceptable SEQ."); - return false; - } - debug2(" Acceptable SEQ: %u \n", in->seq()); - // is acceptable. - return true; + tcp.transmit(packet); + } + tcp.drop(in, "Unacceptable SEQ."); + return false; + } + debug2(" Acceptable SEQ: %u \n", in->seq()); + // is acceptable. + return true; } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /* - 4. Check SYN + 4. Check SYN Used to filter out packets carrying SYN-flag when they're not supposed to. [RFC 793]: - SYN-RECEIVED - ESTABLISHED STATE - FIN-WAIT STATE-1 - FIN-WAIT STATE-2 - CLOSE-WAIT STATE - CLOSING STATE - LAST-ACK STATE - TIME-WAIT STATE + SYN-RECEIVED + ESTABLISHED STATE + FIN-WAIT STATE-1 + FIN-WAIT STATE-2 + CLOSE-WAIT STATE + CLOSING STATE + LAST-ACK STATE + TIME-WAIT STATE If the SYN is in the window it is an error, send a reset, any outstanding RECEIVEs and SEND should receive "reset" responses, @@ -167,14 +167,14 @@ bool Connection::State::check_seq(Connection& tcp, TCP::Packet_ptr in) { ///////////////////////////////////////////////////////////////////// void Connection::State::unallowed_syn_reset_connection(Connection& tcp, TCP::Packet_ptr in) { - assert(in->isset(SYN)); - debug(" Unallowed SYN for STATE: %s, reseting connection.\n", - tcp.state().to_string().c_str()); - // Not sure if this is the correct way to send a "reset response" - auto packet = tcp.outgoing_packet(); + assert(in->isset(SYN)); + debug(" Unallowed SYN for STATE: %s, reseting connection.\n", + tcp.state().to_string().c_str()); + // Not sure if this is the correct way to send a "reset response" + auto packet = tcp.outgoing_packet(); packet->set_seq(in->ack()).set_flag(RST); - tcp.transmit(packet); - tcp.signal_disconnect(Disconnect::RESET); + tcp.transmit(packet); + tcp.signal_disconnect(Disconnect::RESET); } ///////////////////////////////////////////////////////////////////// @@ -182,7 +182,7 @@ void Connection::State::unallowed_syn_reset_connection(Connection& tcp, TCP::Pac ///////////////////////////////////////////////////////////////////// /* - 5. Check ACK + 5. Check ACK "Process" the packet if ACK is present. If not, drop the packet. @@ -191,74 +191,74 @@ void Connection::State::unallowed_syn_reset_connection(Connection& tcp, TCP::Pac ///////////////////////////////////////////////////////////////////// bool Connection::State::check_ack(Connection& tcp, TCP::Packet_ptr in) { - debug2(" Checking for ACK in STATE: %s \n", tcp.state().to_string().c_str()); - if( in->isset(ACK) ) { - auto& tcb = tcp.tcb(); - /* - If SND.UNA < SEG.ACK =< SND.NXT then, set SND.UNA <- SEG.ACK. - Any segments on the retransmission queue which are thereby - entirely acknowledged are removed. Users should receive - positive acknowledgments for buffers which have been SENT and - fully acknowledged (i.e., SEND buffer should be returned with - "ok" response). If the ACK is a duplicate - (SEG.ACK < SND.UNA), it can be ignored. If the ACK acks - something not yet sent (SEG.ACK > SND.NXT) then send an ACK, - drop the segment, and return. - */ - if( tcb.SND.UNA < in->ack() and in->ack() <= tcb.SND.NXT ) { - tcb.SND.UNA = in->ack(); - // tcp.signal_sent(); - // return that buffer has been SENT - currently no support to receipt sent buffer. - - /* - If SND.UNA < SEG.ACK =< SND.NXT, the send window should be - updated. If (SND.WL1 < SEG.SEQ or (SND.WL1 = SEG.SEQ and - SND.WL2 =< SEG.ACK)), set SND.WND <- SEG.WND, set - SND.WL1 <- SEG.SEQ, and set SND.WL2 <- SEG.ACK. - */ - if( tcb.SND.WL1 < in->seq() or ( tcb.SND.WL1 = in->seq() and tcb.SND.WL2 <= in->ack() ) ) { - tcb.SND.WND = in->win(); - tcb.SND.WL1 = in->seq(); - tcb.SND.WL2 = in->ack(); - } - /* - Note that SND.WND is an offset from SND.UNA, that SND.WL1 - records the sequence number of the last segment used to update - SND.WND, and that SND.WL2 records the acknowledgment number of - the last segment used to update SND.WND. The check here - prevents using old segments to update the window. - */ - } - /* If the ACK acks something not yet sent (SEG.ACK > SND.NXT) then send an ACK, drop the segment, and return. */ - else if( in->ack() > tcb.SND.NXT ) { - auto packet = tcp.outgoing_packet(); - packet->set_flag(ACK); - tcp.transmit(packet); - tcp.drop(in, "ACK > SND.NXT"); - return false; - } - /* If the ACK is a duplicate (SEG.ACK < SND.UNA), it can be ignored. */ - /*else if( in->ack() < tcb.SND.UNA ) { - // ignore. - }*/ - return true; + debug2(" Checking for ACK in STATE: %s \n", tcp.state().to_string().c_str()); + if( in->isset(ACK) ) { + auto& tcb = tcp.tcb(); + /* + If SND.UNA < SEG.ACK =< SND.NXT then, set SND.UNA <- SEG.ACK. + Any segments on the retransmission queue which are thereby + entirely acknowledged are removed. Users should receive + positive acknowledgments for buffers which have been SENT and + fully acknowledged (i.e., SEND buffer should be returned with + "ok" response). If the ACK is a duplicate + (SEG.ACK < SND.UNA), it can be ignored. If the ACK acks + something not yet sent (SEG.ACK > SND.NXT) then send an ACK, + drop the segment, and return. + */ + if( tcb.SND.UNA < in->ack() and in->ack() <= tcb.SND.NXT ) { + tcb.SND.UNA = in->ack(); + // tcp.signal_sent(); + // return that buffer has been SENT - currently no support to receipt sent buffer. + + /* + If SND.UNA < SEG.ACK =< SND.NXT, the send window should be + updated. If (SND.WL1 < SEG.SEQ or (SND.WL1 = SEG.SEQ and + SND.WL2 =< SEG.ACK)), set SND.WND <- SEG.WND, set + SND.WL1 <- SEG.SEQ, and set SND.WL2 <- SEG.ACK. + */ + if( tcb.SND.WL1 < in->seq() or ( tcb.SND.WL1 = in->seq() and tcb.SND.WL2 <= in->ack() ) ) { + tcb.SND.WND = in->win(); + tcb.SND.WL1 = in->seq(); + tcb.SND.WL2 = in->ack(); + } + /* + Note that SND.WND is an offset from SND.UNA, that SND.WL1 + records the sequence number of the last segment used to update + SND.WND, and that SND.WL2 records the acknowledgment number of + the last segment used to update SND.WND. The check here + prevents using old segments to update the window. + */ } - // ACK not set. - else { - tcp.drop(in, "!ACK"); - return false; + /* If the ACK acks something not yet sent (SEG.ACK > SND.NXT) then send an ACK, drop the segment, and return. */ + else if( in->ack() > tcb.SND.NXT ) { + auto packet = tcp.outgoing_packet(); + packet->set_flag(ACK); + tcp.transmit(packet); + tcp.drop(in, "ACK > SND.NXT"); + return false; } + /* If the ACK is a duplicate (SEG.ACK < SND.UNA), it can be ignored. */ + /*else if( in->ack() < tcb.SND.UNA ) { + // ignore. + }*/ + return true; + } + // ACK not set. + else { + tcp.drop(in, "!ACK"); + return false; + } } ///////////////////////////////////////////////////////////////////// /* - 7. Process the segment text + 7. Process the segment text If a packet has data, process the data. [RFC 793] Page 74: - Once in the ESTABLISHED state, it is possible to deliver segment + Once in the ESTABLISHED state, it is possible to deliver segment text to user RECEIVE buffers. Text from segments can be moved into buffers until either the buffer is full or the segment is empty. If the segment empties and carries an PUSH flag, then @@ -277,7 +277,7 @@ bool Connection::State::check_ack(Connection& tcp, TCP::Packet_ptr in) { Send an acknowledgment of the form: - + This acknowledgment should be piggybacked on a segment being transmitted if possible without incurring undue delay. @@ -287,46 +287,46 @@ bool Connection::State::check_ack(Connection& tcp, TCP::Packet_ptr in) { void Connection::State::process_segment(Connection& tcp, TCP::Packet_ptr in) { assert(in->has_data()); - auto& tcb = tcp.tcb(); - auto length = in->data_length(); - debug(" Received packet with DATA-LENGTH: %i. Add to receive buffer. \n", length); + auto& tcb = tcp.tcb(); + auto length = in->data_length(); + debug(" Received packet with DATA-LENGTH: %i. Add to receive buffer. \n", length); if(tcp.read_request.buffer.capacity()) { auto received = tcp.receive((uint8_t*)in->data(), in->data_length(), in->isset(PSH)); assert(received == length); } - tcb.RCV.NXT += length; - auto snd_nxt = tcb.SND.NXT; - debug2(" Advanced RCV.NXT: %u. SND.NXT = %u \n", tcb.RCV.NXT, snd_nxt); - /* - Once the TCP takes responsibility for the data it advances + tcb.RCV.NXT += length; + auto snd_nxt = tcb.SND.NXT; + debug2(" Advanced RCV.NXT: %u. SND.NXT = %u \n", tcb.RCV.NXT, snd_nxt); + /* + Once the TCP takes responsibility for the data it advances RCV.NXT over the data accepted, and adjusts RCV.WND as apporopriate to the current buffer availability. The total of RCV.NXT and RCV.WND should not be reduced. */ // TODO: SACK (Selective ACK), or if there is a write queue, don't send ACK. - if(tcb.SND.NXT == snd_nxt) { - auto packet = tcp.outgoing_packet(); + if(tcb.SND.NXT == snd_nxt) { + auto packet = tcp.outgoing_packet(); packet->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); - tcp.transmit(packet); - } else { - debug2(" SND.NXT > snd_nxt, this packet has already been acknowledged. \n"); - } + tcp.transmit(packet); + } else { + debug2(" SND.NXT > snd_nxt, this packet has already been acknowledged. \n"); + } } ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /* - 8. Process FIN + 8. Process FIN Process a packet with FIN, by signal disconnect, reply with ACK etc. [RFC 793] Page 75: - If the FIN bit is set, signal the user "connection closing" and - return any pending RECEIVEs with same message, advance RCV.NXT - over the FIN, and send an acknowledgment for the FIN. Note that - FIN implies PUSH for any segment text not yet delivered to the - user. + If the FIN bit is set, signal the user "connection closing" and + return any pending RECEIVEs with same message, advance RCV.NXT + over the FIN, and send an acknowledgment for the FIN. Note that + FIN implies PUSH for any segment text not yet delivered to the + user. */ ///////////////////////////////////////////////////////////////////// @@ -334,14 +334,14 @@ void Connection::State::process_fin(Connection& tcp, TCP::Packet_ptr in) { debug(" Processing FIN bit in STATE: %s \n", tcp.state().to_string().c_str()); assert(in->isset(FIN)); auto& tcb = tcp.tcb(); - tcp.signal_disconnect(Disconnect::CLOSING); - // Advance RCV.NXT over the FIN? - tcb.RCV.NXT++; - //auto fin = in->data_length(); - //tcb.RCV.NXT += fin; + tcp.signal_disconnect(Disconnect::CLOSING); + // Advance RCV.NXT over the FIN? + tcb.RCV.NXT++; + //auto fin = in->data_length(); + //tcb.RCV.NXT += fin; auto packet = tcp.outgoing_packet(); - packet->set_ack(tcb.RCV.NXT).set_flag(ACK); - tcp.transmit(packet); + packet->set_ack(tcb.RCV.NXT).set_flag(ACK); + tcp.transmit(packet); // signal the user if(!tcp.read_request.buffer.empty()) tcp.receive_disconnect(); @@ -353,9 +353,9 @@ void Connection::State::process_fin(Connection& tcp, TCP::Packet_ptr in) { Send a reset segment. Used when aborting a connection. [RFC 793]: - Send a reset segment: + Send a reset segment: - + All queued SENDs and RECEIVEs should be given "connection reset" notification; all segments queued for transmission (except for the @@ -365,10 +365,10 @@ void Connection::State::process_fin(Connection& tcp, TCP::Packet_ptr in) { ///////////////////////////////////////////////////////////////////// void Connection::State::send_reset(Connection& tcp) { - tcp.write_queue_reset(); - auto packet = tcp.outgoing_packet(); + tcp.write_queue_reset(); + auto packet = tcp.outgoing_packet(); packet->set_seq(tcp.tcb().SND.NXT).set_ack(0).set_flag(RST); - tcp.transmit(packet); + tcp.transmit(packet); } ///////////////////////////////////////////////////////////////////// @@ -381,29 +381,29 @@ void Connection::State::send_reset(Connection& tcp) { The implemenation is ordered in the following structure: 1. Function - 2. State + 2. State Function order: - OPEN - SEND - RECEIVE - CLOSE - ABORT - HANDLE (SEGMENT ARRIVES) + OPEN + SEND + RECEIVE + CLOSE + ABORT + HANDLE (SEGMENT ARRIVES) State order: - State - this is the base state, works as fallback. - Closed - Listen - SynSent - SynReceived - Established - FinWait1 - FinWait2 - CloseWait - Closing - LastAck - TimeWait + State - this is the base state, works as fallback. + Closed + Listen + SynSent + SynReceived + Established + FinWait1 + FinWait2 + CloseWait + Closing + LastAck + TimeWait */ ///////////////////////////////////////////////////////////////////// @@ -596,8 +596,8 @@ void Connection::SynSent::close(Connection& tcp) { void Connection::SynReceived::close(Connection& tcp) { /* If no SENDs have been issued and there is no pending data to send, - then form a FIN segment and send it, and enter FIN-WAIT-1 state; - otherwise queue for processing after entering ESTABLISHED state. + then form a FIN segment and send it, and enter FIN-WAIT-1 state; + otherwise queue for processing after entering ESTABLISHED state. */ // Dont know how to queue for close for processing... auto& tcb = tcp.tcb(); @@ -636,7 +636,7 @@ void Connection::FinWait2::close(Connection&) { void Connection::CloseWait::close(Connection& tcp) { /* Queue this request until all preceding SENDs have been - segmentized; then send a FIN segment, enter CLOSING state. + segmentized; then send a FIN segment, enter CLOSING state. */ auto& tcb = tcp.tcb(); auto packet = tcp.outgoing_packet(); @@ -725,7 +725,7 @@ State::Result Connection::Listen::handle(Connection& tcp, TCP::Packet_ptr in) { tcb.SND.NXT = tcb.ISS+1; tcb.SND.UNA = tcb.ISS; debug(" Received SYN Packet: %s TCB Updated:\n %s \n", - in->to_string().c_str(), tcp.tcb().to_string().c_str()); + in->to_string().c_str(), tcp.tcb().to_string().c_str()); auto packet = tcp.outgoing_packet(); packet->set_seq(tcb.ISS).set_ack(tcb.RCV.NXT).set_flags(SYN | ACK); @@ -770,9 +770,9 @@ State::Result Connection::SynSent::handle(Connection& tcp, TCP::Packet_ptr in) { // 2. check RST if(in->isset(RST)) { if(in->isset(ACK)) { - tcp.signal_error(TCPException{"Connection reset."}); - tcp.drop(in, "RST with acceptable ACK"); - return CLOSED; + tcp.signal_error(TCPException{"Connection reset."}); + tcp.drop(in, "RST with acceptable ACK"); + return CLOSED; } else { tcp.drop(in, "RST"); return OK; @@ -800,7 +800,7 @@ State::Result Connection::SynSent::handle(Connection& tcp, TCP::Packet_ptr in) { If SND.UNA > ISS (our SYN has been ACKed), change the connection state to ESTABLISHED, form an ACK segment - + and send it. Data or controls which were queued for transmission may be included. If there are other controls or @@ -809,7 +809,7 @@ State::Result Connection::SynSent::handle(Connection& tcp, TCP::Packet_ptr in) { Otherwise enter SYN-RECEIVED, form a SYN,ACK segment - + and send it. If there are other controls or text in the segment, queue them for processing after the ESTABLISHED state @@ -1013,9 +1013,9 @@ State::Result Connection::FinWait1::handle(Connection& tcp, TCP::Packet_ptr in) return OK; } /* - In addition to the processing for the ESTABLISHED state, if - our FIN is now acknowledged then enter FIN-WAIT-2 and continue - processing in that state. + In addition to the processing for the ESTABLISHED state, if + our FIN is now acknowledged then enter FIN-WAIT-2 and continue + processing in that state. */ debug2(" Current TCB:\n %s \n", tcp.tcb().to_string().c_str()); if(in->ack() == tcp.tcb().SND.NXT) { @@ -1034,9 +1034,9 @@ State::Result Connection::FinWait1::handle(Connection& tcp, TCP::Packet_ptr in) process_fin(tcp, in); debug2(" FIN isset. TCB:\n %s \n", tcp.tcb().to_string().c_str()); /* - If our FIN has been ACKed (perhaps in this segment), then - enter TIME-WAIT, start the time-wait timer, turn off the other - timers; otherwise enter the CLOSING state. + If our FIN has been ACKed (perhaps in this segment), then + enter TIME-WAIT, start the time-wait timer, turn off the other + timers; otherwise enter the CLOSING state. */ if(in->ack() == tcp.tcb().SND.NXT) { // TODO: I guess or FIN is ACK'ed..? @@ -1062,7 +1062,7 @@ State::Result Connection::FinWait2::handle(Connection& tcp, TCP::Packet_ptr in) return CLOSED; // close } - // 4. check SYN + // 4. check SYN if( in->isset(SYN) ) { unallowed_syn_reset_connection(tcp, in); return CLOSED; @@ -1104,7 +1104,7 @@ State::Result Connection::CloseWait::handle(Connection& tcp, TCP::Packet_ptr in) return CLOSED; // close } - // 4. check SYN + // 4. check SYN if( in->isset(SYN) ) { unallowed_syn_reset_connection(tcp, in); return CLOSED; @@ -1129,32 +1129,32 @@ State::Result Connection::CloseWait::handle(Connection& tcp, TCP::Packet_ptr in) State::Result Connection::Closing::handle(Connection& tcp, TCP::Packet_ptr in) { - // 1. Check sequence number + // 1. Check sequence number if(! check_seq(tcp, in) ) { - return OK; + return OK; } // 2. check RST if( in->isset(RST) ) { - return CLOSED; // close + return CLOSED; // close } // 4. check SYN if( in->isset(SYN) ) { - unallowed_syn_reset_connection(tcp, in); - return CLOSED; - } - - // 5. check ACK - if( ! check_ack(tcp, in)) { - return CLOSED; - } - - /* - In addition to the processing for the ESTABLISHED state, if - the ACK acknowledges our FIN then enter the TIME-WAIT state, - otherwise ignore the segment. - */ + unallowed_syn_reset_connection(tcp, in); + return CLOSED; + } + + // 5. check ACK + if( ! check_ack(tcp, in)) { + return CLOSED; + } + + /* + In addition to the processing for the ESTABLISHED state, if + the ACK acknowledges our FIN then enter the TIME-WAIT state, + otherwise ignore the segment. + */ if(in->ack() == tcp.tcb().SND.NXT) { // TODO: I guess or FIN is ACK'ed..? tcp.set_state(TimeWait::instance()); @@ -1166,9 +1166,9 @@ State::Result Connection::Closing::handle(Connection& tcp, TCP::Packet_ptr in) { // 8. check FIN if(in->isset(FIN)) { - process_fin(tcp, in); - // Remain in state - return OK; + process_fin(tcp, in); + // Remain in state + return OK; } return OK; } diff --git a/src/virtio/block.cpp b/src/virtio/block.cpp index 534d1665bd..6c42fff3b7 100644 --- a/src/virtio/block.cpp +++ b/src/virtio/block.cpp @@ -29,41 +29,41 @@ #define FEAT(x) (1 << x) VirtioBlk::VirtioBlk(hw::PCI_Device& d) - : Virtio(d), - req(queue_size(0), 0, iobase()), - request_counter(0) +: Virtio(d), + req(queue_size(0), 0, iobase()), + request_counter(0) { INFO("VirtioBlk", "Driver initializing"); uint32_t needed_features = - FEAT(VIRTIO_BLK_F_BLK_SIZE); + FEAT(VIRTIO_BLK_F_BLK_SIZE); negotiate_features(needed_features); CHECK(features() & FEAT(VIRTIO_BLK_F_BARRIER), - "Barrier is enabled"); + "Barrier is enabled"); CHECK(features() & FEAT(VIRTIO_BLK_F_SIZE_MAX), - "Size-max is known"); + "Size-max is known"); CHECK(features() & FEAT(VIRTIO_BLK_F_SEG_MAX), - "Seg-max is known"); + "Seg-max is known"); CHECK(features() & FEAT(VIRTIO_BLK_F_GEOMETRY), - "Geometry structure is used"); + "Geometry structure is used"); CHECK(features() & FEAT(VIRTIO_BLK_F_RO), - "Device is read-only"); + "Device is read-only"); CHECK(features() & FEAT(VIRTIO_BLK_F_BLK_SIZE), - "Block-size is known"); + "Block-size is known"); CHECK(features() & FEAT(VIRTIO_BLK_F_SCSI), - "SCSI is enabled :("); + "SCSI is enabled :("); CHECK(features() & FEAT(VIRTIO_BLK_F_FLUSH), - "Flush enabled"); + "Flush enabled"); CHECK ((features() & needed_features) == needed_features, - "Negotiated needed features"); + "Negotiated needed features"); // Step 1 - Initialize REQ queue auto success = assign_queue(0, (uint32_t) req.queue_desc()); CHECK(success, "Request queue assigned (0x%x) to device", - (uint32_t) req.queue_desc()); + (uint32_t) req.queue_desc()); // Step 3 - Fill receive queue with buffers // DEBUG: Disable @@ -84,7 +84,7 @@ VirtioBlk::VirtioBlk(hw::PCI_Device& d) // Done INFO("VirtioBlk", "Block device with %llu sectors capacity", - config.capacity); + config.capacity); //CHECK(config.status == VIRTIO_BLK_S_OK, "Link up\n"); req.kick(); } @@ -105,21 +105,21 @@ void VirtioBlk::irq_handler() // Step 2. A) - one of the queues have changed if (isr & 1) - { - // This now means service RX & TX interchangeably - service_RX(); - } + { + // This now means service RX & TX interchangeably + service_RX(); + } // Step 2. B) if (isr & 2) - { - debug("\t Configuration change:\n"); + { + debug("\t Configuration change:\n"); - // Getting the MAC + status - //debug("\t Old status: 0x%x\n", config.status); - get_config(); - //debug("\t New status: 0x%x \n", config.status); - } + // Getting the MAC + status + //debug("\t Old status: 0x%x\n", config.status); + get_config(); + //debug("\t New status: 0x%x \n", config.status); + } IRQ_manager::eoi(irq()); } @@ -134,28 +134,28 @@ void VirtioBlk::service_RX() //printf("service_RX() reading from VirtioBlk device\n"); while ((hdr = (request_t*) req.dequeue(len)) != nullptr) - { - printf("service_RX() received %u bytes for sector %llu\n", - len, hdr->hdr.sector); - vbr = &hdr->data; + { + printf("service_RX() received %u bytes for sector %llu\n", + len, hdr->hdr.sector); + vbr = &hdr->data; - printf("service_RX() received %u bytes data response\n", len); - printf("Received handler: %p\n", vbr->handler); + printf("service_RX() received %u bytes data response\n", len); + printf("Received handler: %p\n", vbr->handler); - uint8_t* copy = new uint8_t[SECTOR_SIZE]; - memcpy(copy, vbr->sector, SECTOR_SIZE); - auto buf = buffer_t(copy, std::default_delete()); + uint8_t* copy = new uint8_t[SECTOR_SIZE]; + memcpy(copy, vbr->sector, SECTOR_SIZE); + auto buf = buffer_t(copy, std::default_delete()); - printf("Calling handler: %p\n", vbr->handler); - (*vbr->handler)(buf); - delete vbr->handler; + printf("Calling handler: %p\n", vbr->handler); + (*vbr->handler)(buf); + delete vbr->handler; - received++; - } + received++; + } if (received == 0) - { - //printf("service_RX() error processing requests\n"); - } + { + //printf("service_RX() error processing requests\n"); + } req.enable_interrupts(); } diff --git a/src/virtio/console.cpp b/src/virtio/console.cpp index 480ec1bf54..1d73459d21 100644 --- a/src/virtio/console.cpp +++ b/src/virtio/console.cpp @@ -26,58 +26,58 @@ extern "C" #define FEAT(x) (1 << x) VirtioCon::VirtioCon(hw::PCI_Device& d) - : Virtio(d), - rx(queue_size(0), 0, iobase()), - tx(queue_size(1), 1, iobase()), - ctl_rx(queue_size(2), 2, iobase()), - ctl_tx(queue_size(3), 3, iobase()) +: Virtio(d), + rx(queue_size(0), 0, iobase()), + tx(queue_size(1), 1, iobase()), + ctl_rx(queue_size(2), 2, iobase()), + ctl_tx(queue_size(3), 3, iobase()) { INFO("VirtioCon", "Driver initializing"); uint32_t needed_features = - FEAT(VIRTIO_CONSOLE_F_MULTIPORT); + FEAT(VIRTIO_CONSOLE_F_MULTIPORT); negotiate_features(needed_features); CHECK(features() & FEAT(VIRTIO_CONSOLE_F_SIZE), - "Valid console dimensions"); + "Valid console dimensions"); CHECK(features() & FEAT(VIRTIO_CONSOLE_F_MULTIPORT), - "Multiple ports support"); + "Multiple ports support"); CHECK(features() & FEAT(VIRTIO_CONSOLE_F_EMERG_WRITE), - "Emergency write support"); + "Emergency write support"); CHECK ((features() & needed_features) == needed_features, - "Negotiated needed features"); + "Negotiated needed features"); // Step 1 - Initialize queues auto success = assign_queue(0, (uint32_t) rx.queue_desc()); CHECK(success, "Receive queue assigned (0x%x) to device", - (uint32_t) rx.queue_desc()); + (uint32_t) rx.queue_desc()); success = assign_queue(1, (uint32_t) tx.queue_desc()); CHECK(success, "Transmit queue assigned (0x%x) to device", - (uint32_t) tx.queue_desc()); + (uint32_t) tx.queue_desc()); success = assign_queue(2, (uint32_t) ctl_rx.queue_desc()); CHECK(success, "Control rx queue assigned (0x%x) to device", - (uint32_t) ctl_rx.queue_desc()); + (uint32_t) ctl_rx.queue_desc()); success = assign_queue(3, (uint32_t) ctl_tx.queue_desc()); CHECK(success, "Control tx queue assigned (0x%x) to device", - (uint32_t) ctl_tx.queue_desc()); + (uint32_t) ctl_tx.queue_desc()); /* - success = assign_queue(4, (uint32_t) rx1.queue_desc()); - CHECK(success, "rx1 queue assigned (0x%x) to device", + success = assign_queue(4, (uint32_t) rx1.queue_desc()); + CHECK(success, "rx1 queue assigned (0x%x) to device", (uint32_t) rx1.queue_desc()); - success = assign_queue(5, (uint32_t) tx1.queue_desc()); - CHECK(success, "tx1 queue assigned (0x%x) to device", + success = assign_queue(5, (uint32_t) tx1.queue_desc()); + CHECK(success, "tx1 queue assigned (0x%x) to device", (uint32_t) tx1.queue_desc()); */ // Step 3 - Fill receive queue with buffers INFO("VirtioCon", "Queue size rx: %d tx: %d\n", - rx.size(), tx.size()); + rx.size(), tx.size()); // Get device configuration get_config(); @@ -93,7 +93,7 @@ VirtioCon::VirtioCon(hw::PCI_Device& d) // Done INFO("VirtioCon", "Console with size (%u, %u), %u ports", - config.cols, config.rows, config.max_nr_ports); + config.cols, config.rows, config.max_nr_ports); rx.kick(); } @@ -113,20 +113,20 @@ void VirtioCon::irq_handler() // Step 2. A) - one of the queues have changed if (isr & 1) - { - // This now means service RX & TX interchangeably - service_RX(); - } + { + // This now means service RX & TX interchangeably + service_RX(); + } // Step 2. B) if (isr & 2) - { - debug("\t Configuration change:\n"); + { + debug("\t Configuration change:\n"); - //debug("\t Old status: 0x%x\n", config.status); - get_config(); - //debug("\t New status: 0x%x \n", config.status); - } + //debug("\t Old status: 0x%x\n", config.status); + get_config(); + //debug("\t New status: 0x%x \n", config.status); + } IRQ_manager::eoi(irq()); } @@ -135,32 +135,32 @@ void VirtioCon::service_RX() rx.disable_interrupts(); while (rx.new_incoming()) - { - uint32_t len = 0; - char* condata = (char*) rx.dequeue(&len); + { + uint32_t len = 0; + char* condata = (char*) rx.dequeue(&len); - uint32_t dontcare; - rx.dequeue(&dontcare); + uint32_t dontcare; + rx.dequeue(&dontcare); - if (condata) - { - //printf("service_RX() received %u bytes from virtio console\n", len); - //printf("Data: %s\n", condata); - //vbr->handler(0, vbr->sector); - } - else - { - // acknowledgement - //printf("No data, just len = %d\n", len); + if (condata) + { + //printf("service_RX() received %u bytes from virtio console\n", len); + //printf("Data: %s\n", condata); + //vbr->handler(0, vbr->sector); + } + else + { + // acknowledgement + //printf("No data, just len = %d\n", len); + } } - } rx.enable_interrupts(); } void VirtioCon::write ( - const void* data, - size_t len) + const void* data, + size_t len) { char* heapdata = new char[len]; memcpy(heapdata, data, len); diff --git a/src/virtio/virtio.cpp b/src/virtio/virtio.cpp index 50cbe5c438..db78c0e026 100644 --- a/src/virtio/virtio.cpp +++ b/src/virtio/virtio.cpp @@ -85,9 +85,9 @@ Virtio::Virtio(hw::PCI_Device& dev) // 3. Set DRIVER status bit hw::outp(_iobase + VIRTIO_PCI_STATUS, - hw::inp(_iobase + VIRTIO_PCI_STATUS) | - VIRTIO_CONFIG_S_ACKNOWLEDGE | - VIRTIO_CONFIG_S_DRIVER); + hw::inp(_iobase + VIRTIO_PCI_STATUS) | + VIRTIO_CONFIG_S_ACKNOWLEDGE | + VIRTIO_CONFIG_S_DRIVER); // THE REMAINING STEPS MUST BE DONE IN A SUBCLASS @@ -119,8 +119,8 @@ Virtio::Virtio(hw::PCI_Device& dev) // uint32_t queue_size = hw::inpd(_iobase + 0x0C); /* printf(queue_size > 0 and queue_size != PCI_WTF ? - "\t [x] Queue Size : 0x%lx \n" : - "\t [ ] No qeuue Size? : 0x%lx \n" ,queue_size); */ + "\t [x] Queue Size : 0x%lx \n" : + "\t [ ] No qeuue Size? : 0x%lx \n" ,queue_size); */ } @@ -200,13 +200,13 @@ void Virtio::enable_irq_handler(){ } /** void Virtio::enable_irq_handler(IRQ_manager::irq_delegate d){ - //_irq=0; //Works only if IRQ2INTR(_irq), since 0 overlaps an exception. - //IRQ_manager::set_handler(IRQ2INTR(_irq), irq_virtio_entry); + //_irq=0; //Works only if IRQ2INTR(_irq), since 0 overlaps an exception. + //IRQ_manager::set_handler(IRQ2INTR(_irq), irq_virtio_entry); - IRQ_manager::subscribe(_irq,d); + IRQ_manager::subscribe(_irq,d); - IRQ_manager::enable_irq(_irq); - }*/ + IRQ_manager::enable_irq(_irq); + }*/ diff --git a/src/virtio/virtionet.cpp b/src/virtio/virtionet.cpp index c21b35decf..d957d94a62 100644 --- a/src/virtio/virtionet.cpp +++ b/src/virtio/virtionet.cpp @@ -300,9 +300,9 @@ void VirtioNet::service_queues(){ void VirtioNet::add_to_tx_buffer(net::Packet_ptr pckt){ if (transmit_queue_) - transmit_queue_->chain(pckt); - else - transmit_queue_ = pckt; + transmit_queue_->chain(pckt); + else + transmit_queue_ = pckt; #ifdef DEBUG size_t chain_length = 1; diff --git a/test/IDE/service.cpp b/test/IDE/service.cpp index 2639c6e95e..eb8453f91c 100644 --- a/test/IDE/service.cpp +++ b/test/IDE/service.cpp @@ -36,14 +36,14 @@ void Service::start() printf("MAGIC sig: 0x%x\n\n", mbr->magic); ide.read(0, 3, [] (hw::IDE::buffer_t data) { - static int i = 0; - uint8_t* buf = (uint8_t*)data.get(); - printf("Async read, Block %d:\n", i); - for (int i = 0; i < 512; i++) - printf("%x ", buf[i]); - printf("\n"); - i++; - }); + static int i = 0; + uint8_t* buf = (uint8_t*)data.get(); + printf("Async read, Block %d:\n", i); + for (int i = 0; i < 512; i++) + printf("%x ", buf[i]); + printf("\n"); + i++; + }); printf("Reading sync:\n"); mbr = (fs::MBR::mbr*)ide.read_sync(0).get(); @@ -51,10 +51,10 @@ void Service::start() printf("MAGIC sig: 0x%x\n\n", mbr->magic); ide.read(4, [] (hw::IDE::buffer_t data) { - uint8_t* buf = (uint8_t*)data.get(); - printf("Async read, Block %d:\n", 4); - for (int i = 0; i < 512; i++) - printf("%x ", buf[i]); - printf("\n"); - }); + uint8_t* buf = (uint8_t*)data.get(); + printf("Async read, Block %d:\n", 4); + for (int i = 0; i < 512; i++) + printf("%x ", buf[i]); + printf("\n"); + }); } diff --git a/test/IRQ_PIC/service.cpp b/test/IRQ_PIC/service.cpp index 47740ca8b8..a0b33a05b2 100644 --- a/test/IRQ_PIC/service.cpp +++ b/test/IRQ_PIC/service.cpp @@ -35,7 +35,7 @@ std::unique_ptr > inet; We're going to use the network- and keyboard interrupts for now, using UDP to trigger the NIC irq. - **/ +**/ void Service::start() { @@ -111,10 +111,10 @@ void Service::start() /** - A custom IRQ-handler for the serial port - It doesn't send eoi, but it should work anyway - since we're using auto-EOI-mode for IRQ < 8 (master) - */ + A custom IRQ-handler for the serial port + It doesn't send eoi, but it should work anyway + since we're using auto-EOI-mode for IRQ < 8 (master) + */ IRQ_manager::subscribe(4, [](){ uint16_t serial_port1 = 0x3F8; //IRQ_manager::eoi(4); @@ -127,11 +127,11 @@ void Service::start() /* - IRQ_manager::subscribe(11,[](){ - // Calling eoi here will turn the IRQ line on and loop forever. - IRQ_manager::eoi(11); - INFO("IRQ","Network IRQ\n"); - });*/ + IRQ_manager::subscribe(11,[](){ + // Calling eoi here will turn the IRQ line on and loop forever. + IRQ_manager::eoi(11); + INFO("IRQ","Network IRQ\n"); + });*/ // Enabling a timer causes freeze in debug mode, for some reason diff --git a/test/STL/service.cpp b/test/STL/service.cpp index b64d21b0cd..d08d5b3c3f 100644 --- a/test/STL/service.cpp +++ b/test/STL/service.cpp @@ -19,7 +19,7 @@ A very superficial test to verify that basic STL is working This is useful when we mess with / replace STL implementations - **/ +**/ #include @@ -41,60 +41,60 @@ int clock_gettime(clockid_t clk_id, struct timespec *tp){ using namespace std; const lest::test specification[] = -{ { - SCENARIO( "vectors can be sized and resized" "[vector]" ) { - - GIVEN( "A vector with some items" ) { - std::vector v( 5 ); - - EXPECT( v.size() == 5u ); - EXPECT( v.capacity() >= 5u ); - - WHEN( "the size is increased" ) { - v.resize( 10 ); - - THEN( "the size and capacity change" ) { - EXPECT( v.size() == 10u); - EXPECT( v.capacity() >= 10u ); - } - } - WHEN( "the size is reduced" ) { - v.resize( 0 ); - - THEN( "the size changes but not capacity" ) { - EXPECT( v.size() == 0u ); - EXPECT( v.capacity() >= 5u ); - } - } - WHEN( "more capacity is reserved" ) { - v.reserve( 10 ); - - THEN( "the capacity changes but not the size" ) { - EXPECT( v.size() == 5u ); - EXPECT( v.capacity() >= 10u ); - } - WHEN( "less capacity is reserved again" ) { - v.reserve( 7 ); - - THEN( "capacity remains unchanged" ) { - EXPECT( v.capacity() >= 10u ); - } - } - } - WHEN( "less capacity is reserved" ) { - v.reserve( 0 ); - - THEN( "neither size nor capacity are changed" ) { - EXPECT( v.size() == 5u ); - EXPECT( v.capacity() >= 5u ); - } - } + SCENARIO( "vectors can be sized and resized" "[vector]" ) + { + + GIVEN( "A vector with some items" ) { + std::vector v( 5 ); + + EXPECT( v.size() == 5u ); + EXPECT( v.capacity() >= 5u ); + + WHEN( "the size is increased" ) { + v.resize( 10 ); + + THEN( "the size and capacity change" ) { + EXPECT( v.size() == 10u); + EXPECT( v.capacity() >= 10u ); + } + } + WHEN( "the size is reduced" ) { + v.resize( 0 ); + + THEN( "the size changes but not capacity" ) { + EXPECT( v.size() == 0u ); + EXPECT( v.capacity() >= 5u ); + } + } + WHEN( "more capacity is reserved" ) { + v.reserve( 10 ); + + THEN( "the capacity changes but not the size" ) { + EXPECT( v.size() == 5u ); + EXPECT( v.capacity() >= 10u ); + } + WHEN( "less capacity is reserved again" ) { + v.reserve( 7 ); + + THEN( "capacity remains unchanged" ) { + EXPECT( v.capacity() >= 10u ); + } + } + } + WHEN( "less capacity is reserved" ) { + v.reserve( 0 ); + + THEN( "neither size nor capacity are changed" ) { + EXPECT( v.size() == 5u ); + EXPECT( v.capacity() >= 5u ); + } + } + } } } - } -}; + }; #define MYINFO(X,...) INFO("Test STL",X,##__VA_ARGS__) diff --git a/test/bufstore/service.cpp b/test/bufstore/service.cpp index 272875e72f..2643e76d7a 100644 --- a/test/bufstore/service.cpp +++ b/test/bufstore/service.cpp @@ -64,7 +64,7 @@ void Service::start() // Reinitialize the first packet packet = std::make_shared(bufstore_.get_offset_buffer(), - bufstore_.offset_bufsize(), 1500, release); + bufstore_.offset_bufsize(), 1500, release); CHECKSERT(bufstore_.buffers_available() == bufcount_ - 1, "Bufcount is now %i", bufcount_ -1); @@ -84,8 +84,8 @@ void Service::start() while(tail && i < bufcount_ - 1 ) { tail = tail->detach_tail(); CHECKSERT(bufstore_.buffers_available() == i, - "Bufcount is now %i == %i", i, - bufstore_.buffers_available()); + "Bufcount is now %i == %i", i, + bufstore_.buffers_available()); i++; } diff --git a/test/fat/fat16.cpp b/test/fat/fat16.cpp index 3777431b5c..dfa010bf25 100644 --- a/test/fat/fat16.cpp +++ b/test/fat/fat16.cpp @@ -35,44 +35,44 @@ void Service::start() // auto-mount filesystem disk->mount( - [disk] (fs::error_t err) - { - CHECKSERT(!err, "Filesystem auto-mounted"); + [disk] (fs::error_t err) + { + CHECKSERT(!err, "Filesystem auto-mounted"); - auto& fs = disk->fs(); - printf("\t\t%s filesystem\n", fs.name().c_str()); + auto& fs = disk->fs(); + printf("\t\t%s filesystem\n", fs.name().c_str()); - auto vec = fs::new_shared_vector(); - err = fs.ls("/", vec); - CHECKSERT(!err, "List root directory"); + auto vec = fs::new_shared_vector(); + err = fs.ls("/", vec); + CHECKSERT(!err, "List root directory"); - CHECKSERT(vec->size() == 1, "Exactly one ent in root dir"); + CHECKSERT(vec->size() == 1, "Exactly one ent in root dir"); - auto& e = vec->at(0); - CHECKSERT(e.is_file(), "Ent is a file"); - CHECKSERT(e.name() == "banana.txt", "Ents name is 'banana.txt'"); + auto& e = vec->at(0); + CHECKSERT(e.is_file(), "Ent is a file"); + CHECKSERT(e.name() == "banana.txt", "Ents name is 'banana.txt'"); - }); + }); // re-mount on VBR1 disk->mount(disk->VBR1, - [disk] (fs::error_t err) - { - CHECKSERT(!err, "Filesystem mounted on VBR1"); + [disk] (fs::error_t err) + { + CHECKSERT(!err, "Filesystem mounted on VBR1"); - // verify that we can read file - auto& fs = disk->fs(); - auto ent = fs.stat("/banana.txt"); - CHECKSERT(ent.is_valid(), "Stat file in root dir"); - CHECKSERT(ent.is_file(), "Entity is file"); - CHECKSERT(!ent.is_dir(), "Entity is not directory"); - CHECKSERT(ent.name() == "banana.txt", "Name is 'banana.txt'"); + // verify that we can read file + auto& fs = disk->fs(); + auto ent = fs.stat("/banana.txt"); + CHECKSERT(ent.is_valid(), "Stat file in root dir"); + CHECKSERT(ent.is_file(), "Entity is file"); + CHECKSERT(!ent.is_dir(), "Entity is not directory"); + CHECKSERT(ent.name() == "banana.txt", "Name is 'banana.txt'"); - // try reading banana-file - auto buf = fs.read(ent, 0, ent.size); - std::string banana((char*) buf.buffer.get(), buf.len); + // try reading banana-file + auto buf = fs.read(ent, 0, ent.size); + std::string banana((char*) buf.buffer.get(), buf.len); - std::string internal_banana = - R"( ____ ___ + std::string internal_banana = + R"( ____ ___ | _ \ ___ _ _.' _ `. _ | [_) )' _ `._ _ ___ ! \ | | (_) | _ |:;.| _ <| (_) | \ | |' _ `| \| | _ | .:;| @@ -81,11 +81,11 @@ void Service::start() !::, `-!_| | | |\ | | | | | \ !_!.' ':;! !::; ":;:!.!.\_!_!_!.!-'-':;:'' '''! ';:' `::;::;' '' ., . - `: .,. `' .::... . .::;::;' - `..:;::;:.. ::;::;:;:;, :;::;' + `: .,. `' .::... . .::;::;' + `..:;::;:.. ::;::;:;:;, :;::;' "-:;::;:;: ':;::;:'' ;.-' ""`---...________...---'"" -)"; + )"; printf("%s\n", internal_banana.c_str()); CHECKSERT(banana == internal_banana, "Correct banana #1"); diff --git a/test/fat/fat32.cpp b/test/fat/fat32.cpp index c8e560e964..d0bfa744c1 100644 --- a/test/fat/fat32.cpp +++ b/test/fat/fat32.cpp @@ -24,7 +24,7 @@ std::shared_ptr disk; std::string internal_banana = - R"( ____ ___ + R"( ____ ___ | _ \ ___ _ _.' _ `. _ | [_) )' _ `._ _ ___ ! \ | | (_) | _ |:;.| _ <| (_) | \ | |' _ `| \| | _ | .:;| @@ -33,11 +33,11 @@ std::string internal_banana = !::, `-!_| | | |\ | | | | | \ !_!.' ':;! !::; ":;:!.!.\_!_!_!.!-'-':;:'' '''! ';:' `::;::;' '' ., . - `: .,. `' .::... . .::;::;' - `..:;::;:.. ::;::;:;:;, :;::;' + `: .,. `' .::... . .::;::;' + `..:;::;:.. ::;::;:;:;, :;::;' "-:;::;:;: ':;::;:'' ;.-' ""`---...________...---'"" -)"; + )"; void Service::start() { diff --git a/test/memdisk/bigdisk.cpp b/test/memdisk/bigdisk.cpp index d04b021d5e..3d76c9f528 100644 --- a/test/memdisk/bigdisk.cpp +++ b/test/memdisk/bigdisk.cpp @@ -38,9 +38,9 @@ void Service::start() // verify nothing bad happened CHECK(!!(buf), "Buffer for sector 0 is valid"); if (!buf) - { - panic("Failed to read sector 0 on memdisk device\n"); - } + { + panic("Failed to read sector 0 on memdisk device\n"); + } // verify MBR has signature const uint8_t* mbr = buf.get(); assert(mbr[0x1FE] == 0x55); diff --git a/test/memdisk/twosector.cpp b/test/memdisk/twosector.cpp index a0e3357bb4..1c2694f9c2 100644 --- a/test/memdisk/twosector.cpp +++ b/test/memdisk/twosector.cpp @@ -38,9 +38,9 @@ void Service::start() // verify nothing bad happened CHECK(!!(buf), "Buffer for sector 0 is valid"); if (!buf) - { - panic("Failed to read sector 0 on memdisk device\n"); - } + { + panic("Failed to read sector 0 on memdisk device\n"); + } // convert to text std::string text((const char*) buf.get(), disk->dev().block_size()); // verify that the sector contents matches the test string @@ -53,7 +53,7 @@ void Service::start() // verify that reading outside of disk returns a 0x0 pointer buf = disk->dev().read_sync(disk->dev().size()); CHECK(!buf, "Buffer outside of disk range (sector=%llu) is 0x0", - disk->dev().size()); + disk->dev().size()); assert(!buf); INFO("MemDisk", "SUCCESS"); diff --git a/test/tcp/service.cpp b/test/tcp/service.cpp index b8018874b7..479626efa4 100644 --- a/test/tcp/service.cpp +++ b/test/tcp/service.cpp @@ -30,23 +30,23 @@ std::unique_ptr> inet; std::shared_ptr client; /* - TEST VARIABLES + TEST VARIABLES */ TCP::Port - TEST1{8081}, TEST2{8082}, TEST3{8083}, TEST4{8084}, TEST5{8085}; +TEST1{8081}, TEST2{8082}, TEST3{8083}, TEST4{8084}, TEST5{8085}; using HostAddress = std::pair; HostAddress - TEST_ADDR_TIME{"india.colorado.edu", 13}; +TEST_ADDR_TIME{"india.colorado.edu", 13}; std::string - small, big, huge; +small, big, huge; int - S{150}, B{1500}, H{15000}; +S{150}, B{1500}, H{15000}; std::string - TEST_STR {"1337"}; +TEST_STR {"1337"}; size_t buffers_available{0}; @@ -55,84 +55,84 @@ size_t buffers_available{0}; milliseconds MSL_TEST = 5s; /* - TEST: Release of resources/clean up. + TEST: Release of resources/clean up. */ void FINISH_TEST() { - INFO("TEST", "Started 3 x MSL timeout."); - hw::PIT::instance().onTimeout(3 * MSL_TEST, [] { - INFO("TEST", "Verify release of resources"); - CHECK(inet->tcp().activeConnections() == 0, "tcp.activeConnections() == 0"); - CHECK(inet->buffers_available() == buffers_available, - "inet->buffers_available() == buffers_available"); - INFO("Buffers available", "%u", inet->buffers_available()); - printf("# TEST DONE #\n"); - }); + INFO("TEST", "Started 3 x MSL timeout."); + hw::PIT::instance().onTimeout(3 * MSL_TEST, [] { + INFO("TEST", "Verify release of resources"); + CHECK(inet->tcp().activeConnections() == 0, "tcp.activeConnections() == 0"); + CHECK(inet->buffers_available() == buffers_available, + "inet->buffers_available() == buffers_available"); + INFO("Buffers available", "%u", inet->buffers_available()); + printf("# TEST DONE #\n"); + }); } /* - TEST: Outgoing Internet Connection + TEST: Outgoing Internet Connection */ void OUTGOING_TEST_INTERNET(const HostAddress& address) { - auto port = address.second; - INFO("TEST", "Outgoing Internet Connection (%s:%u)", address.first.c_str(), address.second); - inet->resolve(address.first, [port](auto&, auto&, auto ip_address) { - CHECK(ip_address != 0, "Resolved host"); - - if(ip_address != 0) { - inet->tcp().connect(ip_address, port) - ->onConnect([](Connection_ptr conn) { - CHECK(true, "Connected"); - conn->read(1024, [](buffer_t, size_t n) { - CHECK(n > 0, "Received data"); - }); - }) - .onError([](Connection_ptr, TCP::TCPException err) { - CHECK(false, "Error occured: %s", err.what()); - }); - } - }); + auto port = address.second; + INFO("TEST", "Outgoing Internet Connection (%s:%u)", address.first.c_str(), address.second); + inet->resolve(address.first, [port](auto&, auto&, auto ip_address) { + CHECK(ip_address != 0, "Resolved host"); + + if(ip_address != 0) { + inet->tcp().connect(ip_address, port) + ->onConnect([](Connection_ptr conn) { + CHECK(true, "Connected"); + conn->read(1024, [](buffer_t, size_t n) { + CHECK(n > 0, "Received data"); + }); + }) + .onError([](Connection_ptr, TCP::TCPException err) { + CHECK(false, "Error occured: %s", err.what()); + }); + } + }); } /* - TEST: Outgoing Connection to Host + TEST: Outgoing Connection to Host */ void OUTGOING_TEST(TCP::Socket outgoing) { - INFO("TEST", "Outgoing Connection (%s)", outgoing.to_string().c_str()); - inet->tcp().connect(outgoing) - ->onConnect([](Connection_ptr conn) { - conn->write(small.data(), small.size()); - conn->read(small.size(), [](buffer_t buffer, size_t n) { - CHECK(std::string((char*)buffer.get(), n) == small, "conn->read() == small"); + INFO("TEST", "Outgoing Connection (%s)", outgoing.to_string().c_str()); + inet->tcp().connect(outgoing) + ->onConnect([](Connection_ptr conn) { + conn->write(small.data(), small.size()); + conn->read(small.size(), [](buffer_t buffer, size_t n) { + CHECK(std::string((char*)buffer.get(), n) == small, "conn->read() == small"); + }); + }) + .onDisconnect([](Connection_ptr, TCP::Connection::Disconnect) { + CHECK(true, "Connection closed by server"); + + OUTGOING_TEST_INTERNET(TEST_ADDR_TIME); }); - }) - .onDisconnect([](Connection_ptr, TCP::Connection::Disconnect) { - CHECK(true, "Connection closed by server"); - - OUTGOING_TEST_INTERNET(TEST_ADDR_TIME); - }); } // Used to send big data struct Buffer { - size_t written, read; - char* data; - const size_t size; + size_t written, read; + char* data; + const size_t size; - Buffer(size_t length) : - written(0), read(0), data(new char[length]), size(length) {} + Buffer(size_t length) : + written(0), read(0), data(new char[length]), size(length) {} - ~Buffer() { delete[] data; } + ~Buffer() { delete[] data; } - std::string str() { return {data, size};} + std::string str() { return {data, size};} }; void Service::start() { - for(int i = 0; i < S; i++) small += TEST_STR; - for(int i = 0; i < B; i++) big += TEST_STR; - for(int i = 0; i < H; i++) huge += TEST_STR; + for(int i = 0; i < S; i++) small += TEST_STR; + for(int i = 0; i < B; i++) big += TEST_STR; + for(int i = 0; i < H; i++) huge += TEST_STR; - hw::Nic& eth0 = hw::Dev::eth<0,VirtioNet>(); + hw::Nic& eth0 = hw::Dev::eth<0,VirtioNet>(); inet = std::make_unique>(eth0); inet->network_config( {{ 10,0,0,42 }}, // IP @@ -140,113 +140,113 @@ void Service::start() {{ 10,0,0,1 }}, // Gateway {{ 8,8,8,8 }} ); // DNS - buffers_available = inet->buffers_available(); + buffers_available = inet->buffers_available(); INFO("Buffers available", "%u", inet->buffers_available()); - auto& tcp = inet->tcp(); - // reduce test duration - tcp.set_MSL(MSL_TEST); - - /* - TEST: Send and receive small string. - */ - INFO("TEST", "Listeners and connections allocation."); - - /* - TEST: Nothing should be allocated. - */ - CHECK(tcp.openPorts() == 0, "tcp.openPorts() == 0"); - CHECK(tcp.activeConnections() == 0, "tcp.activeConnections() == 0"); - - tcp.bind(TEST1).onConnect([](Connection_ptr conn) { - INFO("TEST", "SMALL string (%u)", small.size()); - conn->read(small.size(), [conn](buffer_t buffer, size_t n) { - CHECK(inet->buffers_available() < buffers_available, - "inet->buffers_available() < buffers_available"); - CHECK(std::string((char*)buffer.get(), n) == small, "conn.read() == small"); - conn->close(); - }); - conn->write(small.data(), small.size()); - INFO("Buffers available", "%u", inet->buffers_available()); + auto& tcp = inet->tcp(); + // reduce test duration + tcp.set_MSL(MSL_TEST); + + /* + TEST: Send and receive small string. + */ + INFO("TEST", "Listeners and connections allocation."); + + /* + TEST: Nothing should be allocated. + */ + CHECK(tcp.openPorts() == 0, "tcp.openPorts() == 0"); + CHECK(tcp.activeConnections() == 0, "tcp.activeConnections() == 0"); + + tcp.bind(TEST1).onConnect([](Connection_ptr conn) { + INFO("TEST", "SMALL string (%u)", small.size()); + conn->read(small.size(), [conn](buffer_t buffer, size_t n) { + CHECK(inet->buffers_available() < buffers_available, + "inet->buffers_available() < buffers_available"); + CHECK(std::string((char*)buffer.get(), n) == small, "conn.read() == small"); + conn->close(); }); - - /* - TEST: Server should be bound. - */ - CHECK(tcp.openPorts() == 1, "tcp.openPorts() == 1"); - - /* - TEST: Send and receive big string. - */ - tcp.bind(TEST2).onConnect([](Connection_ptr conn) { - INFO("TEST", "BIG string (%u)", big.size()); - auto response = std::make_shared(); - conn->read(big.size(), [response, conn](buffer_t buffer, size_t n) { - *response += std::string((char*)buffer.get(), n); - if(response->size() == big.size()) { - bool OK = (*response == big); - CHECK(OK, "conn.read() == big"); - conn->close(); - } - }); - conn->write(big.data(), big.size()); - INFO("Buffers available", "%u", inet->buffers_available()); + conn->write(small.data(), small.size()); + INFO("Buffers available", "%u", inet->buffers_available()); + }); + + /* + TEST: Server should be bound. + */ + CHECK(tcp.openPorts() == 1, "tcp.openPorts() == 1"); + + /* + TEST: Send and receive big string. + */ + tcp.bind(TEST2).onConnect([](Connection_ptr conn) { + INFO("TEST", "BIG string (%u)", big.size()); + auto response = std::make_shared(); + conn->read(big.size(), [response, conn](buffer_t buffer, size_t n) { + *response += std::string((char*)buffer.get(), n); + if(response->size() == big.size()) { + bool OK = (*response == big); + CHECK(OK, "conn.read() == big"); + conn->close(); + } }); - - /* - TEST: Send and receive huge string. - */ - tcp.bind(TEST3).onConnect([](Connection_ptr conn) { - INFO("TEST", "HUGE string (%u)", huge.size()); - auto temp = std::make_shared(huge.size()); - conn->read(huge.size(), [temp, conn](buffer_t buffer, size_t n) { - memcpy(temp->data + temp->written, buffer.get(), n); - temp->written += n; - - // when all expected data is read - if(temp->written == huge.size()) { - bool OK = (temp->str() == huge); - CHECK(OK, "conn.read() == huge"); - conn->close(); - } - }); - conn->write(huge.data(), huge.size()); - INFO("Buffers available", "%u", inet->buffers_available()); - }); - - /* - TEST: More servers should be bound. - */ - CHECK(tcp.openPorts() == 3, "tcp.openPorts() == 3"); - - /* - TEST: Connection (Status etc.) and Active Close - */ - tcp.bind(TEST4).onConnect([](Connection_ptr conn) { - INFO("TEST","Connection"); - // There should be at least one connection. - CHECK(inet->tcp().activeConnections() > 0, "tcp.activeConnections() > 0"); - // Test if connected. - CHECK(conn->is_connected(), "conn.is_connected()"); - // Test if writable. - CHECK(conn->is_writable(), "conn.is_writable()"); - // Test if state is ESTABLISHED. - CHECK(conn->is_state({"ESTABLISHED"}), "conn.is_state(ESTABLISHED)"); - - INFO("TEST", "Active close"); - // Test for active close. - conn->close(); - CHECK(!conn->is_writable(), "!conn->is_writable()"); - CHECK(conn->is_state({"FIN-WAIT-1"}), "conn.is_state(FIN-WAIT-1)"); - }) - .onDisconnect([](Connection_ptr conn, TCP::Connection::Disconnect) { - CHECK(conn->is_state({"FIN-WAIT-2"}), "conn.is_state(FIN-WAIT-2)"); - hw::PIT::instance().onTimeout(1s,[conn]{ - CHECK(conn->is_state({"TIME-WAIT"}), "conn.is_state(TIME-WAIT)"); - - OUTGOING_TEST({inet->router(), TEST5}); - }); - - hw::PIT::instance().onTimeout(5s, [] { FINISH_TEST(); }); + conn->write(big.data(), big.size()); + INFO("Buffers available", "%u", inet->buffers_available()); + }); + + /* + TEST: Send and receive huge string. + */ + tcp.bind(TEST3).onConnect([](Connection_ptr conn) { + INFO("TEST", "HUGE string (%u)", huge.size()); + auto temp = std::make_shared(huge.size()); + conn->read(huge.size(), [temp, conn](buffer_t buffer, size_t n) { + memcpy(temp->data + temp->written, buffer.get(), n); + temp->written += n; + + // when all expected data is read + if(temp->written == huge.size()) { + bool OK = (temp->str() == huge); + CHECK(OK, "conn.read() == huge"); + conn->close(); + } }); + conn->write(huge.data(), huge.size()); + INFO("Buffers available", "%u", inet->buffers_available()); + }); + + /* + TEST: More servers should be bound. + */ + CHECK(tcp.openPorts() == 3, "tcp.openPorts() == 3"); + + /* + TEST: Connection (Status etc.) and Active Close + */ + tcp.bind(TEST4).onConnect([](Connection_ptr conn) { + INFO("TEST","Connection"); + // There should be at least one connection. + CHECK(inet->tcp().activeConnections() > 0, "tcp.activeConnections() > 0"); + // Test if connected. + CHECK(conn->is_connected(), "conn.is_connected()"); + // Test if writable. + CHECK(conn->is_writable(), "conn.is_writable()"); + // Test if state is ESTABLISHED. + CHECK(conn->is_state({"ESTABLISHED"}), "conn.is_state(ESTABLISHED)"); + + INFO("TEST", "Active close"); + // Test for active close. + conn->close(); + CHECK(!conn->is_writable(), "!conn->is_writable()"); + CHECK(conn->is_state({"FIN-WAIT-1"}), "conn.is_state(FIN-WAIT-1)"); + }) + .onDisconnect([](Connection_ptr conn, TCP::Connection::Disconnect) { + CHECK(conn->is_state({"FIN-WAIT-2"}), "conn.is_state(FIN-WAIT-2)"); + hw::PIT::instance().onTimeout(1s,[conn]{ + CHECK(conn->is_state({"TIME-WAIT"}), "conn.is_state(TIME-WAIT)"); + + OUTGOING_TEST({inet->router(), TEST5}); + }); + + hw::PIT::instance().onTimeout(5s, [] { FINISH_TEST(); }); + }); } diff --git a/test/term/term.cpp b/test/term/term.cpp index a1710ff0fe..df37cbbae0 100644 --- a/test/term/term.cpp +++ b/test/term/term.cpp @@ -33,10 +33,10 @@ void Service::start() hw::Nic& eth0 = hw::Dev::eth<0,VirtioNet>(); inet = std::make_unique >(eth0); inet->network_config( - {{ 10,0,0,42 }}, // IP - {{ 255,255,255,0 }}, // Netmask - {{ 10,0,0,1 }}, // Gateway - {{ 8,8,8,8 }} ); // DNS + {{ 10,0,0,42 }}, // IP + {{ 255,255,255,0 }}, // Netmask + {{ 10,0,0,1 }}, // Gateway + {{ 8,8,8,8 }} ); // DNS INFO("TERM", "Running tests for Terminal"); auto disk = fs::new_shared_memdisk(); @@ -44,24 +44,24 @@ void Service::start() // auto-mount filesystem disk->mount( - [disk] (fs::error_t err) - { - CHECKSERT(!err, "Filesystem auto-mounted"); + [disk] (fs::error_t err) + { + CHECKSERT(!err, "Filesystem auto-mounted"); - /// terminal /// - #define SERVICE_TELNET 23 - auto& tcp = inet->tcp(); - auto& server = tcp.bind(SERVICE_TELNET); - server.onConnect( - [disk] (auto client) - { - // create terminal with open TCP connection - term = std::make_unique (client); - term->add_disk_commands(disk); - }); + /// terminal /// +#define SERVICE_TELNET 23 + auto& tcp = inet->tcp(); + auto& server = tcp.bind(SERVICE_TELNET); + server.onConnect( + [disk] (auto client) + { + // create terminal with open TCP connection + term = std::make_unique (client); + term->add_disk_commands(disk); + }); - INFO("TERM", "Connect to terminal with $ telnet %s ", - inet->ip_addr().str().c_str()); - /// terminal /// - }); + INFO("TERM", "Connect to terminal with $ telnet %s ", + inet->ip_addr().str().c_str()); + /// terminal /// + }); } diff --git a/test/transmit/service.cpp b/test/transmit/service.cpp index 9992ab4442..66c8dca086 100644 --- a/test/transmit/service.cpp +++ b/test/transmit/service.cpp @@ -48,7 +48,7 @@ void Service::start() auto& sock = inet->udp().bind(port); sock.onRead([&] (UDP::Socket& conn, UDP::addr_t addr, UDP::port_t port, - const char* data, int len) -> int { + const char* data, int len) -> int { string received = std::string(data,len-1); INFO("Test 2","Starting UDP-test (got UDP data from %s: %i: '%s')", addr.str().c_str(), port, received.c_str()); diff --git a/test/vga/vga.cpp b/test/vga/vga.cpp index 5de0de44a7..6e61dffdac 100644 --- a/test/vga/vga.cpp +++ b/test/vga/vga.cpp @@ -67,22 +67,22 @@ void Service::start() auto test1_1 = [] () -> bool - { - if ( c >= '4') { - hw::PIT::instance().onRepeatedTimeout(100ms, [] { - vga.newline(); - iterations++; - if (iterations == 24) - write_goodbye(); + { + if ( c >= '4') { + hw::PIT::instance().onRepeatedTimeout(100ms, [] { + vga.newline(); + iterations++; + if (iterations == 24) + write_goodbye(); - }, + }, - [] { - return iterations < 36; - }); - } - return c < '4'; - }; + [] { + return iterations < 36; + }); + } + return c < '4'; + }; auto test2 = [](){ diff --git a/vmbuild/vmbuild.cpp b/vmbuild/vmbuild.cpp index 564c77549a..9e5fd7cb82 100644 --- a/vmbuild/vmbuild.cpp +++ b/vmbuild/vmbuild.cpp @@ -107,13 +107,13 @@ int main(int argc, char** argv) { // Bochs requires old-school disk specifications. // sectors=cyls*heads*spt (sectors per track) /* - const int spt = 63; - auto disk_tracks = - (img_size_sect % spt) == 0 ? - (img_size_sect / spt) : // Sector count is a multiple of 63 - (img_size_sect / spt) + 1; // There's a remainder, so we add one track + const int spt = 63; + auto disk_tracks = + (img_size_sect % spt) == 0 ? + (img_size_sect / spt) : // Sector count is a multiple of 63 + (img_size_sect / spt) + 1; // There's a remainder, so we add one track - const decltype(img_size_sect) disksize {disk_tracks * spt * SECT_SIZE}; + const decltype(img_size_sect) disksize {disk_tracks * spt * SECT_SIZE}; */ const auto disksize = (img_size_sect + extra_sectors) * SECT_SIZE; @@ -127,9 +127,9 @@ int main(int argc, char** argv) { } cout << "Creating disk of size: " - //<< "Cyls: " << cylinders << "\n" - //<< "Heads: " << heads << "\n" - //<< "Sec/Tr: " << spt << "\n" + //<< "Cyls: " << cylinders << "\n" + //<< "Heads: " << heads << "\n" + //<< "Sec/Tr: " << spt << "\n" << "=> " << (disksize / SECT_SIZE) << " sectors\n" << "=> " << disksize << " bytes\n"; @@ -154,7 +154,7 @@ int main(int argc, char** argv) { cout << "Signature: "; for(int i {0}; i < EI_NIDENT; ++i) { - cout << elf_header->e_ident[i]; + cout << elf_header->e_ident[i]; } cout << "\nType: " << ((elf_header->e_type == ET_EXEC) ? " ELF Executable\n" : "Non-executable\n"); From c05bc6e5273918e53679171e256dcb1b2985da81 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sat, 2 Apr 2016 13:53:48 +0200 Subject: [PATCH 092/311] Updated STL test. Fix #440 --- test/STL/Makefile | 2 +- test/STL/README.md | 7 +++++++ test/STL/test.sh | 5 +++++ 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 test/STL/README.md create mode 100755 test/STL/test.sh diff --git a/test/STL/Makefile b/test/STL/Makefile index 12d0723356..542c71117b 100644 --- a/test/STL/Makefile +++ b/test/STL/Makefile @@ -3,7 +3,7 @@ ################################################# # The name of your service -SERVICE = Test_STL +SERVICE = test_STL SERVICE_NAME = IncludeOS basic STL test # Your service parts diff --git a/test/STL/README.md b/test/STL/README.md new file mode 100644 index 0000000000..12c09bd023 --- /dev/null +++ b/test/STL/README.md @@ -0,0 +1,7 @@ +# Test basics of C++ Standard Template Library +This just tests a fraction of STL functionality, but it's here to just verify that basic STL support is in place and working. Useful i.e. when working on porting STL or switching implementation (e.g. to EASTL) + +Sucess: Outputs SUCCESS if all tests pass +Fail: Panic if any test fails + +NOTE: This test uses the `lest` unit test framework as well for some tests. The result of those tests will also be reported. diff --git a/test/STL/test.sh b/test/STL/test.sh new file mode 100755 index 0000000000..14e5d77c81 --- /dev/null +++ b/test/STL/test.sh @@ -0,0 +1,5 @@ +#!/bin/bash +source ../test_base + +make +start test_STL.img From b121271440ade4e9204e1bb609f93e2bdf92fe80 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Sun, 3 Apr 2016 16:54:18 +0200 Subject: [PATCH 093/311] test: Work on term test --- test/term/term.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/term/term.cpp b/test/term/term.cpp index a1710ff0fe..8bace62ea7 100644 --- a/test/term/term.cpp +++ b/test/term/term.cpp @@ -58,6 +58,26 @@ void Service::start() // create terminal with open TCP connection term = std::make_unique (client); term->add_disk_commands(disk); + + /// work on network commands /// + // add 'ifconfig' command + term->add( + "ifconfig", "Configure a network interface", + [] (const std::vector&) -> int + { + term->write("Link encap:%s\r\n", inet->tcp().status().c_str()); + return 0; + }); + // add 'netstat' command + term->add( + "netstat", "Print network connections", + [] (const std::vector&) -> int + { + term->write("%s\r\n", inet->tcp().status().c_str()); + return 0; + }); + + }); INFO("TERM", "Connect to terminal with $ telnet %s ", From a47afe0f103030cee4d192a9c0abc4943895ab49 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Sun, 3 Apr 2016 16:57:15 +0200 Subject: [PATCH 094/311] makefile: PHONY make commands --- src/seed/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/src/seed/Makefile b/src/seed/Makefile index fd2e3e338d..f34c510519 100644 --- a/src/seed/Makefile +++ b/src/seed/Makefile @@ -71,6 +71,7 @@ DEPS = $(OBJS:.o=.d) ################################################### # A complete build includes: # - a "service", to be linked with OS-objects (OS included) +.PHONY: all stripped debug debug-info debug-all memdisk service all: service From 103fb5a9752d40c163fd7c3be333f74c32a5cf9f Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Sun, 3 Apr 2016 18:01:19 +0200 Subject: [PATCH 095/311] net: Move arp and ip4 into ip4 folder --- api/net/dns/client.hpp | 4 ++-- api/net/dns/dns.hpp | 6 +++--- api/net/inet4.hpp | 4 ++-- api/net/{ => ip4}/arp.hpp | 6 +++--- api/net/ip4/icmpv4.hpp | 2 +- api/net/{ => ip4}/ip4.hpp | 0 api/net/ip4/packet_arp.hpp | 2 +- api/net/ip4/udp.hpp | 2 +- api/net/packet.hpp | 4 ++-- api/net/tcp.hpp | 6 +++--- src/Makefile | 2 +- src/net/{ => ip4}/arp.cpp | 2 +- src/net/{ => ip4}/ip4.cpp | 2 +- test/tcp/test.sh | 0 14 files changed, 21 insertions(+), 21 deletions(-) rename api/net/{ => ip4}/arp.hpp (98%) rename api/net/{ => ip4}/ip4.hpp (100%) rename src/net/{ => ip4}/arp.cpp (99%) rename src/net/{ => ip4}/ip4.cpp (99%) mode change 100644 => 100755 test/tcp/test.sh diff --git a/api/net/dns/client.hpp b/api/net/dns/client.hpp index 93b61d59c8..209e0d14f4 100644 --- a/api/net/dns/client.hpp +++ b/api/net/dns/client.hpp @@ -18,8 +18,8 @@ #ifndef NET_DNS_CLIENT_HPP #define NET_DNS_CLIENT_HPP -#include "../inet.hpp" -#include "../ip4.hpp" +#include +#include #include namespace net diff --git a/api/net/dns/dns.hpp b/api/net/dns/dns.hpp index d54a11c02a..063ba55630 100644 --- a/api/net/dns/dns.hpp +++ b/api/net/dns/dns.hpp @@ -15,8 +15,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef NET_DNS_HPP -#define NET_DNS_HPP +#ifndef NET_DNS_DNS_HPP +#define NET_DNS_DNS_HPP /** * DNS message @@ -49,7 +49,7 @@ * **/ -#include // UDP headers +#include // IP4::addr #include #include #include diff --git a/api/net/inet4.hpp b/api/net/inet4.hpp index 36f0a3db10..fc55e4f463 100644 --- a/api/net/inet4.hpp +++ b/api/net/inet4.hpp @@ -23,8 +23,8 @@ #include #include "inet.hpp" #include "ethernet.hpp" -#include "arp.hpp" -#include "ip4.hpp" +#include "ip4/arp.hpp" +#include "ip4/ip4.hpp" #include "ip4/udp.hpp" #include "dns/client.hpp" #include "tcp.hpp" diff --git a/api/net/arp.hpp b/api/net/ip4/arp.hpp similarity index 98% rename from api/net/arp.hpp rename to api/net/ip4/arp.hpp index b0c81c1c2b..771855a04f 100644 --- a/api/net/arp.hpp +++ b/api/net/ip4/arp.hpp @@ -16,14 +16,14 @@ // limitations under the License. #pragma once -#ifndef NET_ARP_HPP -#define NET_ARP_HPP +#ifndef NET_IP4_ARP_HPP +#define NET_IP4_ARP_HPP #include #include #include -#include +#include "ip4.hpp" namespace net { diff --git a/api/net/ip4/icmpv4.hpp b/api/net/ip4/icmpv4.hpp index d0787fd783..da9c6c872b 100644 --- a/api/net/ip4/icmpv4.hpp +++ b/api/net/ip4/icmpv4.hpp @@ -19,7 +19,7 @@ #define NET_IP4_ICMPv4_HPP #include "../inet.hpp" -#include "../ip4.hpp" +#include "ip4.hpp" namespace net { diff --git a/api/net/ip4.hpp b/api/net/ip4/ip4.hpp similarity index 100% rename from api/net/ip4.hpp rename to api/net/ip4/ip4.hpp diff --git a/api/net/ip4/packet_arp.hpp b/api/net/ip4/packet_arp.hpp index ca1c82f39a..5091725e9d 100644 --- a/api/net/ip4/packet_arp.hpp +++ b/api/net/ip4/packet_arp.hpp @@ -19,7 +19,7 @@ #ifndef NET_IP4_PACKET_ARP #define NET_IP4_PACKET_ARP -#include "../arp.hpp" +#include "arp.hpp" #include namespace net diff --git a/api/net/ip4/udp.hpp b/api/net/ip4/udp.hpp index be016c3b87..0495259385 100644 --- a/api/net/ip4/udp.hpp +++ b/api/net/ip4/udp.hpp @@ -21,7 +21,7 @@ #include #include "../inet.hpp" -#include "../ip4.hpp" +#include "ip4.hpp" namespace net { diff --git a/api/net/packet.hpp b/api/net/packet.hpp index dec6f94555..0d13519af2 100644 --- a/api/net/packet.hpp +++ b/api/net/packet.hpp @@ -18,8 +18,8 @@ #ifndef NET_PACKET_HPP #define NET_PACKET_HPP -#include -#include +#include "buffer_store.hpp" +#include "ip4/ip4.hpp" #include namespace net { diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index 00973a4bdb..5a5ffcf40d 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -19,9 +19,9 @@ #define NET_TCP_HPP #include -#include // IP4::Addr -#include // PacketIP4 -#include // net::Packet_ptr, htons / noths +#include "ip4/ip4.hpp" // IP4::Addr +#include "ip4/packet_ip4.hpp" // PacketIP4 +#include "util.hpp" // net::Packet_ptr, htons / noths #include // buffer #include #include // ostringstream diff --git a/src/Makefile b/src/Makefile index 833744f3f1..374e14170a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -67,7 +67,7 @@ OS_OBJECTS = kernel/kernel_start.o kernel/syscalls.o kernel/vga.o \ hw/ide.o hw/pit.o hw/pic.o hw/pci_device.o hw/cpu_freq_sampling.o hw/serial.o\ virtio/virtio.o virtio/virtio_queue.o virtio/virtionet.o \ virtio/block.o virtio/console.o \ - net/ethernet.o net/inet_common.o net/arp.o net/ip4.o \ + net/ethernet.o net/inet_common.o net/ip4/arp.o net/ip4/ip4.o \ net/tcp.o net/tcp_connection.o net/tcp_connection_states.o \ net/ip4/icmpv4.o net/ip4/udp.o net/ip4/udp_socket.o \ net/dns/dns.o net/dns/client.o net/dhcp/dh4client.o \ diff --git a/src/net/arp.cpp b/src/net/ip4/arp.cpp similarity index 99% rename from src/net/arp.cpp rename to src/net/ip4/arp.cpp index 46666b9eb0..bc9350f712 100644 --- a/src/net/arp.cpp +++ b/src/net/ip4/arp.cpp @@ -21,8 +21,8 @@ #include #include -#include #include +#include #include namespace net { diff --git a/src/net/ip4.cpp b/src/net/ip4/ip4.cpp similarity index 99% rename from src/net/ip4.cpp rename to src/net/ip4/ip4.cpp index 537e8da023..b8dfc5840f 100644 --- a/src/net/ip4.cpp +++ b/src/net/ip4/ip4.cpp @@ -18,7 +18,7 @@ #define DEBUG // Allow debugging #define DEBUG2 // Allow debug lvl 2 #include -#include +#include #include #include diff --git a/test/tcp/test.sh b/test/tcp/test.sh old mode 100644 new mode 100755 From a3d8a319001123030f31e6f60bb4139f82867c59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Sun, 3 Apr 2016 18:53:51 +0200 Subject: [PATCH 096/311] virtio: fix to reflect changes made to MTU calculation --- src/virtio/virtionet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/virtio/virtionet.cpp b/src/virtio/virtionet.cpp index d957d94a62..89322215e9 100644 --- a/src/virtio/virtionet.cpp +++ b/src/virtio/virtionet.cpp @@ -241,7 +241,7 @@ void VirtioNet::service_queues(){ auto pckt_ptr = std::make_shared (data+sizeof(virtio_net_hdr), // Offset buffer (bufstore knows the offseto) - MTU()-sizeof(virtio_net_hdr), // Capacity + MTU(), // Capacity len - sizeof(virtio_net_hdr), release_buffer); // Size _link_out(pckt_ptr); From c2248986f0d62b2b084bd6ee455a9aa58b1aa439 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Sun, 3 Apr 2016 21:11:05 +0200 Subject: [PATCH 097/311] fs: Elaborate on Buffer, fix broken tests --- api/fs/filesystem.hpp | 31 ++++++++++++++++++++++++++++--- test/fat/fat16.cpp | 21 ++++++++++++--------- test/fat/fat32.cpp | 9 +++++---- 3 files changed, 45 insertions(+), 16 deletions(-) diff --git a/api/fs/filesystem.hpp b/api/fs/filesystem.hpp index 498f642f74..11df6595ab 100644 --- a/api/fs/filesystem.hpp +++ b/api/fs/filesystem.hpp @@ -43,12 +43,37 @@ namespace fs { struct Buffer { + Buffer(error_t e, buffer_t b, size_t l) + : err(e), buffer(b), len(l) {} + + // returns true if this buffer is valid + bool is_valid() const + { + return buffer != nullptr; + } + operator bool () const + { + return is_valid(); + } + + uint8_t* data() + { + return buffer.get(); + } + size_t size() const + { + return len; + } + + // create a std::string from the stored buffer and return it + std::string to_string() const + { + return std::string((char*) buffer.get(), size()); + } + error_t err; buffer_t buffer; uint64_t len; - - Buffer(error_t e, buffer_t b, size_t l) - : err(e), buffer(b), len(l) {} }; enum Enttype { diff --git a/test/fat/fat16.cpp b/test/fat/fat16.cpp index dfa010bf25..ba9d27c139 100644 --- a/test/fat/fat16.cpp +++ b/test/fat/fat16.cpp @@ -67,12 +67,8 @@ void Service::start() CHECKSERT(!ent.is_dir(), "Entity is not directory"); CHECKSERT(ent.name() == "banana.txt", "Name is 'banana.txt'"); - // try reading banana-file - auto buf = fs.read(ent, 0, ent.size); - std::string banana((char*) buf.buffer.get(), buf.len); - std::string internal_banana = - R"( ____ ___ +R"( ____ ___ | _ \ ___ _ _.' _ `. _ | [_) )' _ `._ _ ___ ! \ | | (_) | _ |:;.| _ <| (_) | \ | |' _ `| \| | _ | .:;| @@ -81,12 +77,17 @@ void Service::start() !::, `-!_| | | |\ | | | | | \ !_!.' ':;! !::; ":;:!.!.\_!_!_!.!-'-':;:'' '''! ';:' `::;::;' '' ., . - `: .,. `' .::... . .::;::;' - `..:;::;:.. ::;::;:;:;, :;::;' + `: .,. `' .::... . .::;::;' + `..:;::;:.. ::;::;:;:;, :;::;' "-:;::;:;: ':;::;:'' ;.-' ""`---...________...---'"" - )"; +)"; printf("%s\n", internal_banana.c_str()); + + // try reading banana-file + auto buf = fs.read(ent, 0, ent.size); + auto banana = buf.to_string(); + CHECKSERT(banana == internal_banana, "Correct banana #1"); bool test = true; @@ -95,6 +96,8 @@ void Service::start() { // read one byte at a time buf = fs.read(ent, i, 1); + /// @buf should evaluate to 'true' if its valid + CHECKSERT(buf, "Validate buffer"); // verify that it matches the same location in test-string test = ((char) buf.buffer.get()[0] == internal_banana[i]); @@ -107,7 +110,7 @@ void Service::start() CHECKSERT(test, "Validate random access sync read"); buf = fs.readFile("/banana.txt"); - banana = std::string((char*) buf.buffer.get(), buf.len); + banana = buf.to_string(); CHECKSERT(banana == internal_banana, "Correct banana #2"); }); diff --git a/test/fat/fat32.cpp b/test/fat/fat32.cpp index d0bfa744c1..6891eb5a84 100644 --- a/test/fat/fat32.cpp +++ b/test/fat/fat32.cpp @@ -24,7 +24,7 @@ std::shared_ptr disk; std::string internal_banana = - R"( ____ ___ +R"( ____ ___ | _ \ ___ _ _.' _ `. _ | [_) )' _ `._ _ ___ ! \ | | (_) | _ |:;.| _ <| (_) | \ | |' _ `| \| | _ | .:;| @@ -33,11 +33,11 @@ std::string internal_banana = !::, `-!_| | | |\ | | | | | \ !_!.' ':;! !::; ":;:!.!.\_!_!_!.!-'-':;:'' '''! ';:' `::;::;' '' ., . - `: .,. `' .::... . .::;::;' - `..:;::;:.. ::;::;:;:;, :;::;' + `: .,. `' .::... . .::;::;' + `..:;::;:.. ::;::;:;:;, :;::;' "-:;::;:;: ':;::;:'' ;.-' ""`---...________...---'"" - )"; +)"; void Service::start() { @@ -48,6 +48,7 @@ void Service::start() // verify that the size is indeed N sectors const size_t SIZE = 4194304; + printf("Size: %llu\n", disk->dev().size()); CHECKSERT(disk->dev().size() == SIZE, "Disk size 4194304 sectors"); // which means that the disk can't be empty From 77980d4a11327b59bf3a5f37fffd68723082aac0 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Sun, 3 Apr 2016 21:15:55 +0200 Subject: [PATCH 098/311] ide: Fix broken SLAVE drive selection --- src/hw/ide.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hw/ide.cpp b/src/hw/ide.cpp index 1d9c49e50d..8f8fb0acbb 100644 --- a/src/hw/ide.cpp +++ b/src/hw/ide.cpp @@ -85,7 +85,7 @@ namespace hw { /** IDE device initialization */ set_irq_mode(false); - set_drive(0xA0 | (_drive << 4)); + set_drive(0xA0 | _drive); set_nbsectors(0U); set_blocknum(0U); set_command(IDE_CMD_IDENTIFY); @@ -128,7 +128,7 @@ namespace hw { } set_irq_mode(true); - set_drive(0xE0 | (_drive << 4) | ((blk >> 24) & 0x0F)); + set_drive(0xE0 | _drive | ((blk >> 24) & 0x0F)); set_nbsectors(1); set_blocknum(blk); set_command(IDE_CMD_READ); @@ -146,7 +146,7 @@ namespace hw { } set_irq_mode(true); - set_drive(0xE0 | (_drive << 4) | ((blk >> 24) & 0x0F)); + set_drive(0xE0 | _drive | ((blk >> 24) & 0x0F)); set_nbsectors(count); set_blocknum(blk); set_command(IDE_CMD_READ); @@ -163,7 +163,7 @@ namespace hw { } set_irq_mode(false); - set_drive(0xE0 | (_drive << 4) | ((blk >> 24) & 0x0F)); + set_drive(0xE0 | _drive | ((blk >> 24) & 0x0F)); set_nbsectors(1); set_blocknum(blk); set_command(IDE_CMD_READ); From 269a49a3102dc39a9baf631eb717823a0e35e971 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Mon, 4 Apr 2016 09:27:28 +0200 Subject: [PATCH 099/311] Editorconfig NUKE v2.0 --- api/fs/disk.hpp | 10 +- api/fs/ext4.hpp | 278 ++++----- api/fs/fat.hpp | 20 +- api/fs/filesystem.hpp | 44 +- api/hw/dev.hpp | 8 +- api/hw/ide.hpp | 4 +- api/hw/pci.hpp | 12 +- api/hw/pci_device.hpp | 26 +- api/hw/pit.hpp | 48 +- api/kernel/irq_manager.hpp | 6 +- api/net/dhcp/dh4client.hpp | 2 +- api/net/dhcp/dhcp4.hpp | 2 +- api/net/dns/dns.hpp | 38 +- api/net/ethernet.hpp | 28 +- api/net/inet.hpp | 6 +- api/net/inet4.hpp | 14 +- api/net/inet64.hpp | 26 +- api/net/ip4/arp.hpp | 8 +- api/net/ip4/ip4.hpp | 12 +- api/net/ip4/packet_ip4.hpp | 2 +- api/net/ip4/packet_tcp.hpp | 2 +- api/net/ip4/udp.hpp | 8 +- api/net/ip6/ip6.hpp | 78 +-- api/net/ip6/udp6.hpp | 4 +- api/net/tcp.hpp | 936 +++++++++++++++--------------- api/utility/async_loop.hpp | 12 +- api/utility/delegate.hpp | 42 +- api/utility/membitmap.hpp | 18 +- api/utility/ringbuffer.hpp | 70 +-- api/utility/signal.hpp | 4 +- etc/batch_apply_editorconfig.sh | 2 +- examples/demo_service/service.cpp | 78 +-- examples/tcp/service.cpp | 52 +- src/crt/mman.cpp | 4 +- src/debug/ircd.cpp | 138 ++--- src/debug/ircsplit.hpp | 30 +- src/debug/test_disk.cpp | 200 +++---- src/debug/test_ipv6.cpp | 56 +- src/debug/test_service.cpp | 20 +- src/debug/test_tcp.cpp | 16 +- src/fs/disk.cpp | 162 +++--- src/fs/ext4.cpp | 22 +- src/fs/fat.cpp | 254 ++++---- src/fs/fat_async.cpp | 282 ++++----- src/fs/fat_sync.cpp | 132 ++--- src/fs/mbr.cpp | 66 +-- src/fs/memdisk.cpp | 4 +- src/fs/path.cpp | 78 +-- src/hw/cpu_freq_sampling.cpp | 4 +- src/hw/ide.cpp | 8 +- src/hw/pci_device.cpp | 36 +- src/hw/pit.cpp | 30 +- src/kernel/cpuid.cpp | 8 +- src/kernel/irq_manager.cpp | 66 +-- src/kernel/terminal.cpp | 150 ++--- src/kernel/terminal_disk.cpp | 176 +++--- src/kernel/vga.cpp | 2 +- src/net/buffer_store.cpp | 26 +- src/net/dhcp/dh4client.cpp | 116 ++-- src/net/dns/client.cpp | 16 +- src/net/dns/dns.cpp | 156 ++--- src/net/ethernet.cpp | 12 +- src/net/ip4/arp.cpp | 42 +- src/net/ip4/icmpv4.cpp | 4 +- src/net/ip4/ip4.cpp | 22 +- src/net/ip4/udp.cpp | 18 +- src/net/ip4/udp_socket.cpp | 50 +- src/net/ip6/icmp6.cpp | 176 +++--- src/net/ip6/ip6.cpp | 54 +- src/net/ip6/udp6.cpp | 8 +- src/net/tcp.cpp | 12 +- src/net/tcp_connection.cpp | 26 +- src/net/tcp_connection_states.cpp | 30 +- src/virtio/block.cpp | 26 +- src/virtio/console.cpp | 46 +- src/virtio/virtio.cpp | 12 +- src/virtio/virtionet.cpp | 16 +- test/IDE/service.cpp | 4 +- test/STL/service.cpp | 92 +-- test/bufstore/service.cpp | 6 +- test/fat/fat16.cpp | 62 +- test/fat/fat32.cpp | 8 +- test/memdisk/twosector.cpp | 2 +- test/tcp/service.cpp | 96 +-- test/term/term.cpp | 78 +-- test/timers/service.cpp | 20 +- test/transmit/service.cpp | 2 +- test/vga/vga.cpp | 24 +- 88 files changed, 2553 insertions(+), 2553 deletions(-) diff --git a/api/fs/disk.hpp b/api/fs/disk.hpp index 72ad7f7757..0f8e857d6d 100644 --- a/api/fs/disk.hpp +++ b/api/fs/disk.hpp @@ -53,11 +53,11 @@ namespace fs { struct Partition { explicit Partition(const uint8_t fl, const uint8_t Id, - const uint32_t LBA, const uint32_t sz) noexcept : - flags {fl}, - id {Id}, - lba_begin {LBA}, - sectors {sz} + const uint32_t LBA, const uint32_t sz) noexcept : + flags {fl}, + id {Id}, + lba_begin {LBA}, + sectors {sz} {} uint8_t flags; diff --git a/api/fs/ext4.hpp b/api/fs/ext4.hpp index ca289b95d0..b2d1a5678d 100644 --- a/api/fs/ext4.hpp +++ b/api/fs/ext4.hpp @@ -32,16 +32,16 @@ namespace fs struct EXT4 : public FileSystem { /** - Blocks 2^32 2^32 2^32 2^32 - Inodes 2^32 2^32 2^32 2^32 - File System Size 4TiB 8TiB 16TiB 256PiB - Blocks Per Block Group 8,192 16,384 32,768 524,288 - Inodes Per Block Group 8,192 16,384 32,768 524,288 - Block Group Size 8MiB 32MiB 128MiB 32GiB - Blocks Per File, Extents 2^32 2^32 2^32 2^32 - Blocks Per File, Block Maps 16,843,020 134,480,396 1,074,791,436 4,398,314,962,956 + Blocks 2^32 2^32 2^32 2^32 + Inodes 2^32 2^32 2^32 2^32 + File System Size 4TiB 8TiB 16TiB 256PiB + Blocks Per Block Group 8,192 16,384 32,768 524,288 + Inodes Per Block Group 8,192 16,384 32,768 524,288 + Block Group Size 8MiB 32MiB 128MiB 32GiB + Blocks Per File, Extents 2^32 2^32 2^32 2^32 + Blocks Per File, Block Maps 16,843,020 134,480,396 1,074,791,436 4,398,314,962,956 File Size, Extents 4TiB 8TiB 16TiB 256TiB - File Size, Block Maps 16GiB 256GiB 4TiB 256PiB + File Size, Block Maps 16GiB 256GiB 4TiB 256PiB **/ // 0 = Mount MBR @@ -103,15 +103,15 @@ namespace fs uint16_t magic; // Magic signature, 0xEF53 // File system state. Valid values are: - // 0x0001 Cleanly umounted - // 0x0002 Errors detected - // 0x0004 Orphans being recovered + // 0x0001 Cleanly umounted + // 0x0002 Errors detected + // 0x0004 Orphans being recovered uint16_t state; // Behaviour when detecting errors. One of: - // 1 Continue - // 2 Remount read-only - // 3 Panic + // 1 Continue + // 2 Remount read-only + // 3 Panic uint16_t errors; uint16_t minor_rev_level; // Minor revision level @@ -119,16 +119,16 @@ namespace fs uint32_t checkinterval; // Maximum time between checks, in seconds // OS. One of: - // 0 Linux - // 1 Hurd - // 2 Masix - // 3 FreeBSD - // 4 Lites + // 0 Linux + // 1 Hurd + // 2 Masix + // 3 FreeBSD + // 4 Lites uint32_t creator_os; // Revision level. One of: - // 0 Original format - // 1 v2 format w/ dynamic inode sizes + // 0 Original format + // 1 v2 format w/ dynamic inode sizes uint32_t rev_level; uint16_t def_resuid; // Default uid for reserved blocks @@ -155,54 +155,54 @@ namespace fs // Compatible feature set flags. // Kernel can still read/write this fs even if it doesn't // understand a flag; fsck should not do that. Any of: - // 0x1 Directory preallocation (COMPAT_DIR_PREALLOC). - // 0x2 "imagic inodes". Not clear from the code what this does (COMPAT_IMAGIC_INODES). - // 0x4 Has a journal (COMPAT_HAS_JOURNAL). - // 0x8 Supports extended attributes (COMPAT_EXT_ATTR). - // 0x10 Has reserved GDT blocks for filesystem expansion (COMPAT_RESIZE_INODE). - // 0x20 Has directory indices (COMPAT_DIR_INDEX). - // 0x40 "Lazy BG". Not in Linux kernel, seems to have been for uninitialized block groups? (COMPAT_LAZY_BG) - // 0x80 "Exclude inode". Not used. (COMPAT_EXCLUDE_INODE). - // 0x100 "Exclude bitmap". Seems to be used to indicate the presence of snapshot-related exclude bitmaps? Not defined in kernel or used in e2fsprogs (COMPAT_EXCLUDE_BITMAP). - // 0x200 Sparse Super Block, v2. If this flag is set, the SB field s_backup_bgs points to the two block groups that contain backup superblocks (COMPAT_SPARSE_SUPER2). + // 0x1 Directory preallocation (COMPAT_DIR_PREALLOC). + // 0x2 "imagic inodes". Not clear from the code what this does (COMPAT_IMAGIC_INODES). + // 0x4 Has a journal (COMPAT_HAS_JOURNAL). + // 0x8 Supports extended attributes (COMPAT_EXT_ATTR). + // 0x10 Has reserved GDT blocks for filesystem expansion (COMPAT_RESIZE_INODE). + // 0x20 Has directory indices (COMPAT_DIR_INDEX). + // 0x40 "Lazy BG". Not in Linux kernel, seems to have been for uninitialized block groups? (COMPAT_LAZY_BG) + // 0x80 "Exclude inode". Not used. (COMPAT_EXCLUDE_INODE). + // 0x100 "Exclude bitmap". Seems to be used to indicate the presence of snapshot-related exclude bitmaps? Not defined in kernel or used in e2fsprogs (COMPAT_EXCLUDE_BITMAP). + // 0x200 Sparse Super Block, v2. If this flag is set, the SB field s_backup_bgs points to the two block groups that contain backup superblocks (COMPAT_SPARSE_SUPER2). uint32_t feature_compat; // Incompatible feature set. If the kernel or fsck doesn't // understand one of these bits, it should stop. Any of: - // 0x1 Compression (INCOMPAT_COMPRESSION). - // 0x2 Directory entries record the file type. See ext4_dir_entry_2 below (INCOMPAT_FILETYPE). - // 0x4 Filesystem needs recovery (INCOMPAT_RECOVER). - // 0x8 Filesystem has a separate journal device (INCOMPAT_JOURNAL_DEV). - // 0x10 Meta block groups. See the earlier discussion of this feature (INCOMPAT_META_BG). - // 0x40 Files in this filesystem use extents (INCOMPAT_EXTENTS). - // 0x80 Enable a filesystem size of 2^64 blocks (INCOMPAT_64BIT). - // 0x100 Multiple mount protection. Not implemented (INCOMPAT_MMP). - // 0x200 Flexible block groups. See the earlier discussion of this feature (INCOMPAT_FLEX_BG). - // 0x400 Inodes can be used for large extended attributes (INCOMPAT_EA_INODE). (Not implemented?) - // 0x1000 Data in directory entry (INCOMPAT_DIRDATA). (Not implemented?) - // 0x2000 Metadata checksum seed is stored in the superblock. This feature enables the administrator to change the UUID of a metadata_csum filesystem while the filesystem is mounted; without it, the checksum definition requires all metadata blocks to be rewritten (INCOMPAT_CSUM_SEED). - // 0x4000 Large directory >2GB or 3-level htree (INCOMPAT_LARGEDIR). - // 0x8000 Data in inode (INCOMPAT_INLINE_DATA). - // 0x10000 Encrypted inodes are present on the filesystem. (INCOMPAT_ENCRYPT). + // 0x1 Compression (INCOMPAT_COMPRESSION). + // 0x2 Directory entries record the file type. See ext4_dir_entry_2 below (INCOMPAT_FILETYPE). + // 0x4 Filesystem needs recovery (INCOMPAT_RECOVER). + // 0x8 Filesystem has a separate journal device (INCOMPAT_JOURNAL_DEV). + // 0x10 Meta block groups. See the earlier discussion of this feature (INCOMPAT_META_BG). + // 0x40 Files in this filesystem use extents (INCOMPAT_EXTENTS). + // 0x80 Enable a filesystem size of 2^64 blocks (INCOMPAT_64BIT). + // 0x100 Multiple mount protection. Not implemented (INCOMPAT_MMP). + // 0x200 Flexible block groups. See the earlier discussion of this feature (INCOMPAT_FLEX_BG). + // 0x400 Inodes can be used for large extended attributes (INCOMPAT_EA_INODE). (Not implemented?) + // 0x1000 Data in directory entry (INCOMPAT_DIRDATA). (Not implemented?) + // 0x2000 Metadata checksum seed is stored in the superblock. This feature enables the administrator to change the UUID of a metadata_csum filesystem while the filesystem is mounted; without it, the checksum definition requires all metadata blocks to be rewritten (INCOMPAT_CSUM_SEED). + // 0x4000 Large directory >2GB or 3-level htree (INCOMPAT_LARGEDIR). + // 0x8000 Data in inode (INCOMPAT_INLINE_DATA). + // 0x10000 Encrypted inodes are present on the filesystem. (INCOMPAT_ENCRYPT). uint32_t feature_incompat; // Readonly-compatible feature set. If the kernel doesn't // understand one of these bits, it can still mount read-only. // Any of: - //0x1 Sparse superblocks. See the earlier discussion of this feature (RO_COMPAT_SPARSE_SUPER). - //0x2 This filesystem has been used to store a file greater than 2GiB (RO_COMPAT_LARGE_FILE). - //0x4 Not used in kernel or e2fsprogs (RO_COMPAT_BTREE_DIR). - //0x8 This filesystem has files whose sizes are represented in units of logical blocks, not 512-byte sectors. This implies a very large file indeed! (RO_COMPAT_HUGE_FILE) - //0x10 Group descriptors have checksums. In addition to detecting corruption, this is useful for lazy formatting with uninitialized groups (RO_COMPAT_GDT_CSUM). - //0x20 Indicates that the old ext3 32,000 subdirectory limit no longer applies (RO_COMPAT_DIR_NLINK). - //0x40 Indicates that large inodes exist on this filesystem (RO_COMPAT_EXTRA_ISIZE). - //0x80 This filesystem has a snapshot (RO_COMPAT_HAS_SNAPSHOT). - //0x100 Quota (RO_COMPAT_QUOTA). - //0x200 This filesystem supports "bigalloc", which means that file extents are tracked in units of clusters (of blocks) instead of blocks (RO_COMPAT_BIGALLOC). - //0x400 This filesystem supports metadata checksumming. (RO_COMPAT_METADATA_CSUM; implies RO_COMPAT_GDT_CSUM, though GDT_CSUM must not be set) - //0x800 Filesystem supports replicas. This feature is neither in the kernel nor e2fsprogs. (RO_COMPAT_REPLICA) - //0x1000 Read-only filesystem image; the kernel will not mount this image read-write and most tools will refuse to write to the image. (RO_COMPAT_READONLY) - //0x2000 Filesystem tracks project quotas. (RO_COMPAT_PROJECT) + //0x1 Sparse superblocks. See the earlier discussion of this feature (RO_COMPAT_SPARSE_SUPER). + //0x2 This filesystem has been used to store a file greater than 2GiB (RO_COMPAT_LARGE_FILE). + //0x4 Not used in kernel or e2fsprogs (RO_COMPAT_BTREE_DIR). + //0x8 This filesystem has files whose sizes are represented in units of logical blocks, not 512-byte sectors. This implies a very large file indeed! (RO_COMPAT_HUGE_FILE) + //0x10 Group descriptors have checksums. In addition to detecting corruption, this is useful for lazy formatting with uninitialized groups (RO_COMPAT_GDT_CSUM). + //0x20 Indicates that the old ext3 32,000 subdirectory limit no longer applies (RO_COMPAT_DIR_NLINK). + //0x40 Indicates that large inodes exist on this filesystem (RO_COMPAT_EXTRA_ISIZE). + //0x80 This filesystem has a snapshot (RO_COMPAT_HAS_SNAPSHOT). + //0x100 Quota (RO_COMPAT_QUOTA). + //0x200 This filesystem supports "bigalloc", which means that file extents are tracked in units of clusters (of blocks) instead of blocks (RO_COMPAT_BIGALLOC). + //0x400 This filesystem supports metadata checksumming. (RO_COMPAT_METADATA_CSUM; implies RO_COMPAT_GDT_CSUM, though GDT_CSUM must not be set) + //0x800 Filesystem supports replicas. This feature is neither in the kernel nor e2fsprogs. (RO_COMPAT_REPLICA) + //0x1000 Read-only filesystem image; the kernel will not mount this image read-write and most tools will refuse to write to the image. (RO_COMPAT_READONLY) + //0x2000 Filesystem tracks project quotas. (RO_COMPAT_PROJECT) uint32_t feature_ro_compat; uint8_t uuid[16]; // 128-bit UUID for volume @@ -225,19 +225,19 @@ namespace fs // Journaling support valid if EXT4_FEATURE_COMPAT_HAS_JOURNAL set uint8_t journal_uuid[16]; // UUID of journal superblock - uint32_t journal_inum; // inode number of journal file. + uint32_t journal_inum; // inode number of journal file. uint32_t journal_dev; // Device number of journal file, if the external journal feature flag is set uint32_t last_orphan; // Start of list of orphaned inodes to delete uint32_t hash_seed[4]; // HTREE hash seed // Default hash algorithm to use for directory hashes. One of: - // 0x0 Legacy. - // 0x1 Half MD4. - // 0x2 Tea. - // 0x3 Legacy, unsigned. - // 0x4 Half MD4, unsigned. - // 0x5 Tea, unsigned. + // 0x0 Legacy. + // 0x1 Half MD4. + // 0x2 Tea. + // 0x3 Legacy, unsigned. + // 0x4 Half MD4, unsigned. + // 0x5 Tea, unsigned. uint8_t def_hash_version; // If this value is 0 or EXT3_JNL_BACKUP_BLOCKS (1), then the s_jnl_blocks field contains a duplicate copy of the inode's i_block[] array and i_size @@ -246,18 +246,18 @@ namespace fs uint16_t desc_size; // Default mount options. Any of: - // 0x001 Print debugging info upon (re)mount. (EXT4_DEFM_DEBUG) - // 0x002 New files take the gid of the containing directory (instead of the fsgid of the current process). (EXT4_DEFM_BSDGROUPS) - // 0x004 Support userspace-provided extended attributes. (EXT4_DEFM_XATTR_USER) - // 0x008 Support POSIX access control lists (ACLs). (EXT4_DEFM_ACL) - // 0x010 Do not support 32-bit UIDs. (EXT4_DEFM_UID16) - // 0x020 All data and metadata are commited to the journal. (EXT4_DEFM_JMODE_DATA) - // 0x040 All data are flushed to the disk before metadata are committed to the journal. (EXT4_DEFM_JMODE_ORDERED) - // 0x060 Data ordering is not preserved; data may be written after the metadata has been written. (EXT4_DEFM_JMODE_WBACK) - // 0x100 Disable write flushes. (EXT4_DEFM_NOBARRIER) - // 0x200 Track which blocks in a filesystem are metadata and therefore should not be used as data blocks. This option will be enabled by default on 3.18, hopefully. (EXT4_DEFM_BLOCK_VALIDITY) - // 0x400 Enable DISCARD support, where the storage device is told about blocks becoming unused. (EXT4_DEFM_DISCARD) - // 0x800 Disable delayed allocation. (EXT4_DEFM_NODELALLOC) + // 0x001 Print debugging info upon (re)mount. (EXT4_DEFM_DEBUG) + // 0x002 New files take the gid of the containing directory (instead of the fsgid of the current process). (EXT4_DEFM_BSDGROUPS) + // 0x004 Support userspace-provided extended attributes. (EXT4_DEFM_XATTR_USER) + // 0x008 Support POSIX access control lists (ACLs). (EXT4_DEFM_ACL) + // 0x010 Do not support 32-bit UIDs. (EXT4_DEFM_UID16) + // 0x020 All data and metadata are commited to the journal. (EXT4_DEFM_JMODE_DATA) + // 0x040 All data are flushed to the disk before metadata are committed to the journal. (EXT4_DEFM_JMODE_ORDERED) + // 0x060 Data ordering is not preserved; data may be written after the metadata has been written. (EXT4_DEFM_JMODE_WBACK) + // 0x100 Disable write flushes. (EXT4_DEFM_NOBARRIER) + // 0x200 Track which blocks in a filesystem are metadata and therefore should not be used as data blocks. This option will be enabled by default on 3.18, hopefully. (EXT4_DEFM_BLOCK_VALIDITY) + // 0x400 Enable DISCARD support, where the storage device is told about blocks becoming unused. (EXT4_DEFM_DISCARD) + // 0x800 Disable delayed allocation. (EXT4_DEFM_NODELALLOC) uint32_t default_mount_opts; // First metablock block group, if the meta_bg feature is enabled @@ -275,9 +275,9 @@ namespace fs uint16_t want_extra_isize; // New inodes should reserve # bytes // Miscellaneous flags. Any of: - // 0x01 Signed directory hash in use. - // 0x02 Unsigned directory hash in use. - // 0x04 To test development code. + // 0x01 Signed directory hash in use. + // 0x02 Unsigned directory hash in use. + // 0x04 To test development code. uint32_t flags; // RAID stride. This is the number of logical blocks read from or written to the disk before moving to the next disk. This affects the placement of filesystem metadata, which will hopefully make RAID storage faster @@ -321,10 +321,10 @@ namespace fs uint32_t backup_bgs[2]; // Block groups containing superblock backups (if sparse_super2) // Encryption algorithms in use. There can be up to four algorithms in use at any time; valid algorithm codes are given below: - // 0 Invalid algorithm (ENCRYPTION_MODE_INVALID). - // 1 256-bit AES in XTS mode (ENCRYPTION_MODE_AES_256_XTS). - // 2 256-bit AES in GCM mode (ENCRYPTION_MODE_AES_256_GCM). - // 3 256-bit AES in CBC mode (ENCRYPTION_MODE_AES_256_CBC). + // 0 Invalid algorithm (ENCRYPTION_MODE_INVALID). + // 1 256-bit AES in XTS mode (ENCRYPTION_MODE_AES_256_XTS). + // 2 256-bit AES in GCM mode (ENCRYPTION_MODE_AES_256_GCM). + // 3 256-bit AES in CBC mode (ENCRYPTION_MODE_AES_256_CBC). uint8_t encrypt_algos[4]; // Salt for the string2key algorithm for encryption. uint8_t encrypt_pw_salt[16]; @@ -351,9 +351,9 @@ namespace fs uint16_t free_inodes_count_lo; // Lower 16-bits of free inode count uint16_t used_dirs_count_lo; // Lower 16-bits of directory count // Block group flags. Any of: - // 0x1 inode table and bitmap are not initialized (EXT4_BG_INODE_UNINIT). - // 0x2 block bitmap is not initialized (EXT4_BG_BLOCK_UNINIT). - // 0x4 inode table is zeroed (EXT4_BG_INODE_ZEROED). + // 0x1 inode table and bitmap are not initialized (EXT4_BG_INODE_UNINIT). + // 0x2 block bitmap is not initialized (EXT4_BG_BLOCK_UNINIT). + // 0x4 inode table is zeroed (EXT4_BG_INODE_ZEROED). uint16_t flags; uint32_t exclude_bitmap_lo; // Lower 32-bits of location of snapshot exclusion bitmap @@ -386,26 +386,26 @@ namespace fs struct inode_table { // File mode. Any of: - // 0x1 S_IXOTH (Others may execute) - // 0x2 S_IWOTH (Others may write) - // 0x4 S_IROTH (Others may read) - // 0x8 S_IXGRP (Group members may execute) - // 0x10 S_IWGRP (Group members may write) - // 0x20 S_IRGRP (Group members may read) - // 0x40 S_IXUSR (Owner may execute) - // 0x80 S_IWUSR (Owner may write) - // 0x100 S_IRUSR (Owner may read) - // 0x200 S_ISVTX (Sticky bit) - // 0x400 S_ISGID (Set GID) - // 0x800 S_ISUID (Set UID) + // 0x1 S_IXOTH (Others may execute) + // 0x2 S_IWOTH (Others may write) + // 0x4 S_IROTH (Others may read) + // 0x8 S_IXGRP (Group members may execute) + // 0x10 S_IWGRP (Group members may write) + // 0x20 S_IRGRP (Group members may read) + // 0x40 S_IXUSR (Owner may execute) + // 0x80 S_IWUSR (Owner may write) + // 0x100 S_IRUSR (Owner may read) + // 0x200 S_ISVTX (Sticky bit) + // 0x400 S_ISGID (Set GID) + // 0x800 S_ISUID (Set UID) // These are mutually-exclusive file types: - // 0x1000 S_IFIFO (FIFO) - // 0x2000 S_IFCHR (Character device) - // 0x4000 S_IFDIR (Directory) - // 0x6000 S_IFBLK (Block device) - // 0x8000 S_IFREG (Regular file) - // 0xA000 S_IFLNK (Symbolic link) - // 0xC000 S_IFSOCK (Socket) + // 0x1000 S_IFIFO (FIFO) + // 0x2000 S_IFCHR (Character device) + // 0x4000 S_IFDIR (Directory) + // 0x6000 S_IFBLK (Block device) + // 0x8000 S_IFREG (Regular file) + // 0xA000 S_IFLNK (Symbolic link) + // 0xC000 S_IFSOCK (Socket) uint16_t mode; uint16_t uid; // Owner-ID (lower 16) @@ -419,37 +419,37 @@ namespace fs uint32_t blocks_lo; // "Block" count (lower 32) // Inode flags. Any of: - // 0x1 This file requires secure deletion (EXT4_SECRM_FL). (not implemented) - // 0x2 This file should be preserved, should undeletion be desired (EXT4_UNRM_FL). (not implemented) - // 0x4 File is compressed (EXT4_COMPR_FL). (not really implemented) - // 0x8 All writes to the file must be synchronous (EXT4_SYNC_FL). - // 0x10 File is immutable (EXT4_IMMUTABLE_FL). - // 0x20 File can only be appended (EXT4_APPEND_FL). - // 0x40 The dump(1) utility should not dump this file (EXT4_NODUMP_FL). - // 0x80 Do not update access time (EXT4_NOATIME_FL). - // 0x100 Dirty compressed file (EXT4_DIRTY_FL). (not used) - // 0x200 File has one or more compressed clusters (EXT4_COMPRBLK_FL). (not used) - // 0x400 Do not compress file (EXT4_NOCOMPR_FL). (not used) - // 0x800 Encrypted inode (EXT4_ENCRYPT_FL). This bit value previously was EXT4_ECOMPR_FL (compression error), which was never used. - // 0x1000 Directory has hashed indexes (EXT4_INDEX_FL). - // 0x2000 AFS magic directory (EXT4_IMAGIC_FL). - // 0x4000 File data must always be written through the journal (EXT4_JOURNAL_DATA_FL). - // 0x8000 File tail should not be merged (EXT4_NOTAIL_FL). (not used by ext4) - // 0x10000 All directory entry data should be written synchronously (see dirsync) (EXT4_DIRSYNC_FL). - // 0x20000 Top of directory hierarchy (EXT4_TOPDIR_FL). - // 0x40000 This is a huge file (EXT4_HUGE_FILE_FL). - // 0x80000 Inode uses extents (EXT4_EXTENTS_FL). - // 0x200000 Inode used for a large extended attribute (EXT4_EA_INODE_FL). - // 0x400000 This file has blocks allocated past EOF (EXT4_EOFBLOCKS_FL). (deprecated) - // 0x01000000 Inode is a snapshot (EXT4_SNAPFILE_FL). (not in mainline) - // 0x04000000 Snapshot is being deleted (EXT4_SNAPFILE_DELETED_FL). (not in mainline) - // 0x08000000 Snapshot shrink has completed (EXT4_SNAPFILE_SHRUNK_FL). (not in mainline) - // 0x10000000 Inode has inline data (EXT4_INLINE_DATA_FL). - // 0x20000000 Create children with the same project ID (EXT4_PROJINHERIT_FL). - // 0x80000000 Reserved for ext4 library (EXT4_RESERVED_FL). + // 0x1 This file requires secure deletion (EXT4_SECRM_FL). (not implemented) + // 0x2 This file should be preserved, should undeletion be desired (EXT4_UNRM_FL). (not implemented) + // 0x4 File is compressed (EXT4_COMPR_FL). (not really implemented) + // 0x8 All writes to the file must be synchronous (EXT4_SYNC_FL). + // 0x10 File is immutable (EXT4_IMMUTABLE_FL). + // 0x20 File can only be appended (EXT4_APPEND_FL). + // 0x40 The dump(1) utility should not dump this file (EXT4_NODUMP_FL). + // 0x80 Do not update access time (EXT4_NOATIME_FL). + // 0x100 Dirty compressed file (EXT4_DIRTY_FL). (not used) + // 0x200 File has one or more compressed clusters (EXT4_COMPRBLK_FL). (not used) + // 0x400 Do not compress file (EXT4_NOCOMPR_FL). (not used) + // 0x800 Encrypted inode (EXT4_ENCRYPT_FL). This bit value previously was EXT4_ECOMPR_FL (compression error), which was never used. + // 0x1000 Directory has hashed indexes (EXT4_INDEX_FL). + // 0x2000 AFS magic directory (EXT4_IMAGIC_FL). + // 0x4000 File data must always be written through the journal (EXT4_JOURNAL_DATA_FL). + // 0x8000 File tail should not be merged (EXT4_NOTAIL_FL). (not used by ext4) + // 0x10000 All directory entry data should be written synchronously (see dirsync) (EXT4_DIRSYNC_FL). + // 0x20000 Top of directory hierarchy (EXT4_TOPDIR_FL). + // 0x40000 This is a huge file (EXT4_HUGE_FILE_FL). + // 0x80000 Inode uses extents (EXT4_EXTENTS_FL). + // 0x200000 Inode used for a large extended attribute (EXT4_EA_INODE_FL). + // 0x400000 This file has blocks allocated past EOF (EXT4_EOFBLOCKS_FL). (deprecated) + // 0x01000000 Inode is a snapshot (EXT4_SNAPFILE_FL). (not in mainline) + // 0x04000000 Snapshot is being deleted (EXT4_SNAPFILE_DELETED_FL). (not in mainline) + // 0x08000000 Snapshot shrink has completed (EXT4_SNAPFILE_SHRUNK_FL). (not in mainline) + // 0x10000000 Inode has inline data (EXT4_INLINE_DATA_FL). + // 0x20000000 Create children with the same project ID (EXT4_PROJINHERIT_FL). + // 0x80000000 Reserved for ext4 library (EXT4_RESERVED_FL). // Aggregate flags: - // 0x4BDFFF User-visible flags. - // 0x4B80FF User-modifiable flags. Note that while EXT4_JOURNAL_DATA_FL and EXT4_EXTENTS_FL can be set with setattr, they are not in the kernel's EXT4_FL_USER_MODIFIABLE mask, since it needs to handle the setting of these flags in a special manner and they are masked out of the set of flags that are saved directly to i_flags. + // 0x4BDFFF User-visible flags. + // 0x4B80FF User-modifiable flags. Note that while EXT4_JOURNAL_DATA_FL and EXT4_EXTENTS_FL can be set with setattr, they are not in the kernel's EXT4_FL_USER_MODIFIABLE mask, since it needs to handle the setting of these flags in a special manner and they are masked out of the set of flags that are saved directly to i_flags. uint32_t flags; union // linux1, hurd1, masix1 diff --git a/api/fs/fat.hpp b/api/fs/fat.hpp index 06e00ae9ab..b7f7d7af8c 100644 --- a/api/fs/fat.hpp +++ b/api/fs/fat.hpp @@ -54,14 +54,14 @@ namespace fs virtual std::string name() const override { switch (this->fat_type) - { - case T_FAT12: + { + case T_FAT12: return "FAT12"; - case T_FAT16: + case T_FAT16: return "FAT16"; - case T_FAT32: + case T_FAT32: return "FAT32"; - } + } return "Invalid fat type"; } /// ----------------------------------------------------- /// @@ -121,7 +121,7 @@ namespace fs uint32_t size() const { - return filesize; + return filesize; } } __attribute__((packed)); @@ -162,16 +162,16 @@ namespace fs uint16_t cl_to_entry_offset(uint32_t cl) { if (fat_type == T_FAT16) - return (cl * 2) % sector_size; + return (cl * 2) % sector_size; else // T_FAT32 - return (cl * 4) % sector_size; + return (cl * 4) % sector_size; } uint16_t cl_to_entry_sector(uint32_t cl) { if (fat_type == T_FAT16) - return reserved + (cl * 2 / sector_size); + return reserved + (cl * 2 / sector_size); else // T_FAT32 - return reserved + (cl * 4 / sector_size); + return reserved + (cl * 4 / sector_size); } // initialize filesystem by providing base sector diff --git a/api/fs/filesystem.hpp b/api/fs/filesystem.hpp index 11df6595ab..14898b7ce9 100644 --- a/api/fs/filesystem.hpp +++ b/api/fs/filesystem.hpp @@ -44,7 +44,7 @@ namespace fs { struct Buffer { Buffer(error_t e, buffer_t b, size_t l) - : err(e), buffer(b), len(l) {} + : err(e), buffer(b), len(l) {} // returns true if this buffer is valid bool is_valid() const @@ -90,15 +90,15 @@ namespace fs { struct Dirent { /** Default constructor */ explicit Dirent(const Enttype t = INVALID_ENTITY, const std::string& n = "", - const uint64_t blk = 0U, const uint64_t pr = 0U, - const uint64_t sz = 0U, const uint32_t attr = 0U) : - ftype {t}, - fname {n}, - block {blk}, - parent {pr}, - size {sz}, - attrib {attr}, - timestamp {0} + const uint64_t blk = 0U, const uint64_t pr = 0U, + const uint64_t sz = 0U, const uint32_t attr = 0U) : + ftype {t}, + fname {n}, + block {blk}, + parent {pr}, + size {sz}, + attrib {attr}, + timestamp {0} {} Enttype ftype; @@ -129,19 +129,19 @@ namespace fs { // type converted to human-readable string std::string type_string() const { - switch (ftype) { - case FILE: - return "File"; - case DIR: - return "Directory"; - case VOLUME_ID: - return "Volume ID"; + switch (ftype) { + case FILE: + return "File"; + case DIR: + return "Directory"; + case VOLUME_ID: + return "Volume ID"; - case INVALID_ENTITY: - return "Invalid entity"; - default: - return "Unknown type"; - } //< switch (type) + case INVALID_ENTITY: + return "Invalid entity"; + default: + return "Unknown type"; + } //< switch (type) } }; //< struct Dirent diff --git a/api/hw/dev.hpp b/api/hw/dev.hpp index 559d72982f..612132016f 100644 --- a/api/hw/dev.hpp +++ b/api/hw/dev.hpp @@ -53,10 +53,10 @@ namespace hw { template static Disk& disk(Args&&... args) { static Disk - disk_ { - PCI_manager::device(N), - std::forward(args)... - }; + disk_ { + PCI_manager::device(N), + std::forward(args)... + }; return disk_; } diff --git a/api/hw/ide.hpp b/api/hw/ide.hpp index 759305a712..7c78e298d1 100644 --- a/api/hw/ide.hpp +++ b/api/hw/ide.hpp @@ -31,8 +31,8 @@ namespace hw { public: enum selector_t { - MASTER = 0x00, - SLAVE = 0x10 + MASTER = 0x00, + SLAVE = 0x10 }; /** diff --git a/api/hw/pci.hpp b/api/hw/pci.hpp index fbd0b5a975..6bef855e3d 100644 --- a/api/hw/pci.hpp +++ b/api/hw/pci.hpp @@ -13,8 +13,8 @@ namespace hw { __asm__ volatile("xorl %eax,%eax"); __asm__ volatile("inb %%dx,%%al" - :"=a"(ret) - :"d"(port)); + :"=a"(ret) + :"d"(port)); return ret; } @@ -23,8 +23,8 @@ namespace hw { uint16_t ret; __asm__ volatile("xorl %eax,%eax"); __asm__ volatile("inw %%dx,%%ax" - :"=a"(ret) - :"d"(port)); + :"=a"(ret) + :"d"(port)); return ret; } @@ -33,8 +33,8 @@ namespace hw { uint32_t ret; __asm__ volatile("xorl %eax,%eax"); __asm__ volatile("inl %%dx,%%eax" - :"=a"(ret) - :"d"(port)); + :"=a"(ret) + :"d"(port)); return ret; } diff --git a/api/hw/pci_device.hpp b/api/hw/pci_device.hpp index fb55a09972..065e459408 100644 --- a/api/hw/pci_device.hpp +++ b/api/hw/pci_device.hpp @@ -196,8 +196,8 @@ namespace hw { union vendor_product { uint32_t __value; struct __attribute__((packed)) { - uint16_t vendor; - uint16_t product; + uint16_t vendor; + uint16_t product; }; } device_id_; @@ -205,15 +205,15 @@ namespace hw { union class_revision { uint32_t reg; struct __attribute__((packed)) { - uint8_t rev_id; - uint8_t prog_if; - uint8_t subclass; - uint8_t classcode; + uint8_t rev_id; + uint8_t prog_if; + uint8_t subclass; + uint8_t classcode; }; struct __attribute__((packed)) { - uint16_t class_subclass; - uint8_t __prog_if; //Overlaps the above - uint8_t revision; + uint16_t class_subclass; + uint8_t __prog_if; //Overlaps the above + uint8_t revision; }; } devtype_; @@ -253,11 +253,11 @@ namespace hw { void add_resource(Resource* res, Resource*& Q) noexcept { Resource* q; if (Q) { - q = Q; - while (q->next) q = q->next; - q->next = res; + q = Q; + while (q->next) q = q->next; + q->next = res; } else { - Q = res; + Q = res; } } }; //< class PCI_Device diff --git a/api/hw/pit.hpp b/api/hw/pit.hpp index 5d21588c9d..f4f4d8f439 100644 --- a/api/hw/pit.hpp +++ b/api/hw/pit.hpp @@ -37,17 +37,17 @@ namespace hw { typedef std::function repeat_condition; /** Create a one-shot timer. - @param ms: Expiration time. Compatible with all std::chrono durations. - @param handler: A delegate or function to be called on timeout. */ + @param ms: Expiration time. Compatible with all std::chrono durations. + @param handler: A delegate or function to be called on timeout. */ void onTimeout(std::chrono::milliseconds ms, timeout_handler handler); /** Create a repeating timer. - @param ms: Expiration time. Compatible with all std::chrono durations. - @param handler: A delegate or function to be called every ms interval. - @param cond: The timer ends when cond() returns false. Default to true. */ + @param ms: Expiration time. Compatible with all std::chrono durations. + @param handler: A delegate or function to be called every ms interval. + @param cond: The timer ends when cond() returns false. Default to true. */ void onRepeatedTimeout(std::chrono::milliseconds ms, - timeout_handler handler, - repeat_condition cond = forever); + timeout_handler handler, + repeat_condition cond = forever); /** No copy or move. The OS owns one instance forever. */ PIT(PIT&) = delete; @@ -68,8 +68,8 @@ namespace hw { static inline MHz current_frequency(){ return frequency() / current_freq_divider_; } /** Estimate cpu frequency based on the fixed PIT frequency and rdtsc. - @Note This is an asynchronous function. Once finished the result can be - fetched by CPUFrequency() (below) */ + @Note This is an asynchronous function. Once finished the result can be + fetched by CPUFrequency() (below) */ static void estimateCPUFrequency(); /** Get the last estimated CPU frequency. May trigger frequency sampling */ @@ -80,12 +80,12 @@ namespace hw { static std::function forever; enum Mode { ONE_SHOT = 0, - HW_ONESHOT = 1 << 1, - RATE_GEN = 2 << 1, - SQ_WAVE = 3 << 1, - SW_STROBE = 4 << 1, - HW_STROBE = 5 << 1, - NONE = 256}; + HW_ONESHOT = 1 << 1, + RATE_GEN = 2 << 1, + SQ_WAVE = 3 << 1, + SW_STROBE = 4 << 1, + HW_STROBE = 5 << 1, + NONE = 256}; // The PIT-chip runs at this fixed frequency (in MHz) , according to OSDev.org */ static constexpr MHz frequency_ = MHz(14.31818 / 12); @@ -133,7 +133,7 @@ namespace hw { /** A timer is a handler and an expiration time (interval). - @todo The timer also keeps a pre-computed rdtsc-value, which is currently unused.*/ + @todo The timer also keeps a pre-computed rdtsc-value, which is currently unused.*/ class Timer { public: enum Type { ONE_SHOT, REPEAT, REPEAT_WHILE} type_; @@ -165,18 +165,18 @@ namespace hw { std::chrono::milliseconds interval_; /* This Could be a reference in the default case of "forever", but then the - case of a normal lambda being passed in, the user would have to be in charge - of storage. */ + case of a normal lambda being passed in, the user would have to be in charge + of storage. */ const repeat_condition cond_; }; /** A map of timers. - @note {Performance: We take advantage of the fact that std::map have sorted keys. - * Timers soonest to expire are in the front, so we only iterate over those - * Deletion of finished timers in amortized constant time, via iterators - * Timer insertion is log(n) } - @note This is why we want to instantiate PIT, and why it's a singleton: - If you don't use PIT-timers, you won't pay for them. */ + @note {Performance: We take advantage of the fact that std::map have sorted keys. + * Timers soonest to expire are in the front, so we only iterate over those + * Deletion of finished timers in amortized constant time, via iterators + * Timer insertion is log(n) } + @note This is why we want to instantiate PIT, and why it's a singleton: + If you don't use PIT-timers, you won't pay for them. */ std::multimap timers_; /** Queue the timer. This will update timestamps in the timer */ diff --git a/api/kernel/irq_manager.hpp b/api/kernel/irq_manager.hpp index 74dfc5d1ff..1e2bcdc8bb 100644 --- a/api/kernel/irq_manager.hpp +++ b/api/kernel/irq_manager.hpp @@ -169,9 +169,9 @@ class IRQ_manager { * Use "set_handler" for a simpler version using defaults */ static void create_gate(IDTDescr* idt_entry, - void (*function_addr)(), - uint16_t segment_sel, - char attributes); + void (*function_addr)(), + uint16_t segment_sel, + char attributes); /** The OS will call the following : */ friend class OS; diff --git a/api/net/dhcp/dh4client.hpp b/api/net/dhcp/dh4client.hpp index f97a1362b8..1047d3ec38 100644 --- a/api/net/dhcp/dh4client.hpp +++ b/api/net/dhcp/dh4client.hpp @@ -59,7 +59,7 @@ namespace net uint32_t lease_time; On_config config_handler = [](Stack&){ INFO("DHCPv4::On_config","Config complete"); }; }; - + inline DHClient::DHClient(Stack& inet) : stack(inet) {} } diff --git a/api/net/dhcp/dhcp4.hpp b/api/net/dhcp/dhcp4.hpp index b1a021232d..d4751d8ee0 100644 --- a/api/net/dhcp/dhcp4.hpp +++ b/api/net/dhcp/dhcp4.hpp @@ -20,7 +20,7 @@ #ifndef NET_DHCP_DHCP4_HPP #define NET_DHCP_DHCP4_HPP -#define DHCP_VEND_LEN 304 +#define DHCP_VEND_LEN 304 #define BOOTP_MIN_LEN 300 #define DHCP_MIN_LEN 548 // some clients silently ignore responses less than 300 bytes diff --git a/api/net/dns/dns.hpp b/api/net/dns/dns.hpp index 66759203d5..ea55d0f43b 100644 --- a/api/net/dns/dns.hpp +++ b/api/net/dns/dns.hpp @@ -117,12 +117,12 @@ namespace net enum resp_code { - NO_ERROR = 0, - FORMAT_ERROR = 1, - SERVER_FAIL = 2, - NAME_ERROR = 3, - NOT_IMPL = 4, // unimplemented feature - OP_REFUSED = 5, // for political reasons + NO_ERROR = 0, + FORMAT_ERROR = 1, + SERVER_FAIL = 2, + NAME_ERROR = 3, + NOT_IMPL = 4, // unimplemented feature + OP_REFUSED = 5, // for political reasons }; typedef std::function* (const std::string&)> lookup_func; @@ -132,18 +132,18 @@ namespace net static std::string question_string(unsigned short type) { switch (type) - { - case DNS_TYPE_A: - return "IPv4 address"; - case DNS_TYPE_ALIAS: - return "Alias"; - case DNS_TYPE_MX: - return "Mail exchange"; - case DNS_TYPE_NS: - return "Name server"; - default: - return "FIXME DNS::question_string(type = " + std::to_string(type) + ")"; - } + { + case DNS_TYPE_A: + return "IPv4 address"; + case DNS_TYPE_ALIAS: + return "Alias"; + case DNS_TYPE_MX: + return "Mail exchange"; + case DNS_TYPE_NS: + return "Name server"; + default: + return "FIXME DNS::question_string(type = " + std::to_string(type) + ")"; + } } class Request @@ -161,7 +161,7 @@ namespace net { IP4::addr result{{0}}; if (answers.size()) - result = answers[0].getIP4(); + result = answers[0].getIP4(); return result; } diff --git a/api/net/ethernet.hpp b/api/net/ethernet.hpp index 47736f4ce3..dcf7acdb40 100644 --- a/api/net/ethernet.hpp +++ b/api/net/ethernet.hpp @@ -61,32 +61,32 @@ namespace net { uint8_t part[ETHER_ADDR_LEN]; struct { - uint16_t minor; - uint32_t major; + uint16_t minor; + uint32_t major; } __attribute__((packed)); addr& operator=(const addr cpy) noexcept { - minor = cpy.minor; - major = cpy.major; - return *this; + minor = cpy.minor; + major = cpy.major; + return *this; } // hex string representation std::string str() const { - char eth_addr[17]; - sprintf(eth_addr, "%1x:%1x:%1x:%1x:%1x:%1x", - part[0], part[1], part[2], - part[3], part[4], part[5]); - return eth_addr; + char eth_addr[17]; + sprintf(eth_addr, "%1x:%1x:%1x:%1x:%1x:%1x", + part[0], part[1], part[2], + part[3], part[4], part[5]); + return eth_addr; } /** Check for equality */ bool operator==(const addr mac) const noexcept { - return strncmp( - reinterpret_cast(part), - reinterpret_cast(mac.part), - ETHER_ADDR_LEN) == 0; + return strncmp( + reinterpret_cast(part), + reinterpret_cast(mac.part), + ETHER_ADDR_LEN) == 0; } static const addr MULTICAST_FRAME; diff --git a/api/net/inet.hpp b/api/net/inet.hpp index 761d64614f..71834b517c 100644 --- a/api/net/inet.hpp +++ b/api/net/inet.hpp @@ -56,9 +56,9 @@ namespace net { virtual void set_dns_server(typename IPV::addr server) = 0; virtual void network_config(typename IPV::addr ip, - typename IPV::addr nmask, - typename IPV::addr router, - typename IPV::addr dnssrv) = 0; + typename IPV::addr nmask, + typename IPV::addr router, + typename IPV::addr dnssrv) = 0; /** Event triggered when there are available buffers in the transmit queue */ virtual void on_transmit_queue_available(transmit_avail_delg del) = 0; diff --git a/api/net/inet4.hpp b/api/net/inet4.hpp index 285d14c4ca..1ded92c52d 100644 --- a/api/net/inet4.hpp +++ b/api/net/inet4.hpp @@ -68,19 +68,19 @@ namespace net { inline std::shared_ptr dhclient() override { return dhcp_; } /** Create a Packet, with a preallocated buffer. - @param size : the "size" reported by the allocated packet. - @note as of v0.6.3 this has no effect other than to force the size to be - set explicitly by the caller. - @todo make_shared will allocate with new. This is fast in IncludeOS, - (no context switch for sbrk) but consider overloading operator new. + @param size : the "size" reported by the allocated packet. + @note as of v0.6.3 this has no effect other than to force the size to be + set explicitly by the caller. + @todo make_shared will allocate with new. This is fast in IncludeOS, + (no context switch for sbrk) but consider overloading operator new. */ inline Packet_ptr createPacket(size_t size) override { // Create a release delegate, for returning buffers auto release = BufferStore::release_del::from - (nic_.bufstore()); + (nic_.bufstore()); // Create the packet, using buffer and . return std::make_shared(bufstore_.get_offset_buffer(), - bufstore_.offset_bufsize(), size, release); + bufstore_.offset_bufsize(), size, release); } // We have to ask the Nic for the MTU diff --git a/api/net/inet64.hpp b/api/net/inet64.hpp index dc323cc365..b7d9bb804d 100644 --- a/api/net/inet64.hpp +++ b/api/net/inet64.hpp @@ -43,14 +43,14 @@ namespace net { class Inet64 { public: /** Listen to a UDP port. - This is just a simple forwarder. @see UDP::listen. */ + This is just a simple forwarder. @see UDP::listen. */ inline void udp_listen(uint16_t port, UDP::listener l) { _udp.listen(port,l); } /** Send a UDP datagram. - - @note the data buffer is the *whole* ethernet frame, so don't overwrite - headers unless you own them (i.e. you *are* the IP object) */ + + @note the data buffer is the *whole* ethernet frame, so don't overwrite + headers unless you own them (i.e. you *are* the IP object) */ inline int udp_send(std::shared_ptr pckt) { return _udp.transmit(pckt); } @@ -62,7 +62,7 @@ namespace net { } /// send an UDPv6 packet, hopefully (please dont lie!) std::shared_ptr udp6_create( - Ethernet::addr ether_dest, const IP6::addr& ip_dest, UDPv6::port_t port) + Ethernet::addr ether_dest, const IP6::addr& ip_dest, UDPv6::port_t port) { return _udp6.create(ether_dest, ip_dest, port); } @@ -79,13 +79,13 @@ namespace net { } /** Bind an IP and a netmask to a given device. - The function expects the given device to exist.*/ + The function expects the given device to exist.*/ static void ifconfig( - netdev nic, - IP4::addr ip, - IP4::addr netmask, - IP6::addr ip6); + netdev nic, + IP4::addr ip, + IP4::addr netmask, + IP6::addr ip6); inline static IP4::addr ip4(netdev nic) { return _ip4_list[nic]; } @@ -124,15 +124,15 @@ namespace net { /** Don't think we *want* copy construction. - @todo: Fix this with a singleton or something. + @todo: Fix this with a singleton or something. */ Inet(Inet& UNUSED(cpy)) = delete; Inet(std::vector ips); /** Initialize. For now IP and mac is passed on to Ethernet and Arp. - @todo For now, mac- and IP-addresses are hardcoded here. - They should be user-definable + @todo For now, mac- and IP-addresses are hardcoded here. + They should be user-definable */ Inet(); diff --git a/api/net/ip4/arp.hpp b/api/net/ip4/arp.hpp index 121664fafb..1a44fdbbe5 100644 --- a/api/net/ip4/arp.hpp +++ b/api/net/ip4/arp.hpp @@ -96,11 +96,11 @@ namespace net { void set_resolver(Resolver_name nm) { // @TODO: Add HÅREK-mapping here switch (nm) { - case HH_MAP: - arp_resolver_ = Arp_resolver::from(*this); - break; + case HH_MAP: + arp_resolver_ = Arp_resolver::from(*this); + break; default: - arp_resolver_ = Arp_resolver::from(*this); + arp_resolver_ = Arp_resolver::from(*this); } } diff --git a/api/net/ip4/ip4.hpp b/api/net/ip4/ip4.hpp index 4414c88836..2a369e8716 100644 --- a/api/net/ip4/ip4.hpp +++ b/api/net/ip4/ip4.hpp @@ -50,8 +50,8 @@ namespace net { */ inline addr& operator=(addr cpy) noexcept { - whole = cpy.whole; - return *this; + whole = cpy.whole; + return *this; } /** Standard comparison operators */ @@ -81,10 +81,10 @@ namespace net { /** x.x.x.x string representation */ std::string str() const { - char ip_addr[16]; - sprintf(ip_addr, "%1i.%1i.%1i.%1i", - part[0], part[1], part[2], part[3]); - return ip_addr; + char ip_addr[16]; + sprintf(ip_addr, "%1i.%1i.%1i.%1i", + part[0], part[1], part[2], part[3]); + return ip_addr; } }; //< union addr diff --git a/api/net/ip4/packet_ip4.hpp b/api/net/ip4/packet_ip4.hpp index 918ec77f1d..34e016d3ed 100644 --- a/api/net/ip4/packet_ip4.hpp +++ b/api/net/ip4/packet_ip4.hpp @@ -26,7 +26,7 @@ namespace net { class PacketIP4 : public Packet, // might work as upcast: - public std::enable_shared_from_this + public std::enable_shared_from_this { public: static constexpr size_t DEFAULT_TTL {64}; diff --git a/api/net/ip4/packet_tcp.hpp b/api/net/ip4/packet_tcp.hpp index a21fccf5f1..4507ed9627 100644 --- a/api/net/ip4/packet_tcp.hpp +++ b/api/net/ip4/packet_tcp.hpp @@ -26,7 +26,7 @@ namespace net /** A TCP Packet wrapper, with no data just methods. */ class TCP_packet : public PacketIP4, // might work as upcast: - public std::enable_shared_from_this + public std::enable_shared_from_this { public: diff --git a/api/net/ip4/udp.hpp b/api/net/ip4/udp.hpp index ea71d3a3ce..016e40267c 100644 --- a/api/net/ip4/udp.hpp +++ b/api/net/ip4/udp.hpp @@ -71,10 +71,10 @@ namespace net { /** Send UDP datagram from source ip/port to destination ip/port. - @param sip Local IP-address - @param sport Local port - @param dip Remote IP-address - @param dport Remote port */ + @param sip Local IP-address + @param sport Local port + @param dip Remote IP-address + @param dport Remote port */ void transmit(std::shared_ptr udp); //! @param port local port diff --git a/api/net/ip6/ip6.hpp b/api/net/ip6/ip6.hpp index 1378c2021d..e159208e8a 100644 --- a/api/net/ip6/ip6.hpp +++ b/api/net/ip6/ip6.hpp @@ -44,15 +44,15 @@ namespace net /** Known transport layer protocols. */ enum proto { - PROTO_HOPOPT = 0, // IPv6 hop-by-hop + PROTO_HOPOPT = 0, // IPv6 hop-by-hop - PROTO_ICMPv4 = 1, - PROTO_TCP = 6, - PROTO_UDP = 17, + PROTO_ICMPv4 = 1, + PROTO_TCP = 6, + PROTO_UDP = 17, - PROTO_ICMPv6 = 58, // IPv6 ICMP - PROTO_NoNext = 59, // no next-header - PROTO_OPTSv6 = 60, // dest options + PROTO_ICMPv6 = 58, // IPv6 ICMP + PROTO_NoNext = 59, // no next-header + PROTO_OPTSv6 = 60, // dest options }; struct addr @@ -64,11 +64,11 @@ namespace net uint16_t c1, uint16_t c2, uint16_t d1, uint16_t d2) { i128 = _mm_set_epi16( - //d2, d1, c2, c1, b2, b1, a2, a1); - htons(d2), htons(d1), - htons(c2), htons(c1), - htons(b2), htons(b1), - htons(a2), htons(a1)); + //d2, d1, c2, c1, b2, b1, a2, a1); + htons(d2), htons(d1), + htons(c2), htons(c1), + htons(b2), htons(b1), + htons(a2), htons(a1)); } addr(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { @@ -121,15 +121,15 @@ namespace net bool is_multicast() const { /** - RFC 4291 2.7 Multicast Addresses + RFC 4291 2.7 Multicast Addresses - An IPv6 multicast address is an identifier for a group of interfaces - (typically on different nodes). An interface may belong to any - number of multicast groups. Multicast addresses have the following format: - | 8 | 4 | 4 | 112 bits | - +------ -+----+----+---------------------------------------------+ - |11111111|flgs|scop| group ID | - +--------+----+----+---------------------------------------------+ + An IPv6 multicast address is an identifier for a group of interfaces + (typically on different nodes). An interface may belong to any + number of multicast groups. Multicast addresses have the following format: + | 8 | 4 | 4 | 112 bits | + +------ -+----+----+---------------------------------------------+ + |11111111|flgs|scop| group ID | + +--------+----+----+---------------------------------------------+ **/ return i8[0] == 0xFF; } @@ -153,7 +153,7 @@ namespace net uint8_t tclass() const { return ((scanline[0] & 0xF000) >> 12) + - (scanline[0] & 0xF); + (scanline[0] & 0xF); } // initializes the first scanline with the IPv6 version void init_scan0() @@ -164,7 +164,7 @@ namespace net uint16_t size() const { return ((scanline[1] & 0x00FF) << 8) + - ((scanline[1] & 0xFF00) >> 8); + ((scanline[1] & 0xFF00) >> 8); } void set_size(uint16_t newsize) { @@ -243,25 +243,25 @@ namespace net static std::string protocol_name(uint8_t protocol) { switch (protocol) - { - case PROTO_HOPOPT: - return "IPv6 Hop-By-Hop (0)"; + { + case PROTO_HOPOPT: + return "IPv6 Hop-By-Hop (0)"; - case PROTO_TCP: - return "TCPv6 (6)"; - case PROTO_UDP: - return "UDPv6 (17)"; + case PROTO_TCP: + return "TCPv6 (6)"; + case PROTO_UDP: + return "UDPv6 (17)"; - case PROTO_ICMPv6: - return "ICMPv6 (58)"; - case PROTO_NoNext: - return "No next header (59)"; - case PROTO_OPTSv6: - return "IPv6 destination options (60)"; + case PROTO_ICMPv6: + return "ICMPv6 (58)"; + case PROTO_NoNext: + return "No next header (59)"; + case PROTO_OPTSv6: + return "IPv6 destination options (60)"; - default: - return "Unknown: " + std::to_string(protocol); - } + default: + return "Unknown: " + std::to_string(protocol); + } } // handler for upstream IPv6 packets @@ -283,7 +283,7 @@ namespace net // creates a new IPv6 packet to be sent over the ether static std::shared_ptr create(uint8_t proto, - Ethernet::addr ether_dest, const IP6::addr& dest); + Ethernet::addr ether_dest, const IP6::addr& dest); private: addr local; diff --git a/api/net/ip6/udp6.hpp b/api/net/ip6/udp6.hpp index 30ca33a5f8..380128363d 100644 --- a/api/net/ip6/udp6.hpp +++ b/api/net/ip6/udp6.hpp @@ -72,7 +72,7 @@ namespace net // creates a new packet to be sent over the ether std::shared_ptr create( - Ethernet::addr ether_dest, const IP6::addr& dest, port_t port); + Ethernet::addr ether_dest, const IP6::addr& dest, port_t port); private: std::map listeners; @@ -125,7 +125,7 @@ namespace net header().length = htons(sizeof(UDPv6::header) + newlen); // new total IPv6 payload length ip6_header().set_size( - sizeof(IP6::header) + sizeof(UDPv6::header) + newlen); + sizeof(IP6::header) + sizeof(UDPv6::header) + newlen); // new total packet length size_ = sizeof(IP6::full_header) + sizeof(UDPv6::header) + newlen; } diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index 5a281dbdd4..d9e30d5e18 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -63,50 +63,50 @@ namespace net { class Socket { public: /* - Intialize an empty socket. + Intialize an empty socket. */ inline Socket() : address_(), port_(0) { address_.whole = 0; }; /* - Create a socket with a Address and Port. + Create a socket with a Address and Port. */ inline Socket(Address address, Port port) : address_(address), port_(port) {}; /* - Returns the Socket's address. + Returns the Socket's address. */ inline const TCP::Address address() const { return address_; } /* - Returns the Socket's port. + Returns the Socket's port. */ inline TCP::Port port() const { return port_; } /* - Returns a string in the format "Address:Port". + Returns a string in the format "Address:Port". */ std::string to_string() const { - std::stringstream ss; - ss << address_.str() << ":" << port_; - return ss.str(); + std::stringstream ss; + ss << address_.str() << ":" << port_; + return ss.str(); } inline bool is_empty() const { return (address_.whole == 0 and port_ == 0); } /* - Comparator used for vector. + Comparator used for vector. */ inline bool operator ==(const Socket &s2) const { - return address().whole == s2.address().whole - and port() == s2.port(); + return address().whole == s2.address().whole + and port() == s2.port(); } /* - Comparator used for map. + Comparator used for map. */ inline bool operator <(const Socket& s2) const { - return address().whole < s2.address().whole - or (address().whole == s2.address().whole and port() < s2.port()); + return address().whole < s2.address().whole + or (address().whole == s2.address().whole and port() < s2.port()); } private: @@ -127,15 +127,15 @@ namespace net { Flags (Control bits) in the TCP Header. */ enum Flag { - NS = (1 << 8), // Nounce (Experimental: see RFC 3540) - CWR = (1 << 7), // Congestion Window Reduced - ECE = (1 << 6), // ECN-Echo - URG = (1 << 5), // Urgent - ACK = (1 << 4), // Acknowledgement - PSH = (1 << 3), // Push - RST = (1 << 2), // Reset - SYN = (1 << 1), // Syn(chronize) - FIN = 1, // Fin(ish) + NS = (1 << 8), // Nounce (Experimental: see RFC 3540) + CWR = (1 << 7), // Congestion Window Reduced + ECE = (1 << 6), // ECN-Echo + URG = (1 << 5), // Urgent + ACK = (1 << 4), // Acknowledgement + PSH = (1 << 3), // Push + RST = (1 << 2), // Reset + SYN = (1 << 1), // Syn(chronize) + FIN = 1, // Fin(ish) }; /* @@ -163,21 +163,21 @@ namespace net { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ struct Header { - TCP::Port source_port; // Source port - TCP::Port destination_port; // Destination port - uint32_t seq_nr; // Sequence number - uint32_t ack_nr; // Acknowledge number + TCP::Port source_port; // Source port + TCP::Port destination_port; // Destination port + uint32_t seq_nr; // Sequence number + uint32_t ack_nr; // Acknowledge number union { - uint16_t whole; // Reference to offset_reserved & flags together. - struct { - uint8_t offset_reserved; // Offset (4 bits) + Reserved (3 bits) + NS (1 bit) - uint8_t flags; // All Flags (Control bits) except NS (9 bits - 1 bit) - }; - } offset_flags; // Data offset + Reserved + Flags (16 bits) - uint16_t window_size; // Window size - uint16_t checksum; // Checksum - uint16_t urgent; // Urgent pointer offset - uint8_t options[0]; // Options + uint16_t whole; // Reference to offset_reserved & flags together. + struct { + uint8_t offset_reserved; // Offset (4 bits) + Reserved (3 bits) + NS (1 bit) + uint8_t flags; // All Flags (Control bits) except NS (9 bits - 1 bit) + }; + } offset_flags; // Data offset + Reserved + Flags (16 bits) + uint16_t window_size; // Window size + uint16_t checksum; // Checksum + uint16_t urgent; // Urgent pointer offset + uint8_t options[0]; // Options }__attribute__((packed)); // << struct TCP::Header @@ -218,35 +218,35 @@ namespace net { uint8_t data[0]; enum Kind { - END = 0x00, // End of option list - NOP = 0x01, // No-Opeartion - MSS = 0x02, // Maximum Segment Size [RFC 793] Rev: [879, 6691] + END = 0x00, // End of option list + NOP = 0x01, // No-Opeartion + MSS = 0x02, // Maximum Segment Size [RFC 793] Rev: [879, 6691] }; static std::string kind_string(Kind kind) { - switch(kind) { - case MSS: - return {"MSS"}; + switch(kind) { + case MSS: + return {"MSS"}; - default: - return {"Unknown Option"}; - } + default: + return {"Unknown Option"}; + } } struct opt_mss { - uint8_t kind; - uint8_t length; - uint16_t mss; + uint8_t kind; + uint8_t length; + uint16_t mss; - opt_mss(uint16_t mss) - : kind(MSS), length(4), mss(htons(mss)) {} + opt_mss(uint16_t mss) + : kind(MSS), length(4), mss(htons(mss)) {} }; struct opt_timestamp { - uint8_t kind; - uint8_t length; - uint32_t ts_val; - uint32_t ts_ecr; + uint8_t kind; + uint8_t length; + uint32_t ts_val; + uint32_t ts_ecr; }; }; @@ -260,7 +260,7 @@ namespace net { inline TCP::Header& header() const { - return ((TCP::Full_header*) buffer())->tcp; + return ((TCP::Full_header*) buffer())->tcp; } static const size_t HEADERS_SIZE = sizeof(TCP::Full_header); @@ -269,16 +269,16 @@ namespace net { //! a valid MTU-sized buffer void init() { - // Erase all headers (smart? necessary? ...well, convenient) - memset(buffer(), 0, HEADERS_SIZE); - PacketIP4::init(); + // Erase all headers (smart? necessary? ...well, convenient) + memset(buffer(), 0, HEADERS_SIZE); + PacketIP4::init(); - set_protocol(IP4::IP4_TCP); - set_win_size(TCP::default_window_size); - set_offset(5); + set_protocol(IP4::IP4_TCP); + set_win_size(TCP::default_window_size); + set_offset(5); - // set TCP payload location (!?) - set_payload(buffer() + all_headers_len()); + // set TCP payload location (!?) + set_payload(buffer() + all_headers_len()); } // GETTERS @@ -298,67 +298,67 @@ namespace net { // SETTERS inline TCP::Packet& set_src_port(TCP::Port p) { - header().source_port = htons(p); - return *this; + header().source_port = htons(p); + return *this; } inline TCP::Packet& set_dst_port(TCP::Port p) { - header().destination_port = htons(p); - return *this; + header().destination_port = htons(p); + return *this; } inline TCP::Packet& set_seq(TCP::Seq n) { - header().seq_nr = htonl(n); - return *this; + header().seq_nr = htonl(n); + return *this; } inline TCP::Packet& set_ack(TCP::Seq n) { - header().ack_nr = htonl(n); - return *this; + header().ack_nr = htonl(n); + return *this; } inline TCP::Packet& set_win_size(uint16_t size) { - header().window_size = htons(size); - return *this; + header().window_size = htons(size); + return *this; } inline TCP::Packet& set_checksum(uint16_t checksum) { - header().checksum = checksum; - return *this; + header().checksum = checksum; + return *this; } inline TCP::Packet& set_source(const TCP::Socket& src) { - set_src(src.address()); // PacketIP4::set_src - set_src_port(src.port()); - return *this; + set_src(src.address()); // PacketIP4::set_src + set_src_port(src.port()); + return *this; } inline TCP::Packet& set_destination(const TCP::Socket& dest) { - set_dst(dest.address()); // PacketIP4::set_dst - set_dst_port(dest.port()); - return *this; + set_dst(dest.address()); // PacketIP4::set_dst + set_dst_port(dest.port()); + return *this; } /// FLAGS / CONTROL BITS /// inline TCP::Packet& set_flag(TCP::Flag f) { - header().offset_flags.whole |= htons(f); - return *this; + header().offset_flags.whole |= htons(f); + return *this; } inline TCP::Packet& set_flags(uint16_t f) { - header().offset_flags.whole |= htons(f); - return *this; + header().offset_flags.whole |= htons(f); + return *this; } inline TCP::Packet& clear_flag(TCP::Flag f) { - header().offset_flags.whole &= ~ htons(f); - return *this; + header().offset_flags.whole &= ~ htons(f); + return *this; } inline TCP::Packet& clear_flags() { - header().offset_flags.whole &= 0x00ff; - return *this; + header().offset_flags.whole &= 0x00ff; + return *this; } inline bool isset(TCP::Flag f) { return ntohs(header().offset_flags.whole) & f; } @@ -414,30 +414,30 @@ namespace net { // sets the correct length for all the protocols up to IP4 void set_length(uint16_t newlen = 0) { - // new total packet length - set_size( all_headers_len() + newlen ); + // new total packet length + set_size( all_headers_len() + newlen ); } //! assuming the packet has been properly initialized, //! this will fill bytes from @buffer into this packets buffer, //! then return the number of bytes written. buffer is unmodified size_t fill(const char* buffer, size_t length) { - size_t rem = capacity() - all_headers_len(); - size_t total = (length < rem) ? length : rem; - // copy from buffer to packet buffer - memcpy(data() + data_length(), buffer, total); - // set new packet length - set_length(data_length() + total); - return total; + size_t rem = capacity() - all_headers_len(); + size_t total = (length < rem) ? length : rem; + // copy from buffer to packet buffer + memcpy(data() + data_length(), buffer, total); + // set new packet length + set_length(data_length() + total); + return total; } inline std::string to_string() { - std::ostringstream os; - os << "[ S:" << source().to_string() << " D:" << destination().to_string() - << " SEQ:" << seq() << " ACK:" << ack() - << " HEAD-LEN:" << (int)header_size() << " OPT-LEN:" << (int)options_length() << " DATA-LEN:" << data_length() - << " WIN:" << win() << " FLAGS:" << std::bitset<8>{header().offset_flags.flags} << " ]"; - return os.str(); + std::ostringstream os; + os << "[ S:" << source().to_string() << " D:" << destination().to_string() + << " SEQ:" << seq() << " ACK:" << ack() + << " HEAD-LEN:" << (int)header_size() << " OPT-LEN:" << (int)options_length() << " DATA-LEN:" << data_length() + << " WIN:" << win() << " FLAGS:" << std::bitset<8>{header().offset_flags.flags} << " ]"; + return os.str(); } }; // << class TCP::Packet @@ -457,8 +457,8 @@ namespace net { class TCPBadOptionException : public TCPException { public: TCPBadOptionException(Option::Kind kind, const std::string& error) : - TCPException("Bad Option [" + Option::kind_string(kind) + "]: " + error), - kind_(kind) {}; + TCPException("Bad Option [" + Option::kind_string(kind) + "]: " + error), + kind_(kind) {}; Option::Kind kind(); private: @@ -475,272 +475,272 @@ namespace net { public: /* - Wrapper around a buffer that receives data. + Wrapper around a buffer that receives data. */ struct ReadBuffer { - buffer_t buffer; - size_t remaining; - size_t offset; - bool push; + buffer_t buffer; + size_t remaining; + size_t offset; + bool push; - ReadBuffer(buffer_t buf, size_t length, size_t offs = 0) - : buffer(buf), remaining(length-offs), offset(offs), push(false) {} + ReadBuffer(buffer_t buf, size_t length, size_t offs = 0) + : buffer(buf), remaining(length-offs), offset(offs), push(false) {} - inline size_t capacity() const { return remaining + offset; } + inline size_t capacity() const { return remaining + offset; } - inline bool empty() const { return offset == 0; } + inline bool empty() const { return offset == 0; } - inline bool full() const { return remaining == 0; } + inline bool full() const { return remaining == 0; } - inline size_t size() const { return offset; } + inline size_t size() const { return offset; } - inline uint8_t* begin() const { return buffer.get(); } + inline uint8_t* begin() const { return buffer.get(); } - inline uint8_t* pos() const { return buffer.get() + offset; } + inline uint8_t* pos() const { return buffer.get() + offset; } - inline uint8_t* end() const { return buffer.get() + capacity(); } + inline uint8_t* end() const { return buffer.get() + capacity(); } - inline bool advance(size_t length) { - assert(length <= remaining); - offset += length; - remaining -= length; - return length > 0; - } + inline bool advance(size_t length) { + assert(length <= remaining); + offset += length; + remaining -= length; + return length > 0; + } - inline size_t add(uint8_t* data, size_t n) { - auto written = std::min(n, remaining); - memcpy(pos(), data, written); - return written; - } + inline size_t add(uint8_t* data, size_t n) { + auto written = std::min(n, remaining); + memcpy(pos(), data, written); + return written; + } - inline void clear() { - memset(begin(), 0, offset); - remaining = capacity(); - offset = 0; - push = false; - } + inline void clear() { + memset(begin(), 0, offset); + remaining = capacity(); + offset = 0; + push = false; + } }; // < Connection::ReadBuffer /* - Wrapper around a buffer that contains data to be written. + Wrapper around a buffer that contains data to be written. */ struct WriteBuffer { - buffer_t buffer; - size_t remaining; - size_t offset; - bool push; + buffer_t buffer; + size_t remaining; + size_t offset; + bool push; - WriteBuffer(buffer_t buf, size_t length, bool PSH, size_t offs = 0) - : buffer(buf), remaining(length-offs), offset(offs), push(PSH) {} + WriteBuffer(buffer_t buf, size_t length, bool PSH, size_t offs = 0) + : buffer(buf), remaining(length-offs), offset(offs), push(PSH) {} - inline size_t length() const { return remaining + offset; } + inline size_t length() const { return remaining + offset; } - inline bool done() const { return remaining == 0; } + inline bool done() const { return remaining == 0; } - inline uint8_t* begin() const { return buffer.get(); } + inline uint8_t* begin() const { return buffer.get(); } - inline uint8_t* pos() const { return buffer.get() + offset; } + inline uint8_t* pos() const { return buffer.get() + offset; } - inline uint8_t* end() const { return buffer.get() + length(); } + inline uint8_t* end() const { return buffer.get() + length(); } - inline bool advance(size_t length) { - assert(length <= remaining); - offset += length; - remaining -= length; - return length > 0; - } + inline bool advance(size_t length) { + assert(length <= remaining); + offset += length; + remaining -= length; + return length > 0; + } }; // < Connection::WriteBuffer /* - Callback when a receive buffer receives either push or is full - - Supplied on asynchronous read + Callback when a receive buffer receives either push or is full + - Supplied on asynchronous read */ using ReadCallback = delegate; struct ReadRequest { - ReadBuffer buffer; - ReadCallback callback; + ReadBuffer buffer; + ReadCallback callback; - ReadRequest(ReadBuffer buf, ReadCallback cb) : buffer(buf), callback(cb) {} - ReadRequest(size_t n = 0) : - buffer(buffer_t(new uint8_t[n], std::default_delete()), n), - callback([](auto, auto){}) {} + ReadRequest(ReadBuffer buf, ReadCallback cb) : buffer(buf), callback(cb) {} + ReadRequest(size_t n = 0) : + buffer(buffer_t(new uint8_t[n], std::default_delete()), n), + callback([](auto, auto){}) {} }; /* - Callback when a write is sent by the TCP - - Supplied on asynchronous write + Callback when a write is sent by the TCP + - Supplied on asynchronous write */ using WriteCallback = delegate; using WriteRequest = std::pair; /* - Connection identifier + Connection identifier */ using Tuple = std::pair; /// CALLBACKS /// /* - On connection attempt - When a remote sends SYN to connection in LISTENING state. - First thing that will happen. + On connection attempt - When a remote sends SYN to connection in LISTENING state. + First thing that will happen. */ - using AcceptCallback = delegate)>; + using AcceptCallback = delegate)>; /* - On connected - When both hosts exchanged sequence numbers (handshake is done). - Now in ESTABLISHED state - it's allowed to write and read to/from the remote. + On connected - When both hosts exchanged sequence numbers (handshake is done). + Now in ESTABLISHED state - it's allowed to write and read to/from the remote. */ - using ConnectCallback = delegate)>; + using ConnectCallback = delegate)>; /* - On disconnect - When a remote told it wanna close the connection. - Connection has received a FIN, currently last thing that will happen before a connection is remoed. + On disconnect - When a remote told it wanna close the connection. + Connection has received a FIN, currently last thing that will happen before a connection is remoed. */ struct Disconnect; - using DisconnectCallback = delegate, Disconnect)>; + using DisconnectCallback = delegate, Disconnect)>; /* - On error - When any of the users request fails. + On error - When any of the users request fails. */ - using ErrorCallback = delegate, TCPException)>; + using ErrorCallback = delegate, TCPException)>; /* - When a packet is received - Everytime a connection receives an incoming packet. - Would probably be used for debugging. - (Currently not in use) + When a packet is received - Everytime a connection receives an incoming packet. + Would probably be used for debugging. + (Currently not in use) */ - using PacketReceivedCallback = delegate, TCP::Packet_ptr)>; + using PacketReceivedCallback = delegate, TCP::Packet_ptr)>; /* - When a packet is dropped - Everytime an incoming packet is unallowed, it will be dropped. - Can be used for debugging. + When a packet is dropped - Everytime an incoming packet is unallowed, it will be dropped. + Can be used for debugging. */ - using PacketDroppedCallback = delegate; + using PacketDroppedCallback = delegate; /* - Reason for disconnect event. + Reason for disconnect event. */ struct Disconnect { public: - enum Reason { - CLOSING, - REFUSED, - RESET - }; - - Reason reason; - - explicit Disconnect(Reason reason) : reason(reason) {} - - inline operator Reason() const noexcept { return reason; } - - inline operator std::string() const noexcept { return to_string(); } - - inline bool operator ==(const Disconnect& dc) const { return reason == dc.reason; } - - std::string to_string() const { - switch(reason) { - case CLOSING: - return "Connection closing"; - case REFUSED: - return "Conneciton refused"; - case RESET: - return "Connection reset"; - default: - return "Unknown reason"; - } - } + enum Reason { + CLOSING, + REFUSED, + RESET + }; + + Reason reason; + + explicit Disconnect(Reason reason) : reason(reason) {} + + inline operator Reason() const noexcept { return reason; } + + inline operator std::string() const noexcept { return to_string(); } + + inline bool operator ==(const Disconnect& dc) const { return reason == dc.reason; } + + std::string to_string() const { + switch(reason) { + case CLOSING: + return "Connection closing"; + case REFUSED: + return "Conneciton refused"; + case RESET: + return "Connection reset"; + default: + return "Unknown reason"; + } + } }; // < struct TCP::Connection::Disconnect /* - Interface for one of the many states a Connection can have. + Interface for one of the many states a Connection can have. */ class State { public: - enum Result { - CLOSED = -1, - OK = 0, - CLOSE = 1 - }; - /* - Open a Connection. - OPEN - */ - virtual void open(Connection&, bool active = false); - - /* - Write to a Connection. - SEND - */ - virtual size_t send(Connection&, WriteBuffer&); - - /* - Read from a Connection. - RECEIVE - */ - virtual void receive(Connection&, ReadBuffer&); - - /* - Close a Connection. - CLOSE - */ - virtual void close(Connection&); - - /* - Terminate a Connection. - ABORT - */ - virtual void abort(Connection&); - - /* - Handle a Packet - SEGMENT ARRIVES - */ - virtual Result handle(Connection&, TCP::Packet_ptr in) = 0; - - /* - The current state represented as a string. - STATUS - */ - virtual std::string to_string() const = 0; - - /* - - */ - virtual bool is_connected() const { return false; } - - virtual bool is_writable() const { return false; } - - virtual bool is_readable() const { return false; } - - virtual bool is_closing() const { return false; } + enum Result { + CLOSED = -1, + OK = 0, + CLOSE = 1 + }; + /* + Open a Connection. + OPEN + */ + virtual void open(Connection&, bool active = false); + + /* + Write to a Connection. + SEND + */ + virtual size_t send(Connection&, WriteBuffer&); + + /* + Read from a Connection. + RECEIVE + */ + virtual void receive(Connection&, ReadBuffer&); + + /* + Close a Connection. + CLOSE + */ + virtual void close(Connection&); + + /* + Terminate a Connection. + ABORT + */ + virtual void abort(Connection&); + + /* + Handle a Packet + SEGMENT ARRIVES + */ + virtual Result handle(Connection&, TCP::Packet_ptr in) = 0; + + /* + The current state represented as a string. + STATUS + */ + virtual std::string to_string() const = 0; + + /* + + */ + virtual bool is_connected() const { return false; } + + virtual bool is_writable() const { return false; } + + virtual bool is_readable() const { return false; } + + virtual bool is_closing() const { return false; } protected: - /* - Helper functions - TODO: Clean up names. - */ - virtual bool check_seq(Connection&, TCP::Packet_ptr); + /* + Helper functions + TODO: Clean up names. + */ + virtual bool check_seq(Connection&, TCP::Packet_ptr); - virtual void unallowed_syn_reset_connection(Connection&, TCP::Packet_ptr); + virtual void unallowed_syn_reset_connection(Connection&, TCP::Packet_ptr); - virtual bool check_ack(Connection&, TCP::Packet_ptr); + virtual bool check_ack(Connection&, TCP::Packet_ptr); - virtual void process_segment(Connection&, TCP::Packet_ptr); + virtual void process_segment(Connection&, TCP::Packet_ptr); - virtual void process_fin(Connection&, TCP::Packet_ptr); + virtual void process_fin(Connection&, TCP::Packet_ptr); - virtual void send_reset(Connection&); + virtual void send_reset(Connection&); }; // < class TCP::Connection::State /* - Forward declaration of concrete states. - Definition in "tcp_connection_states.hpp" + Forward declaration of concrete states. + Definition in "tcp_connection_states.hpp" */ class Closed; class Listen; @@ -755,261 +755,261 @@ namespace net { class TimeWait; /* - Transmission Control Block. - Keep tracks of all the data for a connection. + Transmission Control Block. + Keep tracks of all the data for a connection. - RFC 793: Page 19 - Among the variables stored in the - TCB are the local and remote socket numbers, the security and - precedence of the connection, pointers to the user's send and receive - buffers, pointers to the retransmit queue and to the current segment. - In addition several variables relating to the send and receive - sequence numbers are stored in the TCB. + RFC 793: Page 19 + Among the variables stored in the + TCB are the local and remote socket numbers, the security and + precedence of the connection, pointers to the user's send and receive + buffers, pointers to the retransmit queue and to the current segment. + In addition several variables relating to the send and receive + sequence numbers are stored in the TCB. */ struct TCB { - /* Send Sequence Variables */ - struct { - TCP::Seq UNA; // send unacknowledged - TCP::Seq NXT; // send next - uint16_t WND; // send window - uint16_t UP; // send urgent pointer - TCP::Seq WL1; // segment sequence number used for last window update - TCP::Seq WL2; // segment acknowledgment number used for last window update - - uint16_t MSS; // Maximum segment size for outgoing segments. - } SND; // << - TCP::Seq ISS; // initial send sequence number - - /* Receive Sequence Variables */ - struct { - TCP::Seq NXT; // receive next - uint16_t WND; // receive window - uint16_t UP; // receive urgent pointer - } RCV; // << - TCP::Seq IRS; // initial receive sequence number - - TCB() { - SND = { 0, 0, TCP::default_window_size, 0, 0, 0, TCP::default_mss }; - ISS = 0; - RCV = { 0, TCP::default_window_size, 0 }; - IRS = 0; - }; - - std::string to_string() const; + /* Send Sequence Variables */ + struct { + TCP::Seq UNA; // send unacknowledged + TCP::Seq NXT; // send next + uint16_t WND; // send window + uint16_t UP; // send urgent pointer + TCP::Seq WL1; // segment sequence number used for last window update + TCP::Seq WL2; // segment acknowledgment number used for last window update + + uint16_t MSS; // Maximum segment size for outgoing segments. + } SND; // << + TCP::Seq ISS; // initial send sequence number + + /* Receive Sequence Variables */ + struct { + TCP::Seq NXT; // receive next + uint16_t WND; // receive window + uint16_t UP; // receive urgent pointer + } RCV; // << + TCP::Seq IRS; // initial receive sequence number + + TCB() { + SND = { 0, 0, TCP::default_window_size, 0, 0, 0, TCP::default_mss }; + ISS = 0; + RCV = { 0, TCP::default_window_size, 0 }; + IRS = 0; + }; + + std::string to_string() const; }__attribute__((packed)); // < struct TCP::Connection::TCB /* - Creates a connection without a remote. + Creates a connection without a remote. */ Connection(TCP& host, Port local_port); /* - Creates a connection with a remote. + Creates a connection with a remote. */ Connection(TCP& host, Port local_port, Socket remote); /* - The hosting TCP instance. + The hosting TCP instance. */ inline const TCP& host() const { return host_; } /* - The local Socket bound to this connection. + The local Socket bound to this connection. */ inline TCP::Socket local() const { return {host_.inet_.ip_addr(), local_port_}; } /* - The remote Socket bound to this connection. + The remote Socket bound to this connection. */ inline TCP::Socket remote() const { return remote_; } /* - Set remote Socket bound to this connection. - @WARNING: Should this be public? Used by TCP. + Set remote Socket bound to this connection. + @WARNING: Should this be public? Used by TCP. */ inline void set_remote(Socket remote) { remote_ = remote; } /* - Read asynchronous from a remote. + Read asynchronous from a remote. - Create n sized internal read buffer and callback for when data is received. - Callback will be called until overwritten with a new read() or connection closes. - Buffer is cleared for data after every reset. + Create n sized internal read buffer and callback for when data is received. + Callback will be called until overwritten with a new read() or connection closes. + Buffer is cleared for data after every reset. */ inline void read(size_t n, ReadCallback callback) { - ReadBuffer buffer = {buffer_t(new uint8_t[n], std::default_delete()), n}; - read(buffer, callback); + ReadBuffer buffer = {buffer_t(new uint8_t[n], std::default_delete()), n}; + read(buffer, callback); } /* - Assign the connections receive buffer and callback for when data is received. - Works as read(size_t, ReadCallback); + Assign the connections receive buffer and callback for when data is received. + Works as read(size_t, ReadCallback); */ inline void read(buffer_t buffer, size_t n, ReadCallback callback) { - read({buffer, n}, callback); + read({buffer, n}, callback); } void read(ReadBuffer buffer, ReadCallback callback); /* - Write asynchronous to a remote. + Write asynchronous to a remote. - Copies the data from the buffer into an internal buffer. Callback is called when a a write is either done or aborted. - Immediately tries to write the data to the connection. If not possible, queues the write for processing when possible (FIFO). + Copies the data from the buffer into an internal buffer. Callback is called when a a write is either done or aborted. + Immediately tries to write the data to the connection. If not possible, queues the write for processing when possible (FIFO). */ inline void write(const void* buf, size_t n, WriteCallback callback, bool PUSH = true) { - auto buffer = buffer_t(new uint8_t[n], std::default_delete()); - memcpy(buffer.get(), buf, n); - write(buffer, n, callback, PUSH); + auto buffer = buffer_t(new uint8_t[n], std::default_delete()); + memcpy(buffer.get(), buf, n); + write(buffer, n, callback, PUSH); } /* - Works as write(const void*, size_t, WriteCallback, bool), - but with the exception of avoiding copying the data to an internal buffer. + Works as write(const void*, size_t, WriteCallback, bool), + but with the exception of avoiding copying the data to an internal buffer. */ inline void write(buffer_t buffer, size_t n, WriteCallback callback, bool PUSH = true) { - write({buffer, n, PUSH}, callback); + write({buffer, n, PUSH}, callback); } /* - Works the same as it's counterpart, without subscribing to a WriteCallback. + Works the same as it's counterpart, without subscribing to a WriteCallback. */ inline void write(const void* buf, size_t n, bool PUSH = true) { - write(buf, n, [](auto){}, PUSH); + write(buf, n, [](auto){}, PUSH); } /* - Works the same as it's counterpart, without subscribing to a WriteCallback. + Works the same as it's counterpart, without subscribing to a WriteCallback. */ inline void write(buffer_t buffer, size_t n, bool PUSH = true) { - write({buffer, n, PUSH}, [](auto){}); + write({buffer, n, PUSH}, [](auto){}); } void write(WriteBuffer request, WriteCallback callback); /* - Open connection. + Open connection. */ void open(bool active = false); /* - Close connection. + Close connection. */ void close(); /* - Abort connection. (Same as Terminate) + Abort connection. (Same as Terminate) */ inline void abort() { - state_->abort(*this); - signal_close(); + state_->abort(*this); + signal_close(); } /* - Set callback for ACCEPT event. + Set callback for ACCEPT event. */ inline Connection& onAccept(AcceptCallback callback) { - on_accept_ = callback; - return *this; + on_accept_ = callback; + return *this; } /* - Set callback for CONNECT event. + Set callback for CONNECT event. */ inline Connection& onConnect(ConnectCallback callback) { - on_connect_ = callback; - return *this; + on_connect_ = callback; + return *this; } /* - Set callback for DISCONNECT event. + Set callback for DISCONNECT event. */ inline Connection& onDisconnect(DisconnectCallback callback) { - on_disconnect_ = callback; - return *this; + on_disconnect_ = callback; + return *this; } /* - Set callback for ERROR event. + Set callback for ERROR event. */ inline Connection& onError(ErrorCallback callback) { - on_error_ = callback; - return *this; + on_error_ = callback; + return *this; } /* - Set callback for every packet received. + Set callback for every packet received. */ inline Connection& onPacketReceived(PacketReceivedCallback callback) { - on_packet_received_ = callback; - return *this; + on_packet_received_ = callback; + return *this; } /* - Set callback for when a packet is dropped. + Set callback for when a packet is dropped. */ inline Connection& onPacketDropped(PacketDroppedCallback callback) { - on_packet_dropped_ = callback; - return *this; + on_packet_dropped_ = callback; + return *this; } /* - Represent the Connection as a string (STATUS). + Represent the Connection as a string (STATUS). */ std::string to_string() const; /* - Returns the current state of the connection. + Returns the current state of the connection. */ inline Connection::State& state() const { return *state_; } /* - Returns the previous state of the connection. + Returns the previous state of the connection. */ inline Connection::State& prev_state() const { return *prev_state_; } /* - Calculates and return bytes transmitted. - TODO: Not sure if this will suffice. + Calculates and return bytes transmitted. + TODO: Not sure if this will suffice. */ inline uint32_t bytes_transmitted() const { - return control_block.SND.NXT - control_block.ISS; + return control_block.SND.NXT - control_block.ISS; } /* - Calculates and return bytes received. - TODO: Not sure if this will suffice. + Calculates and return bytes received. + TODO: Not sure if this will suffice. */ inline uint32_t bytes_received() const { - return control_block.RCV.NXT - control_block.IRS; + return control_block.RCV.NXT - control_block.IRS; } /* - Bytes queued for transmission. - TODO: Implement when retransmission is up and running. + Bytes queued for transmission. + TODO: Implement when retransmission is up and running. */ //inline size_t send_queue_bytes() const {} /* - Bytes currently in receive buffer. + Bytes currently in receive buffer. */ inline size_t read_queue_bytes() const { - return read_request.buffer.size(); + return read_request.buffer.size(); } /* - Return the id (TUPLE) of the connection. + Return the id (TUPLE) of the connection. */ inline Connection::Tuple tuple() const { - return {local_port_, remote_}; + return {local_port_, remote_}; } /* - State checks. + State checks. */ bool is_listening() const; @@ -1024,65 +1024,65 @@ namespace net { /* - Helper function for state checks. + Helper function for state checks. */ inline bool is_state(const State& state) const { - return state_ == &state; + return state_ == &state; } inline bool is_state(const std::string& state_str) const { - return state_->to_string() == state_str; + return state_->to_string() == state_str; } /* - Destroy the Connection. + Destroy the Connection. - Clean up. + Clean up. */ ~Connection(); private: /* - "Parent" for Connection. + "Parent" for Connection. */ - TCP& host_; // 4 B + TCP& host_; // 4 B /* - End points. + End points. */ - TCP::Port local_port_; // 2 B - TCP::Socket remote_; // 8~ B + TCP::Port local_port_; // 2 B + TCP::Socket remote_; // 8~ B /* - The current state the Connection is in. - Handles most of the logic. + The current state the Connection is in. + Handles most of the logic. */ - State* state_; // 4 B + State* state_; // 4 B // Previous state. Used to keep track of state transitions. - State* prev_state_; // 4 B + State* prev_state_; // 4 B /* - Keep tracks of all sequence variables. + Keep tracks of all sequence variables. */ - TCB control_block; // 36 B + TCB control_block; // 36 B /* - The given read request + The given read request */ ReadRequest read_request; /* - Queue for write requests to process + Queue for write requests to process */ std::queue write_queue; /* - Bytes queued for transmission. + Bytes queued for transmission. */ //size_t write_queue_total; /* - When time-wait timer was started. + When time-wait timer was started. */ uint64_t time_wait_started; @@ -1092,110 +1092,110 @@ namespace net { /* When a Connection is initiated. */ AcceptCallback on_accept_ = AcceptCallback::from(this); inline bool default_on_accept(std::shared_ptr) { - //debug2(" Connection attempt from: %s \n", conn->remote().to_string().c_str()); - return true; // Always accept + //debug2(" Connection attempt from: %s \n", conn->remote().to_string().c_str()); + return true; // Always accept } /* When Connection is ESTABLISHED. */ ConnectCallback on_connect_ = [](std::shared_ptr) { - debug2(" Connected.\n"); + debug2(" Connected.\n"); }; /* When Connection is CLOSING. */ DisconnectCallback on_disconnect_ = [](std::shared_ptr, Disconnect) { - //debug2(" Connection disconnect. Reason: %s \n", msg.c_str()); + //debug2(" Connection disconnect. Reason: %s \n", msg.c_str()); }; /* When error occcured. */ ErrorCallback on_error_ = ErrorCallback::from(this); inline void default_on_error(std::shared_ptr, TCPException) { - //debug2(" TCPException: %s \n", error.what()); + //debug2(" TCPException: %s \n", error.what()); } /* When packet is received */ PacketReceivedCallback on_packet_received_ = [](std::shared_ptr, TCP::Packet_ptr) { - //debug2(" Packet received: %s \n", packet->to_string().c_str()); + //debug2(" Packet received: %s \n", packet->to_string().c_str()); }; /* When a packet is dropped. */ PacketDroppedCallback on_packet_dropped_ = [](TCP::Packet_ptr, std::string) { - //debug(" Packet dropped. %s | Reason: %s \n", - // packet->to_string().c_str(), reason.c_str()); + //debug(" Packet dropped. %s | Reason: %s \n", + // packet->to_string().c_str(), reason.c_str()); }; /// READING /// /* - Assign the read request (read buffer) + Assign the read request (read buffer) */ inline void receive(ReadBuffer& buffer) { - read_request.buffer = {buffer}; + read_request.buffer = {buffer}; } /* - Receive data into the current read requests buffer. + Receive data into the current read requests buffer. */ size_t receive(const uint8_t* data, size_t n, bool PUSH); /* - Copy data into the ReadBuffer + Copy data into the ReadBuffer */ inline size_t receive(ReadBuffer& buf, const uint8_t* data, size_t n) { - auto received = std::min(n, buf.remaining); - memcpy(buf.pos(), data, received); // Can we use move? - return received; + auto received = std::min(n, buf.remaining); + memcpy(buf.pos(), data, received); // Can we use move? + return received; } /* - Remote is closing, no more data will be received. - Returns receive buffer to user. + Remote is closing, no more data will be received. + Returns receive buffer to user. */ inline void receive_disconnect() { - assert(!read_request.buffer.empty()); - auto& buf = read_request.buffer; - buf.push = true; - read_request.callback(buf.buffer, buf.size()); + assert(!read_request.buffer.empty()); + auto& buf = read_request.buffer; + buf.push = true; + read_request.callback(buf.buffer, buf.size()); } /// WRITING /// /* - Active try to send a buffer by asking the TCP. + Active try to send a buffer by asking the TCP. */ inline size_t send(WriteBuffer& buffer) { - return host_.send(shared_from_this(), buffer); + return host_.send(shared_from_this(), buffer); } /* - Segmentize buffer into packets until either everything has been written, - or all packets are used up. + Segmentize buffer into packets until either everything has been written, + or all packets are used up. */ size_t send(const char* buffer, size_t remaining, size_t& packets, bool PUSH); inline size_t send(WriteBuffer& buffer, size_t& packets) { - return send((char*)buffer.pos(), buffer.remaining, packets, buffer.push); + return send((char*)buffer.pos(), buffer.remaining, packets, buffer.push); } /* - Process the write queue with the given amount of packets. - Returns true if all the jobs are done (queue is empty) + Process the write queue with the given amount of packets. + Returns true if all the jobs are done (queue is empty) */ bool offer(size_t& packets); /* - Try to write (some of) queue on connected. + Try to write (some of) queue on connected. */ void write_queue_on_connect(); /* - Reset queue on disconnect. Clears the queue and notice every requests callback. + Reset queue on disconnect. Clears the queue and notice every requests callback. */ void write_queue_reset(); /* - Invoke/signal the diffrent TCP events. + Invoke/signal the diffrent TCP events. */ inline bool signal_accept() { return on_accept_(shared_from_this()); } @@ -1210,7 +1210,7 @@ namespace net { inline void signal_packet_dropped(TCP::Packet_ptr packet, std::string reason) { on_packet_dropped_(packet, reason); } /* - Drop a packet. Used for debug/callback. + Drop a packet. Used for debug/callback. */ inline void drop(TCP::Packet_ptr packet, std::string reason) { signal_packet_dropped(packet, reason); } inline void drop(TCP::Packet_ptr packet) { drop(packet, "None given."); } @@ -1219,19 +1219,19 @@ namespace net { /// TCB HANDLING /// /* - Returns the TCB. + Returns the TCB. */ inline Connection::TCB& tcb() { return control_block; } /* - Generate a new ISS. + Generate a new ISS. */ TCP::Seq generate_iss(); /// STATE HANDLING /// /* - Set state. (used by substates) + Set state. (used by substates) */ void set_state(State& state); @@ -1239,78 +1239,78 @@ namespace net { /// BUFFER HANDLING /// /* - Transmit the send buffer. + Transmit the send buffer. */ void transmit(); /* - Transmit the packet. + Transmit the packet. */ void transmit(TCP::Packet_ptr); /* - Creates a new outgoing packet with the current TCB values and options. + Creates a new outgoing packet with the current TCB values and options. */ TCP::Packet_ptr create_outgoing_packet(); /* */ inline TCP::Packet_ptr outgoing_packet() { - return create_outgoing_packet(); + return create_outgoing_packet(); } /// RETRANSMISSION /// /* - Starts a retransmission timer that retransmits the packet when RTO has passed. + Starts a retransmission timer that retransmits the packet when RTO has passed. - // TODO: Calculate RTO, currently hardcoded to 1 second (1000ms). - */ + // TODO: Calculate RTO, currently hardcoded to 1 second (1000ms). + */ void add_retransmission(TCP::Packet_ptr); /* - Measure the elapsed time between sending a data octet with a - particular sequence number and receiving an acknowledgment that - covers that sequence number (segments sent do not have to match - segments received). This measured elapsed time is the Round Trip - Time (RTT). + Measure the elapsed time between sending a data octet with a + particular sequence number and receiving an acknowledgment that + covers that sequence number (segments sent do not have to match + segments received). This measured elapsed time is the Round Trip + Time (RTT). */ //std::chrono::milliseconds RTT() const; std::chrono::milliseconds RTO() const; /* - Start the time wait timeout for 2*MSL + Start the time wait timeout for 2*MSL */ void start_time_wait_timeout(); /* - Tell the host (TCP) to delete this connection. + Tell the host (TCP) to delete this connection. */ void signal_close(); /// OPTIONS /// /* - Maximum Segment Data Size - (Limit the size for outgoing packets) + Maximum Segment Data Size + (Limit the size for outgoing packets) */ inline uint16_t MSDS() const { - return std::min(host_.MSS(), control_block.SND.MSS); + return std::min(host_.MSS(), control_block.SND.MSS); } /* - Parse and apply options. + Parse and apply options. */ void parse_options(TCP::Packet_ptr); /* - Add an option. + Add an option. */ void add_option(TCP::Option::Kind, TCP::Packet_ptr); /* - Receive a TCP Packet. + Receive a TCP Packet. */ void segment_arrived(TCP::Packet_ptr); @@ -1395,9 +1395,9 @@ namespace net { */ inline uint16_t MSS() const { /* - VirtulaBox "issue": - MTU > 1498 will break TCP. - MTU > 1482 seems to cause fragmentation: https://www.virtualbox.org/ticket/13967 + VirtulaBox "issue": + MTU > 1498 will break TCP. + MTU > 1482 seems to cause fragmentation: https://www.virtualbox.org/ticket/13967 */ const uint16_t VBOX_LIMIT = 1482; return std::min(inet_.MTU(), VBOX_LIMIT) - sizeof(Full_header::ip4) - sizeof(TCP::Header); diff --git a/api/utility/async_loop.hpp b/api/utility/async_loop.hpp index d30230784e..87f3f1676e 100644 --- a/api/utility/async_loop.hpp +++ b/api/utility/async_loop.hpp @@ -6,8 +6,8 @@ typedef std::shared_ptr next_ptr_t; inline void async_loop( - std::function func, - std::function on_done) + std::function func, + std::function on_done) { // store next function on heap auto next = std::make_shared (); @@ -19,10 +19,10 @@ async_loop( // check we are done, and if so, // execute the callback function and return if (done) - { - on_done(); - return; - } + { + on_done(); + return; + } // otherwise, // execute one iteration of the loop func(next); diff --git a/api/utility/delegate.hpp b/api/utility/delegate.hpp index a942bf7da5..5956da5491 100644 --- a/api/utility/delegate.hpp +++ b/api/utility/delegate.hpp @@ -42,16 +42,16 @@ class delegate delegate(::std::nullptr_t const) noexcept : delegate() { } template {}>::type> - explicit delegate(C const* const o) noexcept : - object_ptr_(const_cast(o)) + typename ::std::enable_if< ::std::is_class{}>::type> + explicit delegate(C const* const o) noexcept : + object_ptr_(const_cast(o)) { } template {}>::type> - explicit delegate(C const& o) noexcept : - object_ptr_(const_cast(&o)) + typename ::std::enable_if< ::std::is_class{}>::type> + explicit delegate(C const& o) noexcept : + object_ptr_(const_cast(&o)) { } @@ -87,8 +87,8 @@ class delegate > delegate(T&& f) : store_(operator new(sizeof(typename ::std::decay::type)), - functor_deleter::type>), - store_size_(sizeof(typename ::std::decay::type)) + functor_deleter::type>), + store_size_(sizeof(typename ::std::decay::type)) { using functor_type = typename ::std::decay::type; @@ -129,14 +129,14 @@ class delegate if ((sizeof(functor_type) > store_size_) || !store_.unique()) { - store_.reset(operator new(sizeof(functor_type)), - functor_deleter); + store_.reset(operator new(sizeof(functor_type)), + functor_deleter); - store_size_ = sizeof(functor_type); + store_size_ = sizeof(functor_type); } else { - deleter_(store_.get()); + deleter_(store_.get()); } new (store_.get()) functor_type(::std::forward(f)); @@ -201,14 +201,14 @@ class delegate template static delegate from(C* const object_ptr, - R (C::* const method_ptr)(A...)) + R (C::* const method_ptr)(A...)) { return member_pair(object_ptr, method_ptr); } template static delegate from(C const* const object_ptr, - R (C::* const method_ptr)(A...) const) + R (C::* const method_ptr)(A...) const) { return const_member_pair(object_ptr, method_ptr); } @@ -221,7 +221,7 @@ class delegate template static delegate from(C const& object, - R (C::* const method_ptr)(A...) const) + R (C::* const method_ptr)(A...) const) { return const_member_pair(&object, method_ptr); } @@ -303,14 +303,14 @@ class delegate static R method_stub(void* const object_ptr, A&&... args) { return (static_cast(object_ptr)->*method_ptr)( - ::std::forward
(args)...); + ::std::forward(args)...); } template static R const_method_stub(void* const object_ptr, A&&... args) { return (static_cast(object_ptr)->*method_ptr)( - ::std::forward(args)...); + ::std::forward(args)...); } template @@ -318,7 +318,7 @@ class delegate template struct is_member_pair< ::std::pair > : std::true_type + R (C::* const)(A...)> > : std::true_type { }; @@ -327,7 +327,7 @@ class delegate template struct is_const_member_pair< ::std::pair > : std::true_type + R (C::* const)(A...) const> > : std::true_type { }; @@ -351,7 +351,7 @@ class delegate functor_stub(void* const object_ptr, A&&... args) { return (static_cast(object_ptr)->first->* - static_cast(object_ptr)->second)(::std::forward(args)...); + static_cast(object_ptr)->second)(::std::forward(args)...); } }; @@ -365,7 +365,7 @@ namespace std auto const seed(hash()(d.object_ptr_)); return hash::stub_ptr_type>()( - d.stub_ptr_) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + d.stub_ptr_) + 0x9e3779b9 + (seed << 6) + (seed >> 2); } }; } diff --git a/api/utility/membitmap.hpp b/api/utility/membitmap.hpp index fe22eb1e67..4205818f9a 100644 --- a/api/utility/membitmap.hpp +++ b/api/utility/membitmap.hpp @@ -56,15 +56,15 @@ namespace fs { // each word for (index_t i = 0; i < _size; i++) - if (_data[i] != WORD_MAX) - { - // each bit - for (index_t b = 0; b < CHUNK_SIZE; b++) - if (!(_data[i] & (1 << b))) - { - return i * CHUNK_SIZE + b; - } - } // chunk + if (_data[i] != WORD_MAX) + { + // each bit + for (index_t b = 0; b < CHUNK_SIZE; b++) + if (!(_data[i] & (1 << b))) + { + return i * CHUNK_SIZE + b; + } + } // chunk return -1; } // first_free() diff --git a/api/utility/ringbuffer.hpp b/api/utility/ringbuffer.hpp index 1999811a90..01f377e757 100644 --- a/api/utility/ringbuffer.hpp +++ b/api/utility/ringbuffer.hpp @@ -28,12 +28,12 @@ namespace includeOS { enum error_t { - E_OK = 0, - E_NO_SPACE = -1; - E_WRITE_FAILED = -2; + E_OK = 0, + E_NO_SPACE = -1; + E_WRITE_FAILED = -2; }; - - + + RingBuffer(int size) { this->size = size + 1; @@ -44,56 +44,56 @@ namespace includeOS ~RingBuffer() { if (this->buffer) - delete[] this->buffer; + delete[] this->buffer; } - + int write(char* data, int length) { if (available_data() == 0) - { - this->start = this->end = 0; - } - + { + this->start = this->end = 0; + } + if (length > available_space()) - { - return E_NO_SPACE; - } - + { + return E_NO_SPACE; + } + void* result = memcpy(ends_at(), data, length); if (result == nullptr) - { - return E_WRITE_FAILED; - } - + { + return E_WRITE_FAILED; + } + // commit write this->end = (this->end + length) % this->size; // return length written return length; } - + int read(char* dest, int length) { check_debug(amount <= RingBuffer_available_data(buffer), - "Not enough in the buffer: has %d, needs %d", - RingBuffer_available_data(buffer), amount); + "Not enough in the buffer: has %d, needs %d", + RingBuffer_available_data(buffer), amount); void *result = memcpy(target, RingBuffer_starts_at(buffer), amount); check(result != NULL, "Failed to write buffer into data."); - + // commit read this->start = (this->start + length) % this->size; - + if (this->end == this->start) - { - this->start = this->end = 0; - } - + { + this->start = this->end = 0; + } + return length; } - + #define RingBuffer_available_data(B) (((B)->end + 1) % (B)->length - (B)->start - 1) #define RingBuffer_available_space(B) ((B)->length - (B)->end - 1) - + int available_data() const { return (this->end + 1) % this->size - this->start - 1; @@ -101,8 +101,8 @@ namespace includeOS int available_space() const { return this-> - } - + } + const char* starts_at() const { return this->buffer + this->end; @@ -111,7 +111,7 @@ namespace includeOS { return this->buffer + this->end; } - + bool full() const { return available_data() - this->size == 0; @@ -120,8 +120,8 @@ namespace includeOS { return available_data() == 0; } - - + + private: int size; int start; diff --git a/api/utility/signal.hpp b/api/utility/signal.hpp index 35c672f8f0..f18de4b26b 100644 --- a/api/utility/signal.hpp +++ b/api/utility/signal.hpp @@ -43,14 +43,14 @@ class signal { void connect(handler&& fn) { funcs.emplace_back(std::forward(fn)); } - + //! \brief Emit this signal by executing all connected callable objects template void emit(Args&&... args) { for(auto& fn : funcs) fn(std::forward(args)...); } - + private: // Set of callable objects registered to be called on demand std::vector funcs; diff --git a/etc/batch_apply_editorconfig.sh b/etc/batch_apply_editorconfig.sh index e0fa4ebdef..22afe5d786 100755 --- a/etc/batch_apply_editorconfig.sh +++ b/etc/batch_apply_editorconfig.sh @@ -5,5 +5,5 @@ SRC=$1 for file in `find $SRC \( -not -path "*/cxxabi/*" -not -path "*/STREAM/*" -not -path "*/lest/*" -not -path "*/mod/*" \) -type f \( -name *.cpp -or -name *.hpp -or -name *.inc \)` do echo -e "\n >> Formatting $file" - emacs $file -batch --eval '(indent-region (point-min) (point-max) nil)' -f save-buffer + emacs $file -batch -l ~/.emacs.d/.emacs -f format-buffer done diff --git a/examples/demo_service/service.cpp b/examples/demo_service/service.cpp index 4b69193b60..402c24b307 100644 --- a/examples/demo_service/service.cpp +++ b/examples/demo_service/service.cpp @@ -39,9 +39,9 @@ void Service::start() { // Static IP configuration, until we (possibly) get DHCP // @note : Mostly to get a robust demo service that it works with and without DHCP inet->network_config( {{ 10,0,0,42 }}, // IP - {{ 255,255,255,0 }}, // Netmask - {{ 10,0,0,1 }}, // Gateway - {{ 8,8,8,8 }} ); // DNS + {{ 255,255,255,0 }}, // Netmask + {{ 10,0,0,1 }}, // Gateway + {{ 8,8,8,8 }} ); // DNS srand(OS::cycles_since_boot()); @@ -55,52 +55,52 @@ void Service::start() { // Add a TCP connection handler - here a hardcoded HTTP-service server.onAccept([](auto conn) -> bool { printf(" @onAccept - Connection attempt from: %s \n", - conn->to_string().c_str()); + conn->to_string().c_str()); return true; // allow all connections }).onConnect([](auto) { - printf(" @onConnect - Connection successfully established.\n"); + printf(" @onConnect - Connection successfully established.\n"); }).onReceive([](auto conn, bool push) { - std::string data = conn->read(1024); - printf(" @onData - PUSH: %d, Data read: \n%s\n", push, data.c_str()); - int color = rand(); - std::stringstream stream; + std::string data = conn->read(1024); + printf(" @onData - PUSH: %d, Data read: \n%s\n", push, data.c_str()); + int color = rand(); + std::stringstream stream; - /* HTML Fonts */ - std::string ubuntu_medium = "font-family: \'Ubuntu\', sans-serif; font-weight: 500; "; - std::string ubuntu_normal = "font-family: \'Ubuntu\', sans-serif; font-weight: 400; "; - std::string ubuntu_light = "font-family: \'Ubuntu\', sans-serif; font-weight: 300; "; + /* HTML Fonts */ + std::string ubuntu_medium = "font-family: \'Ubuntu\', sans-serif; font-weight: 500; "; + std::string ubuntu_normal = "font-family: \'Ubuntu\', sans-serif; font-weight: 400; "; + std::string ubuntu_light = "font-family: \'Ubuntu\', sans-serif; font-weight: 300; "; - /* HTML */ - stream << "" - << "" - << "" - << "

> 8) << "\">" - << "IncludeOS

" - << "

Now speaks TCP!

" - // .... generate more dynamic content - << "

...and can improvise http. With limitations of course, but it's been easier than expected so far

" - << "

© 2015, Oslo and Akershus University College of Applied Sciences
" - << "\n"; + /* HTML */ + stream << "" + << "" + << "" + << "

> 8) << "\">" + << "IncludeOS

" + << "

Now speaks TCP!

" + // .... generate more dynamic content + << "

...and can improvise http. With limitations of course, but it's been easier than expected so far

" + << "

© 2015, Oslo and Akershus University College of Applied Sciences
" + << "\n"; - /* HTTP-header */ - std::string html = stream.str(); - std::string header="HTTP/1.1 200 OK \n " \ - "Date: Mon, 01 Jan 1970 00:00:01 GMT \n" \ - "Server: IncludeOS prototype 4.0 \n" \ - "Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT \n" \ - "Content-Type: text/html; charset=UTF-8 \n" \ - "Content-Length: "+std::to_string(html.size())+"\n" \ - "Accept-Ranges: bytes\n" \ - "Connection: close\n\n"; + /* HTTP-header */ + std::string html = stream.str(); + std::string header="HTTP/1.1 200 OK \n " \ + "Date: Mon, 01 Jan 1970 00:00:01 GMT \n" \ + "Server: IncludeOS prototype 4.0 \n" \ + "Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT \n" \ + "Content-Type: text/html; charset=UTF-8 \n" \ + "Content-Length: "+std::to_string(html.size())+"\n" \ + "Accept-Ranges: bytes\n" \ + "Connection: close\n\n"; - std::string output{header + html}; - conn->write(output.data(), output.size()); + std::string output{header + html}; + conn->write(output.data(), output.size()); - }).onDisconnect([](auto, auto reason) { - printf(" @onDisconnect - Reason: %s \n", reason.to_string().c_str()); - }); + }).onDisconnect([](auto, auto reason) { + printf(" @onDisconnect - Reason: %s \n", reason.to_string().c_str()); + }); printf("*** TEST SERVICE STARTED *** \n"); } diff --git a/examples/tcp/service.cpp b/examples/tcp/service.cpp index 610a7edebf..42a0ccfbdc 100644 --- a/examples/tcp/service.cpp +++ b/examples/tcp/service.cpp @@ -18,10 +18,10 @@ /* An example to show incoming and outgoing TCP Connections. In this example, IncludeOS is listening on port 80. - + Data received on port 80 will be redirected to a outgoing connection to a (in this case) python server (server.py) - + Data received from the python server connection will be redirected back to the client. @@ -67,9 +67,9 @@ void Service::start() { // Static IP configuration, until we (possibly) get DHCP inet->network_config( {{ 10,0,0,42 }}, // IP - {{ 255,255,255,0 }}, // Netmask - {{ 10,0,0,1 }}, // Gateway - {{ 8,8,8,8 }} ); // DNS + {{ 255,255,255,0 }}, // Netmask + {{ 10,0,0,1 }}, // Gateway + {{ 8,8,8,8 }} ); // DNS // Set up a TCP server on port 80 auto& server = inet->tcp().bind(80); @@ -84,31 +84,31 @@ void Service::start() { auto outgoing = inet->tcp().connect(python_server); // When outgoing connection to python sever is established outgoing->onConnect([client](Connection_ptr python) { - printf("Connected [Python]: %s\n", python->to_string().c_str()); + printf("Connected [Python]: %s\n", python->to_string().c_str()); - // Setup handlers for when data is received on client and python connection - // When client has data to be read - client->onReceive([python](Connection_ptr client, bool) { - handle_client_on_receive(client, python); - }); + // Setup handlers for when data is received on client and python connection + // When client has data to be read + client->onReceive([python](Connection_ptr client, bool) { + handle_client_on_receive(client, python); + }); - // When python server has data to be read - python->onReceive([client](Connection_ptr python, bool) { - handle_python_on_receive(python, client); - }); + // When python server has data to be read + python->onReceive([client](Connection_ptr python, bool) { + handle_python_on_receive(python, client); + }); - // When client is disconnecting - client->onDisconnect([python](Connection_ptr, Disconnect reason) { - printf("Disconnected [Client]: %s\n", reason.to_string().c_str()); - python->close(); - }); + // When client is disconnecting + client->onDisconnect([python](Connection_ptr, Disconnect reason) { + printf("Disconnected [Client]: %s\n", reason.to_string().c_str()); + python->close(); + }); - // When python is disconnecting - python->onDisconnect([client](Connection_ptr, Disconnect reason) { - printf("Disconnected [Python]: %s\n", reason.to_string().c_str()); - client->close(); - }); - }); // << onConnect (outgoing (python)) + // When python is disconnecting + python->onDisconnect([client](Connection_ptr, Disconnect reason) { + printf("Disconnected [Python]: %s\n", reason.to_string().c_str()); + client->close(); + }); + }); // << onConnect (outgoing (python)) }); // << onConnect (client) } diff --git a/src/crt/mman.cpp b/src/crt/mman.cpp index 23f99aef44..8baadf17fa 100644 --- a/src/crt/mman.cpp +++ b/src/crt/mman.cpp @@ -20,8 +20,8 @@ struct mmap_entry_t std::map _mmap_entries; void* mmap(void* addr, size_t length, - int prot, int flags, - int fd, off_t offset) + int prot, int flags, + int fd, off_t offset) { // invalid or misaligned length if (length == 0 || (length & 4095) != 0) diff --git a/src/debug/ircd.cpp b/src/debug/ircd.cpp index 84068f8a8c..b42042a0b6 100644 --- a/src/debug/ircd.cpp +++ b/src/debug/ircd.cpp @@ -29,42 +29,42 @@ void Client::read(const char* buf, size_t len) int search = -1; for (size_t i = 0; i < len; i++) - if (buf[i] == 13 || buf[i] == 10) - { - search = i; break; - } + if (buf[i] == 13 || buf[i] == 10) + { + search = i; break; + } // not found: if (search == -1) - { - // append entire buffer - buffer.append(buf, len); - break; - } + { + // append entire buffer + buffer.append(buf, len); + break; + } else - { - // found CR LF: - if (search != 0) - { - // append to clients buffer - buffer.append(buf, search); + { + // found CR LF: + if (search != 0) + { + // append to clients buffer + buffer.append(buf, search); - // move forward in socket buffer - buf += search; - // decrease len - len -= search; - } - else - { - buf++; len--; - } + // move forward in socket buffer + buf += search; + // decrease len + len -= search; + } + else + { + buf++; len--; + } - // parse message - if (buffer.size()) - { - split_message(buffer); - buffer.clear(); - } - } + // parse message + if (buffer.size()) + { + split_message(buffer); + buffer.clear(); + } + } } } @@ -104,48 +104,48 @@ void Client::handle(const std::string&, if (this->is_reg() == false) { if (cmd == TK_CAP) - { - // ignored completely - } + { + // ignored completely + } else if (cmd == TK_PASS) - { - if (msg.size() > 1) - { - this->passw = msg[1]; - } - else - { - send(ERR_NEEDMOREPARAMS, cmd + " :Not enough parameters"); - } - } + { + if (msg.size() > 1) + { + this->passw = msg[1]; + } + else + { + send(ERR_NEEDMOREPARAMS, cmd + " :Not enough parameters"); + } + } else if (cmd == TK_NICK) - { - if (msg.size() > 1) - { - this->nick = msg[1]; - welcome(regis | 1); - } - else - { - send(ERR_NEEDMOREPARAMS, cmd + " :Not enough parameters"); - } - } + { + if (msg.size() > 1) + { + this->nick = msg[1]; + welcome(regis | 1); + } + else + { + send(ERR_NEEDMOREPARAMS, cmd + " :Not enough parameters"); + } + } else if (cmd == TK_USER) - { - if (msg.size() > 1) - { - this->user = msg[1]; - welcome(regis | 2); - } - else - { - send(ERR_NEEDMOREPARAMS, cmd + " :Not enough parameters"); - } - } + { + if (msg.size() > 1) + { + this->user = msg[1]; + welcome(regis | 2); + } + else + { + send(ERR_NEEDMOREPARAMS, cmd + " :Not enough parameters"); + } + } else - { - send(ERR_NOSUCHCMD, cmd + " :Unknown command"); - } + { + send(ERR_NOSUCHCMD, cmd + " :Unknown command"); + } } } diff --git a/src/debug/ircsplit.hpp b/src/debug/ircsplit.hpp index e195f79e09..1f80098869 100644 --- a/src/debug/ircsplit.hpp +++ b/src/debug/ircsplit.hpp @@ -24,23 +24,23 @@ split(const std::string& text, std::string& source) size_t y = text.find(":", x+1); // find last param if (y == x+1) - { - // single argument - retv.push_back(text.substr(p, x-p)); - // ending text argument - retv.push_back(text.substr(y+1)); - break; - } + { + // single argument + retv.push_back(text.substr(p, x-p)); + // ending text argument + retv.push_back(text.substr(y+1)); + break; + } else if (x != std::string::npos) - { - // single argument - retv.push_back(text.substr(p, x-p)); - } + { + // single argument + retv.push_back(text.substr(p, x-p)); + } else - { - // last argument - retv.push_back(text.substr(p)); - } + { + // last argument + retv.push_back(text.substr(p)); + } p = x+1; } while (x != std::string::npos); diff --git a/src/debug/test_disk.cpp b/src/debug/test_disk.cpp index c52289d5aa..0ece49b679 100644 --- a/src/debug/test_disk.cpp +++ b/src/debug/test_disk.cpp @@ -23,106 +23,106 @@ void Service::start() // mount first valid partition (auto-detect and mount) disk->mount( // or specify partition explicitly in parameter - [] (fs::error_t err) - { - if (err) - { - printf("Could not mount filesystem\n"); - return; - } - // get a reference to the mounted filesystem - auto& fs = disk->fs(); + [] (fs::error_t err) + { + if (err) + { + printf("Could not mount filesystem\n"); + return; + } + // get a reference to the mounted filesystem + auto& fs = disk->fs(); - // check contents of disk - auto dirents = fs::new_shared_vector(); - err = fs.ls("/", dirents); - if (err) - printf("Could not list '/' directory\n"); - else - for (auto& e : *dirents) - { - printf("%s: %s\t of size %llu bytes (CL: %llu)\n", - e.type_string().c_str(), e.name().c_str(), e.size, e.block); - } + // check contents of disk + auto dirents = fs::new_shared_vector(); + err = fs.ls("/", dirents); + if (err) + printf("Could not list '/' directory\n"); + else + for (auto& e : *dirents) + { + printf("%s: %s\t of size %llu bytes (CL: %llu)\n", + e.type_string().c_str(), e.name().c_str(), e.size, e.block); + } - auto ent = fs.stat("/test.txt"); - // validate the stat call - if (ent.is_valid()) - { - // read specific area of file - auto buf = fs.read(ent, 1032, 65); - std::string contents((const char*) buf.buffer.get(), buf.len); - printf("[%s contents (%llu bytes)]:\n%s\n[end]\n\n", - ent.name().c_str(), buf.len, contents.c_str()); + auto ent = fs.stat("/test.txt"); + // validate the stat call + if (ent.is_valid()) + { + // read specific area of file + auto buf = fs.read(ent, 1032, 65); + std::string contents((const char*) buf.buffer.get(), buf.len); + printf("[%s contents (%llu bytes)]:\n%s\n[end]\n\n", + ent.name().c_str(), buf.len, contents.c_str()); - } - else - { - printf("Invalid entity for /test.txt\n"); - } - return; + } + else + { + printf("Invalid entity for /test.txt\n"); + } + return; - disk->fs().ls("/", - [] (fs::error_t err, auto ents) - { - if (err) - { - printf("Could not list '/' directory\n"); - return; - } + disk->fs().ls("/", + [] (fs::error_t err, auto ents) + { + if (err) + { + printf("Could not list '/' directory\n"); + return; + } - for (auto& e : *ents) - { - printf("%s: %s\t of size %llu bytes (CL: %llu)\n", - e.type_string().c_str(), e.name().c_str(), e.size, e.block); + for (auto& e : *ents) + { + printf("%s: %s\t of size %llu bytes (CL: %llu)\n", + e.type_string().c_str(), e.name().c_str(), e.size, e.block); - if (e.is_file()) - { - printf("*** Attempting to read: %s\n", e.name().c_str()); - disk->fs().read(e, 0, e.size, - [e] (fs::error_t err, fs::buffer_t buffer, size_t len) - { - if (err) - { - printf("Failed to read file %s!\n", - e.name().c_str()); - return; - } + if (e.is_file()) + { + printf("*** Attempting to read: %s\n", e.name().c_str()); + disk->fs().read(e, 0, e.size, + [e] (fs::error_t err, fs::buffer_t buffer, size_t len) + { + if (err) + { + printf("Failed to read file %s!\n", + e.name().c_str()); + return; + } - std::string contents((const char*) buffer.get(), len); - printf("[%s contents]:\n%s\nEOF\n\n", - e.name().c_str(), contents.c_str()); - }); - } - } - }); + std::string contents((const char*) buffer.get(), len); + printf("[%s contents]:\n%s\nEOF\n\n", + e.name().c_str(), contents.c_str()); + }); + } + } + }); - disk->fs().stat("/test.txt", - [] (fs::error_t err, const auto& e) - { - if (err) - { - printf("Could not stat %s\n", e.name().c_str()); - return; - } + disk->fs().stat("/test.txt", + [] (fs::error_t err, const auto& e) + { + if (err) + { + printf("Could not stat %s\n", e.name().c_str()); + return; + } - printf("stat: /test.txt is a %s on cluster %llu\n", - e.type_string().c_str(), e.block); - }); - disk->fs().stat("/Sample Pictures/Koala.jpg", - [] (fs::error_t err, const auto& e) - { - if (err) - { - printf("Could not stat %s\n", e.name().c_str()); - return; - } + printf("stat: /test.txt is a %s on cluster %llu\n", + e.type_string().c_str(), e.block); + }); + disk->fs().stat("/Sample Pictures/Koala.jpg", + [] (fs::error_t err, const auto& e) + { + if (err) + { + printf("Could not stat %s\n", e.name().c_str()); + return; + } - printf("stat: %s is a %s on cluster %llu\n", - e.name().c_str(), e.type_string().c_str(), e.block); - }); + printf("stat: %s is a %s on cluster %llu\n", + e.name().c_str(), e.type_string().c_str(), e.block); + }); - }); // disk->auto_detect() + }); // disk->auto_detect() printf("*** TEST SERVICE STARTED *** \n"); } @@ -130,16 +130,16 @@ void Service::start() void list_partitions(decltype(disk) disk) { disk->partitions( - [] (fs::error_t err, auto& parts) - { - if (err) - { - printf("Failed to retrieve volumes on disk\n"); - return; - } + [] (fs::error_t err, auto& parts) + { + if (err) + { + printf("Failed to retrieve volumes on disk\n"); + return; + } - for (auto& part : parts) - printf("[Partition] '%s' at LBA %u\n", - part.name().c_str(), part.lba()); - }); + for (auto& part : parts) + printf("[Partition] '%s' at LBA %u\n", + part.name().c_str(), part.lba()); + }); } diff --git a/src/debug/test_ipv6.cpp b/src/debug/test_ipv6.cpp index 9bb1b0d917..347f39a1a7 100644 --- a/src/debug/test_ipv6.cpp +++ b/src/debug/test_ipv6.cpp @@ -40,9 +40,9 @@ void Service::start() // basic UDP service net::Inet::ifconfig( - net::ETH0, - ip4, {{255, 255, 255, 0}}, - ip6); + net::ETH0, + ip4, {{255, 255, 255, 0}}, + ip6); net::Inet* inet = net::Inet::up(); @@ -64,37 +64,37 @@ void Service::start() // basic UDP service static const int UDP_PORT = 64; inet->udp6_listen(UDP_PORT, - [=] (std::shared_ptr& pckt) -> int - { - printf("Received UDP6 packet from %s to my listener on port %d\n", - pckt->src().str().c_str(), pckt->dst_port()); + [=] (std::shared_ptr& pckt) -> int + { + printf("Received UDP6 packet from %s to my listener on port %d\n", + pckt->src().str().c_str(), pckt->dst_port()); - std::string data((const char*) pckt->data(), pckt->data_length()); + std::string data((const char*) pckt->data(), pckt->data_length()); - printf("Contents (len=%d):\n%s\n", pckt->data_length(), data.c_str()); + printf("Contents (len=%d):\n%s\n", pckt->data_length(), data.c_str()); - // unfortunately, - // copy the ether src field of the incoming packet - net::Ethernet::addr ether_src = - ((net::Ethernet::header*) pckt->buffer())->src; + // unfortunately, + // copy the ether src field of the incoming packet + net::Ethernet::addr ether_src = + ((net::Ethernet::header*) pckt->buffer())->src; - // create a response packet with destination [ether_src] dst() - std::shared_ptr newpacket = - inet->udp6_create(ether_src, pckt->dst(), UDP_PORT); + // create a response packet with destination [ether_src] dst() + std::shared_ptr newpacket = + inet->udp6_create(ether_src, pckt->dst(), UDP_PORT); - const char* text = "This is the response packet!"; - // copy text into UDP data section - memcpy( newpacket->data(), text, strlen(text) ); - // set new length - newpacket->set_length(strlen(text)); + const char* text = "This is the response packet!"; + // copy text into UDP data section + memcpy( newpacket->data(), text, strlen(text) ); + // set new length + newpacket->set_length(strlen(text)); - // generate checksum for packet before sending - newpacket->gen_checksum(); + // generate checksum for packet before sending + newpacket->gen_checksum(); - // ship it to the ether - inet->udp6_send(newpacket); - return -1; - } - ); + // ship it to the ether + inet->udp6_send(newpacket); + return -1; + } + ); } diff --git a/src/debug/test_service.cpp b/src/debug/test_service.cpp index 2553927806..614fcc6a76 100644 --- a/src/debug/test_service.cpp +++ b/src/debug/test_service.cpp @@ -35,10 +35,10 @@ void Service::start() hw::Nic& eth0 = hw::Dev::eth<0,VirtioNet>(); inet = std::make_unique >(eth0); inet->network_config( - {{ 10,0,0,42 }}, // IP - {{ 255,255,255,0 }}, // Netmask - {{ 10,0,0,1 }}, // Gateway - {{ 8,8,8,8 }} ); // DNS + {{ 10,0,0,42 }}, // IP + {{ 255,255,255,0 }}, // Netmask + {{ 10,0,0,1 }}, // Gateway + {{ 8,8,8,8 }} ); // DNS /* auto& tcp = inet->tcp(); @@ -82,12 +82,12 @@ void Service::start() term = std::make_unique (serial); // add 'ifconfig' command term->add( - "ifconfig", "Show information about interfaces", - [] (const std::vector&) -> int - { - term->write("%s\r\n", inet->tcp().status().c_str()); - return 0; - }); + "ifconfig", "Show information about interfaces", + [] (const std::vector&) -> int + { + term->write("%s\r\n", inet->tcp().status().c_str()); + return 0; + }); /// terminal /// printf("*** TEST SERVICE STARTED *** \n"); diff --git a/src/debug/test_tcp.cpp b/src/debug/test_tcp.cpp index f42594c305..d9f00ffeb4 100644 --- a/src/debug/test_tcp.cpp +++ b/src/debug/test_tcp.cpp @@ -33,9 +33,9 @@ void Service::start() { inet = std::make_unique(eth0); inet->network_config( {{ 10,0,0,42 }}, // IP - {{ 255,255,255,0 }}, // Netmask - {{ 10,0,0,1 }}, // Gateway - {{ 8,8,8,8 }} ); // DNS + {{ 255,255,255,0 }}, // Netmask + {{ 10,0,0,1 }}, // Gateway + {{ 8,8,8,8 }} ); // DNS auto& server = inet->tcp().bind(80); @@ -48,11 +48,11 @@ void Service::start() { printf(" Received: %s\n", packet->to_string().c_str()); }).onPacketDropped([](auto packet, std::string reason) { - printf(" Dropped: %s - Reason: %s \n", packet->to_string().c_str(), reason.c_str()); + printf(" Dropped: %s - Reason: %s \n", packet->to_string().c_str(), reason.c_str()); }).onReceive([](auto conn, bool) { - conn->write("Hey"); - }).onConnect([](auto conn) { - printf(" Connected.\n"); - }); + conn->write("Hey"); + }).onConnect([](auto conn) { + printf(" Connected.\n"); + }); } diff --git a/src/fs/disk.cpp b/src/fs/disk.cpp index f6e8afa24a..00a6ea21b0 100644 --- a/src/fs/disk.cpp +++ b/src/fs/disk.cpp @@ -32,115 +32,115 @@ namespace fs { /** Read Master Boot Record (sector 0) */ device.read(0, - [this, func] (hw::IDiskDevice::buffer_t data) - { - std::vector parts; + [this, func] (hw::IDiskDevice::buffer_t data) + { + std::vector parts; - if (!data) { - func(true, parts); - return; - } + if (!data) { + func(true, parts); + return; + } - // First sector is the Master Boot Record - auto* mbr =(MBR::mbr*) data.get(); + // First sector is the Master Boot Record + auto* mbr =(MBR::mbr*) data.get(); - for (int i {0}; i < 4; ++i) { - // all the partitions are offsets to potential Volume Boot Records - parts.emplace_back( - mbr->part[i].flags, //< flags - mbr->part[i].type, //< id - mbr->part[i].lba_begin, //< LBA - mbr->part[i].sectors); - } + for (int i {0}; i < 4; ++i) { + // all the partitions are offsets to potential Volume Boot Records + parts.emplace_back( + mbr->part[i].flags, //< flags + mbr->part[i].type, //< id + mbr->part[i].lba_begin, //< LBA + mbr->part[i].sectors); + } - func(no_error, parts); - }); + func(no_error, parts); + }); } void Disk::mount(on_mount_func func) { device.read(0, - [this, func] (hw::IDiskDevice::buffer_t data) - { - if (!data) { - // TODO: error-case for unable to read MBR - mount(INVALID, func); - return; - } + [this, func] (hw::IDiskDevice::buffer_t data) + { + if (!data) { + // TODO: error-case for unable to read MBR + mount(INVALID, func); + return; + } - // auto-detect FAT on MBR: - auto* mbr = (MBR::mbr*) data.get(); - MBR::BPB* bpb = mbr->bpb(); + // auto-detect FAT on MBR: + auto* mbr = (MBR::mbr*) data.get(); + MBR::BPB* bpb = mbr->bpb(); - if (bpb->bytes_per_sector >= 512 - && bpb->fa_tables != 0 - && bpb->signature != 0) // check MBR signature too - { - // we have FAT on MBR (and we are assuming mount FAT) - mount(MBR, func); - return; - } + if (bpb->bytes_per_sector >= 512 + && bpb->fa_tables != 0 + && bpb->signature != 0) // check MBR signature too + { + // we have FAT on MBR (and we are assuming mount FAT) + mount(MBR, func); + return; + } - // go through partition list - for (int i = 0; i < 4; i++) - { - if (mbr->part[i].type != 0 // 0 is unused partition - && mbr->part[i].lba_begin != 0 // 0 is MBR anyways - && mbr->part[i].sectors != 0) // 0 means no size, so... - { - mount((partition_t) (VBR1 + i), func); - return; - } - } + // go through partition list + for (int i = 0; i < 4; i++) + { + if (mbr->part[i].type != 0 // 0 is unused partition + && mbr->part[i].lba_begin != 0 // 0 is MBR anyways + && mbr->part[i].sectors != 0) // 0 means no size, so... + { + mount((partition_t) (VBR1 + i), func); + return; + } + } - // no partition was found (TODO: extended partitions) - mount(INVALID, func); - return; - }); + // no partition was found (TODO: extended partitions) + mount(INVALID, func); + return; + }); } void Disk::mount(partition_t part, on_mount_func func) { if (part == INVALID) { - // Something bad happened maybe in auto-detect - // Either way, no partition was found - func(true); - return; + // Something bad happened maybe in auto-detect + // Either way, no partition was found + func(true); + return; } else if (part == MBR) { - // For the MBR case, all we need to do is mount on sector 0 - fs().mount(0, device.size(), func); + // For the MBR case, all we need to do is mount on sector 0 + fs().mount(0, device.size(), func); } else { - /** - * Otherwise, we will have to read the LBA offset - * of the partition to be mounted - */ - device.read(0, - [this, part, func] (hw::IDiskDevice::buffer_t data) - { - if (!data) { - // TODO: error-case for unable to read MBR - func(true); - return; - } + /** + * Otherwise, we will have to read the LBA offset + * of the partition to be mounted + */ + device.read(0, + [this, part, func] (hw::IDiskDevice::buffer_t data) + { + if (!data) { + // TODO: error-case for unable to read MBR + func(true); + return; + } - auto* mbr = (MBR::mbr*) data.get(); //< Treat data as MBR - auto pint = static_cast(part - 1); //< Treat VBR1 as index 0 etc. + auto* mbr = (MBR::mbr*) data.get(); //< Treat data as MBR + auto pint = static_cast(part - 1); //< Treat VBR1 as index 0 etc. - /** Get LBA from selected partition */ - auto lba_base = mbr->part[pint].lba_begin; - auto lba_size = mbr->part[pint].sectors; + /** Get LBA from selected partition */ + auto lba_base = mbr->part[pint].lba_begin; + auto lba_size = mbr->part[pint].sectors; - /** - * Call the filesystems mount function - * with lba_begin as base address - */ - fs().mount(lba_base, lba_size, func); - }); + /** + * Call the filesystems mount function + * with lba_begin as base address + */ + fs().mount(lba_base, lba_size, func); + }); } } diff --git a/src/fs/ext4.cpp b/src/fs/ext4.cpp index a361e72173..bde88554b3 100644 --- a/src/fs/ext4.cpp +++ b/src/fs/ext4.cpp @@ -19,26 +19,26 @@ namespace fs void EXT4::mount(uint64_t start, uint64_t size, on_mount_func on_mount) { printf("Superblock: %u bytes, Block group desc: %u bytes\n", - sizeof(superblock), sizeof(group_desc)); + sizeof(superblock), sizeof(group_desc)); assert(sizeof(superblock) == 1024); assert(sizeof(group_desc) == 64); printf("Inode table: %u\n", - sizeof(inode_table)); + sizeof(inode_table)); // read Master Boot Record (sector 0) device.read(start, - [this, start, size, on_mount] (buffer_t data) - { - auto* mbr = (MBR::mbr*) data.get(); - assert(mbr != nullptr); + [this, start, size, on_mount] (buffer_t data) + { + auto* mbr = (MBR::mbr*) data.get(); + assert(mbr != nullptr); - /// now what? - printf("Mounting EXT4 from LBA %llu to %llu\n", - start, size); + /// now what? + printf("Mounting EXT4 from LBA %llu to %llu\n", + start, size); - init(data.get()); - }); + init(data.get()); + }); } diff --git a/src/fs/fat.cpp b/src/fs/fat.cpp index 72a126a5de..483851ea43 100644 --- a/src/fs/fat.cpp +++ b/src/fs/fat.cpp @@ -15,8 +15,8 @@ #define unlikely(x) __builtin_expect(!!(x), 0) inline std::string trim_right_copy( - const std::string& s, - const std::string& delimiters = " \f\n\r\t\v" ) + const std::string& s, + const std::string& delimiters = " \f\n\r\t\v" ) { return s.substr( 0, s.find_last_not_of( delimiters ) + 1 ); } @@ -38,9 +38,9 @@ namespace fs this->sector_size = bpb->bytes_per_sector; if (unlikely(this->sector_size < 512)) { - printf("Invalid sector size (%u) for FAT32 partition\n", sector_size); - printf("Are you mounting the correct partition?\n"); - panic("FAT32: Invalid sector size"); + printf("Invalid sector size (%u) for FAT32 partition\n", sector_size); + printf("Are you mounting the correct partition?\n"); + panic("FAT32: Invalid sector size"); } // Let's begin our incantation @@ -93,26 +93,26 @@ namespace fs // using the official method: if (this->clusters < 4085) { - this->fat_type = FAT::T_FAT12; - this->root_cluster = 2; - debug("The image is type FAT12, with %u clusters\n", this->clusters); + this->fat_type = FAT::T_FAT12; + this->root_cluster = 2; + debug("The image is type FAT12, with %u clusters\n", this->clusters); } else if (this->clusters < 65525) { - this->fat_type = FAT::T_FAT16; - this->root_cluster = 2; - debug("The image is type FAT16, with %u clusters\n", this->clusters); + this->fat_type = FAT::T_FAT16; + this->root_cluster = 2; + debug("The image is type FAT16, with %u clusters\n", this->clusters); } else { - this->fat_type = FAT::T_FAT32; - this->root_cluster = *(uint32_t*) &mbr->boot[33]; - this->root_cluster = 2; - debug("The image is type FAT32, with %u clusters\n", this->clusters); - //printf("Root dir entries: %u clusters\n", bpb->root_entries); - //assert(bpb->root_entries == 0); - //this->root_dir_sectors = 0; - //this->data_index = bpb->reserved_sectors + bpb->fa_tables * this->sectors_per_fat; + this->fat_type = FAT::T_FAT32; + this->root_cluster = *(uint32_t*) &mbr->boot[33]; + this->root_cluster = 2; + debug("The image is type FAT32, with %u clusters\n", this->clusters); + //printf("Root dir entries: %u clusters\n", bpb->root_entries); + //assert(bpb->root_entries == 0); + //this->root_dir_sectors = 0; + //this->data_index = bpb->reserved_sectors + bpb->fa_tables * this->sectors_per_fat; } debug("Root cluster index: %u (sector %u)\n", this->root_cluster, cl_to_sector(root_cluster)); debug("System ID: %.8s\n", bpb->system_id); @@ -125,48 +125,48 @@ namespace fs // read Partition block device.read(this->lba_base, - [this, on_mount] (buffer_t data) - { - auto* mbr = (MBR::mbr*) data.get(); - assert(mbr != nullptr); + [this, on_mount] (buffer_t data) + { + auto* mbr = (MBR::mbr*) data.get(); + assert(mbr != nullptr); - // verify image signature - debug("OEM name: \t%s\n", mbr->oem_name); - debug("MBR signature: \t0x%x\n", mbr->magic); - assert(mbr->magic == 0xAA55); + // verify image signature + debug("OEM name: \t%s\n", mbr->oem_name); + debug("MBR signature: \t0x%x\n", mbr->magic); + assert(mbr->magic == 0xAA55); - // initialize FAT16 or FAT32 filesystem - init(mbr); + // initialize FAT16 or FAT32 filesystem + init(mbr); - // determine which FAT version is mounted - std::string inf = "ofs: " + std::to_string(lba_base) + - "size: " + std::to_string(lba_size) + - " (" + std::to_string(this->lba_size * sector_size) + " bytes)\n"; + // determine which FAT version is mounted + std::string inf = "ofs: " + std::to_string(lba_base) + + "size: " + std::to_string(lba_size) + + " (" + std::to_string(this->lba_size * sector_size) + " bytes)\n"; - switch (this->fat_type) - { - case FAT::T_FAT12: - INFO("FS", "Mounting FAT12 filesystem"); - break; - case FAT::T_FAT16: - INFO("FS", "Mounting FAT16 filesystem"); - break; - case FAT::T_FAT32: - INFO("FS", "Mounting FAT32 filesystem"); - break; - } - INFO2("[ofs=%u size=%u (%u bytes)]\n", - this->lba_base, this->lba_size, this->lba_size * 512); + switch (this->fat_type) + { + case FAT::T_FAT12: + INFO("FS", "Mounting FAT12 filesystem"); + break; + case FAT::T_FAT16: + INFO("FS", "Mounting FAT16 filesystem"); + break; + case FAT::T_FAT32: + INFO("FS", "Mounting FAT32 filesystem"); + break; + } + INFO2("[ofs=%u size=%u (%u bytes)]\n", + this->lba_base, this->lba_size, this->lba_size * 512); - // on_mount callback - on_mount(no_error); - }); + // on_mount callback + on_mount(no_error); + }); } bool FAT::int_dirent( - uint32_t sector, - const void* data, - dirvec_t dirents) + uint32_t sector, + const void* data, + dirvec_t dirents) { auto* root = (cl_dir*) data; bool found_last = false; @@ -174,97 +174,97 @@ namespace fs for (int i = 0; i < 16; i++) { if (unlikely(root[i].shortname[0] == 0x0)) - { - //printf("end of dir\n"); - found_last = true; - // end of directory - break; - } + { + //printf("end of dir\n"); + found_last = true; + // end of directory + break; + } else if (unlikely(root[i].shortname[0] == 0xE5)) - { - // unused index - } + { + // unused index + } else - { + { // traverse long names, then final cluster // to read all the relevant info if (likely(root[i].is_longname())) - { - auto* L = (cl_long*) &root[i]; - // the last long index is part of a chain of entries - if (L->is_last()) - { - // buffer for long filename - char final_name[256]; - int final_count = 0; + { + auto* L = (cl_long*) &root[i]; + // the last long index is part of a chain of entries + if (L->is_last()) + { + // buffer for long filename + char final_name[256]; + int final_count = 0; - int total = L->long_index(); - // go to the last entry and work backwards - i += total-1; - L += total-1; + int total = L->long_index(); + // go to the last entry and work backwards + i += total-1; + L += total-1; - for (int idx = total; idx > 0; idx--) - { - uint16_t longname[13]; - memcpy(longname+ 0, L->first, 10); - memcpy(longname+ 5, L->second, 12); - memcpy(longname+11, L->third, 4); + for (int idx = total; idx > 0; idx--) + { + uint16_t longname[13]; + memcpy(longname+ 0, L->first, 10); + memcpy(longname+ 5, L->second, 12); + memcpy(longname+11, L->third, 4); - for (int j = 0; j < 13; j++) - { - // 0xFFFF indicates end of name - if (unlikely(longname[j] == 0xFFFF)) break; - // sometimes, invalid stuff are snuck into filenames - if (unlikely(longname[j] == 0x0)) break; + for (int j = 0; j < 13; j++) + { + // 0xFFFF indicates end of name + if (unlikely(longname[j] == 0xFFFF)) break; + // sometimes, invalid stuff are snuck into filenames + if (unlikely(longname[j] == 0x0)) break; - final_name[final_count] = longname[j] & 0xFF; - final_count++; - } - L--; + final_name[final_count] = longname[j] & 0xFF; + final_count++; + } + L--; - if (unlikely(final_count > 240)) - { - debug("Suspicious long name length, breaking...\n"); - break; - } - } + if (unlikely(final_count > 240)) + { + debug("Suspicious long name length, breaking...\n"); + break; + } + } - final_name[final_count] = 0; - debug("Long name: %s\n", final_name); + final_name[final_count] = 0; + debug("Long name: %s\n", final_name); - i++; // skip over the long version - // to the short version for the stats and cluster - auto* D = &root[i]; - std::string dirname(final_name, final_count); - dirname = trim_right_copy(dirname); + i++; // skip over the long version + // to the short version for the stats and cluster + auto* D = &root[i]; + std::string dirname(final_name, final_count); + dirname = trim_right_copy(dirname); - dirents->emplace_back( - D->type(), - dirname, - D->dir_cluster(root_cluster), - sector, // parent block - D->size(), - D->attrib); - } - } + dirents->emplace_back( + D->type(), + dirname, + D->dir_cluster(root_cluster), + sector, // parent block + D->size(), + D->attrib); + } + } else - { - auto* D = &root[i]; - debug("Short name: %.11s\n", D->shortname); + { + auto* D = &root[i]; + debug("Short name: %.11s\n", D->shortname); - std::string dirname((char*) D->shortname, 11); - dirname = trim_right_copy(dirname); + std::string dirname((char*) D->shortname, 11); + dirname = trim_right_copy(dirname); - dirents->emplace_back( - D->type(), - dirname, - D->dir_cluster(root_cluster), - sector, // parent block - D->size(), - D->attrib); - } - } + dirents->emplace_back( + D->type(), + dirname, + D->dir_cluster(root_cluster), + sector, // parent block + D->size(), + D->attrib); + } + } } // directory list return found_last; diff --git a/src/fs/fat_async.cpp b/src/fs/fat_async.cpp index ca1cb4b1db..d8c47858d4 100644 --- a/src/fs/fat_async.cpp +++ b/src/fs/fat_async.cpp @@ -15,9 +15,9 @@ namespace fs { void FAT::int_ls( - uint32_t sector, - dirvec_t dirents, - on_internal_ls_func callback) + uint32_t sector, + dirvec_t dirents, + on_internal_ls_func callback) { // list contents of meme sector by sector typedef std::function next_func_t; @@ -26,29 +26,29 @@ namespace fs *next = [this, sector, callback, dirents, next] (uint32_t sector) { - debug("int_ls: sec=%u\n", sector); - device.read(sector, - [this, sector, callback, dirents, next] (buffer_t data) + debug("int_ls: sec=%u\n", sector); + device.read(sector, + [this, sector, callback, dirents, next] (buffer_t data) { if (!data) - { - // could not read sector - callback(true, dirents); - return; - } + { + // could not read sector + callback(true, dirents); + return; + } // parse entries in sector bool done = int_dirent(sector, data.get(), dirents); if (done) - { - // execute callback - callback(no_error, dirents); - } + { + // execute callback + callback(no_error, dirents); + } else - { - // go to next sector - (*next)(sector+1); - } + { + // go to next sector + (*next)(sector+1); + } }); // read root dir }; @@ -67,60 +67,60 @@ namespace fs *next = [this, path, next, callback] (uint32_t cluster) { - if (path->empty()) - { - // attempt to read directory - uint32_t S = this->cl_to_sector(cluster); + if (path->empty()) + { + // attempt to read directory + uint32_t S = this->cl_to_sector(cluster); - // result allocated on heap - auto dirents = std::make_shared> (); + // result allocated on heap + auto dirents = std::make_shared> (); - int_ls(S, dirents, - [callback] (error_t error, dirvec_t ents) + int_ls(S, dirents, + [callback] (error_t error, dirvec_t ents) { - callback(error, ents); + callback(error, ents); }); - return; - } + return; + } - // retrieve next name - std::string name = path->front(); - path->pop_front(); + // retrieve next name + std::string name = path->front(); + path->pop_front(); - uint32_t S = this->cl_to_sector(cluster); - debug("Current target: %s on cluster %u (sector %u)\n", name.c_str(), cluster, S); + uint32_t S = this->cl_to_sector(cluster); + debug("Current target: %s on cluster %u (sector %u)\n", name.c_str(), cluster, S); - // result allocated on heap - auto dirents = std::make_shared> (); + // result allocated on heap + auto dirents = std::make_shared> (); - // list directory contents - int_ls(S, dirents, - [name, dirents, next, callback] (error_t error, dirvec_t ents) + // list directory contents + int_ls(S, dirents, + [name, dirents, next, callback] (error_t error, dirvec_t ents) { if (unlikely(error)) - { - debug("Could not find: %s\n", name.c_str()); - callback(true, dirents); - return; - } + { + debug("Could not find: %s\n", name.c_str()); + callback(true, dirents); + return; + } // look for name in directory for (auto& e : *ents) - { - if (unlikely(e.name() == name)) - { - // go to this directory, unless its the last name - debug("Found match for %s", name.c_str()); - // enter the matching directory - debug("\t\t cluster: %llu\n", e.block); - // only follow directories - if (e.type() == DIR) - (*next)(e.block); - else - callback(true, dirents); - return; - } - } // for (ents) + { + if (unlikely(e.name() == name)) + { + // go to this directory, unless its the last name + debug("Found match for %s", name.c_str()); + // enter the matching directory + debug("\t\t cluster: %llu\n", e.block); + // only follow directories + if (e.type() == DIR) + (*next)(e.block); + else + callback(true, dirents); + return; + } + } // for (ents) debug("NO MATCH for %s\n", name.c_str()); callback(true, dirents); @@ -137,10 +137,10 @@ namespace fs auto pstk = std::make_shared (path); traverse(pstk, - [on_ls] (error_t error, dirvec_t dirents) - { - on_ls(error, dirents); - }); + [on_ls] (error_t error, dirvec_t dirents) + { + on_ls(error, dirents); + }); } void FAT::read(const Dirent& ent, uint64_t pos, uint64_t n, on_read_func callback) @@ -158,42 +158,42 @@ namespace fs *next = [this, sector, buffer, callback, next] (size_t start, size_t n, size_t end) { - if (unlikely(n == end)) - { - // report back to HQ - debug("DONE start=%lu, current=%lu, total=%lu\n", start, n, end - start); - // create shared buffer - auto buffer_ptr = buffer_t(buffer, std::default_delete()); - // notify caller - callback(no_error, buffer_ptr, end - start); - return; - } + if (unlikely(n == end)) + { + // report back to HQ + debug("DONE start=%lu, current=%lu, total=%lu\n", start, n, end - start); + // create shared buffer + auto buffer_ptr = buffer_t(buffer, std::default_delete()); + // notify caller + callback(no_error, buffer_ptr, end - start); + return; + } - // read the current sector based on position @n - uint32_t current_sector = sector + n / this->sector_size; + // read the current sector based on position @n + uint32_t current_sector = sector + n / this->sector_size; - device.read(current_sector, - [this, start, n, end, buffer, &callback, sector, next] (buffer_t data) + device.read(current_sector, + [this, start, n, end, buffer, &callback, sector, next] (buffer_t data) { if (!data) - { - // general I/O error occurred - debug("Failed to read sector %u for read()", sector); - // cleanup - delete[] buffer; - callback(true, buffer_t(), 0); - return; - } + { + // general I/O error occurred + debug("Failed to read sector %u for read()", sector); + // cleanup + delete[] buffer; + callback(true, buffer_t(), 0); + return; + } uint32_t length = n & (sector_size-1); if (n == start && n > 0) - { - length = sector_size - length; - } + { + length = sector_size - length; + } else - { - length = (n + sector_size) < end ? sector_size : (end - n); - } + { + length = (n + sector_size) < end ? sector_size : (end - n); + } // copy over data memcpy(buffer + n, data.get(), length); @@ -211,9 +211,9 @@ namespace fs auto path = std::make_shared (strpath); if (unlikely(path->empty())) { - // there is no possible file to read where path is empty - callback(true, nullptr, 0); - return; + // there is no possible file to read where path is empty + callback(true, nullptr, 0); + return; } debug("readFile: %s\n", path->back().c_str()); @@ -221,29 +221,29 @@ namespace fs path->pop_back(); traverse(path, - [this, filename, &callback] (error_t error, dirvec_t dirents) - { - if (unlikely(error)) - { - // no path, no file! - callback(error, buffer_t(), 0); - return; - } + [this, filename, &callback] (error_t error, dirvec_t dirents) + { + if (unlikely(error)) + { + // no path, no file! + callback(error, buffer_t(), 0); + return; + } - // find the matching filename in directory - for (auto& ent : *dirents) - { - if (unlikely(ent.name() == filename)) - { - // read this file - read(ent, 0, ent.size, callback); - return; - } - } + // find the matching filename in directory + for (auto& ent : *dirents) + { + if (unlikely(ent.name() == filename)) + { + // read this file + read(ent, 0, ent.size, callback); + return; + } + } - // file not found - callback(true, buffer_t(), 0); - }); + // file not found + callback(true, buffer_t(), 0); + }); } // readFile() void FAT::stat(const std::string& strpath, on_stat_func func) @@ -251,10 +251,10 @@ namespace fs auto path = std::make_shared (strpath); if (unlikely(path->empty())) { - // root doesn't have any stat anyways - // Note: could use ATTR_VOLUME_ID in FAT - func(true, Dirent(INVALID_ENTITY, strpath)); - return; + // root doesn't have any stat anyways + // Note: could use ATTR_VOLUME_ID in FAT + func(true, Dirent(INVALID_ENTITY, strpath)); + return; } debug("stat: %s\n", path->back().c_str()); @@ -265,28 +265,28 @@ namespace fs auto callback = std::make_shared (func); traverse(path, - [this, filename, callback] (error_t error, dirvec_t dirents) - { - if (unlikely(error)) - { - // no path, no file! - (*callback)(error, Dirent(INVALID_ENTITY, filename)); - return; - } + [this, filename, callback] (error_t error, dirvec_t dirents) + { + if (unlikely(error)) + { + // no path, no file! + (*callback)(error, Dirent(INVALID_ENTITY, filename)); + return; + } - // find the matching filename in directory - for (auto& e : *dirents) - { - if (unlikely(e.name() == filename)) - { - // read this file - (*callback)(no_error, e); - return; - } - } + // find the matching filename in directory + for (auto& e : *dirents) + { + if (unlikely(e.name() == filename)) + { + // read this file + (*callback)(no_error, e); + return; + } + } - // not found - (*callback)(true, Dirent(INVALID_ENTITY, filename)); - }); + // not found + (*callback)(true, Dirent(INVALID_ENTITY, filename)); + }); } } diff --git a/src/fs/fat_sync.cpp b/src/fs/fat_sync.cpp index e1b3af2d58..5efc2bb2ec 100644 --- a/src/fs/fat_sync.cpp +++ b/src/fs/fat_sync.cpp @@ -36,9 +36,9 @@ namespace fs // if what we want to read is larger than the rest, exit early if (rest > n) { - memcpy(result, data.get() + internal_ofs, n); + memcpy(result, data.get() + internal_ofs, n); - return Buffer(no_error, buffer_t(result), n); + return Buffer(no_error, buffer_t(result), n); } // otherwise, read to the sector border uint8_t* ptr = result; @@ -50,19 +50,19 @@ namespace fs // copy entire sectors while (n > device.block_size()) { - data = device.read_sync(sector); + data = device.read_sync(sector); - memcpy(ptr, data.get(), device.block_size()); - ptr += device.block_size(); - n -= device.block_size(); - sector += 1; + memcpy(ptr, data.get(), device.block_size()); + ptr += device.block_size(); + n -= device.block_size(); + sector += 1; } // copy remainder if (likely(n > 0)) { - data = device.read_sync(sector); - memcpy(ptr, data.get(), n); + data = device.read_sync(sector); + memcpy(ptr, data.get(), n); } return Buffer(no_error, buffer_t(result), total); @@ -73,8 +73,8 @@ namespace fs Path path(strpath); if (unlikely(path.empty())) { - // there is no possible file to read where path is empty - return Buffer(true, nullptr, 0); + // there is no possible file to read where path is empty + return Buffer(true, nullptr, 0); } debug("readFile: %s\n", path.back().c_str()); @@ -90,11 +90,11 @@ namespace fs // find the matching filename in directory for (auto& e : *dirents) { - if (unlikely(e.name() == filename)) - { - // read this file - return read(e, 0, e.size); - } + if (unlikely(e.name() == filename)) + { + // read this file + return read(e, 0, e.size); + } } // entry not found return Buffer(true, buffer_t(), 0); @@ -105,13 +105,13 @@ namespace fs bool done = false; while (!done) { - // read sector sync - buffer_t data = device.read_sync(sector); - if (!data) return true; - // parse directory into @ents - done = int_dirent(sector, data.get(), ents); - // go to next sector until done - sector++; + // read sector sync + buffer_t data = device.read_sync(sector); + if (!data) return true; + // parse directory into @ents + done = int_dirent(sector, data.get(), ents); + // go to next sector until done + sector++; } return no_error; } @@ -126,44 +126,44 @@ namespace fs while (!path.empty()) { - uint32_t S = this->cl_to_sector(cluster); - dirents->clear(); // mui importante - // sync read entire directory - auto err = int_ls(S, dirents); - if (err) return err; - // the name we are looking for - std::string name = path.front(); - path.pop_front(); + uint32_t S = this->cl_to_sector(cluster); + dirents->clear(); // mui importante + // sync read entire directory + auto err = int_ls(S, dirents); + if (err) return err; + // the name we are looking for + std::string name = path.front(); + path.pop_front(); - // check for matches in dirents - for (auto& e : *dirents) - if (unlikely(e.name() == name)) - { - // go to this directory, unless its the last name - debug("traverse_sync: Found match for %s", name.c_str()); - // enter the matching directory - debug("\t\t cluster: %lu\n", e.block); - // only follow if the name is a directory - if (e.type() == DIR) - { - found = e; - break; - } - else - { - // not dir = error, for now - return true; - } - } // for (ents) + // check for matches in dirents + for (auto& e : *dirents) + if (unlikely(e.name() == name)) + { + // go to this directory, unless its the last name + debug("traverse_sync: Found match for %s", name.c_str()); + // enter the matching directory + debug("\t\t cluster: %lu\n", e.block); + // only follow if the name is a directory + if (e.type() == DIR) + { + found = e; + break; + } + else + { + // not dir = error, for now + return true; + } + } // for (ents) - // validate result - if (found.type() == INVALID_ENTITY) - { - debug("traverse_sync: NO MATCH for %s\n", name.c_str()); - return true; - } - // set next cluster - cluster = found.block; + // validate result + if (found.type() == INVALID_ENTITY) + { + debug("traverse_sync: NO MATCH for %s\n", name.c_str()); + return true; + } + // set next cluster + cluster = found.block; } uint32_t S = this->cl_to_sector(cluster); @@ -181,8 +181,8 @@ namespace fs Path path(strpath); if (unlikely(path.empty())) { - // root doesn't have any stat anyways (except ATTR_VOLUME_ID in FAT) - return Dirent(INVALID_ENTITY); + // root doesn't have any stat anyways (except ATTR_VOLUME_ID in FAT) + return Dirent(INVALID_ENTITY); } debug("stat_sync: %s\n", path.back().c_str()); @@ -199,11 +199,11 @@ namespace fs // find the matching filename in directory for (auto& e : *dirents) { - if (unlikely(e.name() == filename)) - { - // return this directory entry - return e; - } + if (unlikely(e.name() == filename)) + { + // return this directory entry + return e; + } } // entry not found return Dirent(INVALID_ENTITY); diff --git a/src/fs/mbr.cpp b/src/fs/mbr.cpp index 0e1dabc188..aae019b0ac 100644 --- a/src/fs/mbr.cpp +++ b/src/fs/mbr.cpp @@ -7,71 +7,71 @@ namespace fs switch (id) { case 0x00: - return "Empty"; + return "Empty"; case 0x01: - return "DOS 12-bit FAT"; + return "DOS 12-bit FAT"; case 0x02: - return "XENIX root"; + return "XENIX root"; case 0x03: - return "XENIX /usr"; + return "XENIX /usr"; case 0x04: - return "DOS 3.0+ 16-bit FAT"; + return "DOS 3.0+ 16-bit FAT"; case 0x05: - return "DOS 3.3+ Extended Partition"; + return "DOS 3.3+ Extended Partition"; case 0x06: - return "DOS 3.31+ 16-bit FAT (32M+)"; + return "DOS 3.31+ 16-bit FAT (32M+)"; case 0x07: - return "NTFS or exFAT"; + return "NTFS or exFAT"; case 0x08: - return "Commodore DOS logical FAT"; + return "Commodore DOS logical FAT"; case 0x0b: - return "WIN95 OSR2 FAT32"; + return "WIN95 OSR2 FAT32"; case 0x0c: - return "WIN95 OSR2 FAT32, LBA-mapped"; + return "WIN95 OSR2 FAT32, LBA-mapped"; case 0x0d: - return "SILICON SAFE"; + return "SILICON SAFE"; case 0x0e: - return "WIN95: DOS 16-bit FAT, LBA-mapped"; + return "WIN95: DOS 16-bit FAT, LBA-mapped"; case 0x0f: - return "WIN95: Extended partition, LBA-mapped"; + return "WIN95: Extended partition, LBA-mapped"; case 0x11: - return "Hidden DOS 12-bit FAT"; + return "Hidden DOS 12-bit FAT"; case 0x12: - return "Configuration utility partition (Compaq)"; + return "Configuration utility partition (Compaq)"; case 0x14: - return "Hidden DOS 16-bit FAT <32M"; + return "Hidden DOS 16-bit FAT <32M"; case 0x16: - return "Hidden DOS 16-bit FAT >= 32M"; + return "Hidden DOS 16-bit FAT >= 32M"; case 0x27: - return "Windows RE hidden partition"; + return "Windows RE hidden partition"; case 0x3c: - return "PartitionMagic recovery partition"; + return "PartitionMagic recovery partition"; case 0x82: - return "Linux swap"; + return "Linux swap"; case 0x83: - return "Linux native partition"; + return "Linux native partition"; case 0x84: - return "Hibernation partition"; + return "Hibernation partition"; case 0x85: - return "Linux extended partition"; + return "Linux extended partition"; case 0x86: - return "FAT16 fault tolerant volume set"; + return "FAT16 fault tolerant volume set"; case 0x87: - return "NTFS fault tolerant volume set"; + return "NTFS fault tolerant volume set"; case 0x8e: - return "Linux Logical Volume Manager partition"; + return "Linux Logical Volume Manager partition"; case 0x9f: - return "BSDI (BSD/OS)"; + return "BSDI (BSD/OS)"; case 0xa6: - return "OpenBSD"; + return "OpenBSD"; case 0xa8: - return "Apple MacOS X (BSD-like filesystem)"; + return "Apple MacOS X (BSD-like filesystem)"; case 0xa9: - return "NetBSD"; + return "NetBSD"; case 0xaf: - return "MacOS X HFS"; + return "MacOS X HFS"; default: - return "Invalid identifier: " + std::to_string(id); + return "Invalid identifier: " + std::to_string(id); } } diff --git a/src/fs/memdisk.cpp b/src/fs/memdisk.cpp index 83fed8ddab..967f39208c 100644 --- a/src/fs/memdisk.cpp +++ b/src/fs/memdisk.cpp @@ -41,7 +41,7 @@ namespace fs { // Disallow reading memory past disk image if (unlikely(sector_loc >= image_end)) { - callback(buffer_t()); return; + callback(buffer_t()); return; } auto* buffer = new uint8_t[block_size()]; @@ -56,7 +56,7 @@ namespace fs { // Disallow reading memory past disk image if (unlikely(end_loc >= image_end)) { - callback(buffer_t()); return; + callback(buffer_t()); return; } auto* buffer = new uint8_t[count * block_size()]; diff --git a/src/fs/path.cpp b/src/fs/path.cpp index 45fe6a7612..fbf03b5156 100644 --- a/src/fs/path.cpp +++ b/src/fs/path.cpp @@ -23,7 +23,7 @@ namespace fs { static const char PATH_SEPARATOR = '/'; - + Path::Path() : Path("/") { @@ -33,9 +33,9 @@ namespace fs { // parse full path this->state = parse(path); - + } // Path::Path(std::string) - + std::string Path::to_string() const { // build path @@ -43,66 +43,66 @@ namespace fs std::string ss; for (const auto& p : this->stk) { - ss += PATH_SEPARATOR + p; + ss += PATH_SEPARATOR + p; } // append path/ to end ss += PATH_SEPARATOR; return ss; } - + int Path::parse(const std::string& path) { if (path.empty()) { - // do nothing? - return 0; + // do nothing? + return 0; } - + std::string buffer(path.size(), 0); char lastChar = 0; int bufi = 0; - + for (size_t i = 0; i < path.size(); i++) { - if (path[i] == PATH_SEPARATOR) - { - if (lastChar == PATH_SEPARATOR) - { // invalid path containing // (more than one forw-slash) - return -EINVAL; - } - if (bufi) - { - name_added(std::string(buffer, 0, bufi)); - bufi = 0; - } - else if (i == 0) - { - // if the first character is / separator, - // the path is relative to root, so clear stack - stk.clear(); - } - } - else - { - buffer[bufi] = path[i]; - bufi++; - } - lastChar = path[i]; + if (path[i] == PATH_SEPARATOR) + { + if (lastChar == PATH_SEPARATOR) + { // invalid path containing // (more than one forw-slash) + return -EINVAL; + } + if (bufi) + { + name_added(std::string(buffer, 0, bufi)); + bufi = 0; + } + else if (i == 0) + { + // if the first character is / separator, + // the path is relative to root, so clear stack + stk.clear(); + } + } + else + { + buffer[bufi] = path[i]; + bufi++; + } + lastChar = path[i]; } // parse path if (bufi) { - name_added(std::string(buffer, 0, bufi)); + name_added(std::string(buffer, 0, bufi)); } return 0; } - + void Path::name_added(const std::string& name) { //std::cout << "Path: " << toString() << " --> " << name << std::endl; - + if (name == ".") { - // same directory + // same directory } /*else if (name == "..") { @@ -116,8 +116,8 @@ namespace fs }*/ else { - // otherwise treat as directory - stk.push_back(name); + // otherwise treat as directory + stk.push_back(name); } } } diff --git a/src/hw/cpu_freq_sampling.cpp b/src/hw/cpu_freq_sampling.cpp index b6899ccf9b..ebda6604d5 100644 --- a/src/hw/cpu_freq_sampling.cpp +++ b/src/hw/cpu_freq_sampling.cpp @@ -71,8 +71,8 @@ namespace hw { auto freq = cycles / (1 / test_frequency().count()); _cpu_freq_samples.push_back(freq); debug("%lu - %lu = Delta: %lu Current PIT-Freq: %f Hz CPU Freq: %f MHz \n", - (uint32_t)_cpu_timestamps[i], (uint32_t)_cpu_timestamps[i-1], - (uint32_t)cycles, Hz(test_frequency()), freq); + (uint32_t)_cpu_timestamps[i], (uint32_t)_cpu_timestamps[i-1], + (uint32_t)cycles, Hz(test_frequency()), freq); } diff --git a/src/hw/ide.cpp b/src/hw/ide.cpp index 8f8fb0acbb..1da37c1ff2 100644 --- a/src/hw/ide.cpp +++ b/src/hw/ide.cpp @@ -193,11 +193,11 @@ namespace hw { for (int i {IDE_TIMEOUT}; i; --i) { if (set) { - if ((ret & flags) == flags) - break; + if ((ret & flags) == flags) + break; } else { - if ((ret & flags) not_eq flags) - break; + if ((ret & flags) not_eq flags) + break; } ret = inb(IDE_STATUS); diff --git a/src/hw/pci_device.cpp b/src/hw/pci_device.cpp index 2a1174856c..f4207c6c1c 100644 --- a/src/hw/pci_device.cpp +++ b/src/hw/pci_device.cpp @@ -69,10 +69,10 @@ namespace hw { } _pci_vendorlist[] { {0x8086,"Intel Corp."}, {0x1013,"Cirrus Logic"}, - {0x10EC,"Realtek Semi.Corp."}, - {0x1AF4,"Virtio (Rusty Russell)"}, // Virtio creator - {0x1022,"AMD"}, - {0x0000,NULL} + {0x10EC,"Realtek Semi.Corp."}, + {0x1AF4,"Virtio (Rusty Russell)"}, // Virtio creator + {0x1022,"AMD"}, + {0x0000,NULL} }; static unsigned long pci_size(const unsigned long base, const unsigned long mask) noexcept { @@ -116,21 +116,21 @@ namespace hw { if (value & 1) { // Resource type IO - unmasked_val = value & PCI::BASE_ADDRESS_IO_MASK; - pci__size = pci_size(len, PCI::BASE_ADDRESS_IO_MASK & 0xFFFF); + unmasked_val = value & PCI::BASE_ADDRESS_IO_MASK; + pci__size = pci_size(len, PCI::BASE_ADDRESS_IO_MASK & 0xFFFF); - // Add it to resource list - add_resource(new Resource(unmasked_val, pci__size), res_io_); - assert(res_io_ != nullptr); + // Add it to resource list + add_resource(new Resource(unmasked_val, pci__size), res_io_); + assert(res_io_ != nullptr); } else { //Resource type Mem - unmasked_val = value & PCI::BASE_ADDRESS_MEM_MASK; - pci__size = pci_size(len, PCI::BASE_ADDRESS_MEM_MASK); + unmasked_val = value & PCI::BASE_ADDRESS_MEM_MASK; + pci__size = pci_size(len, PCI::BASE_ADDRESS_MEM_MASK); - //Add it to resource list - add_resource(new Resource(unmasked_val, pci__size), res_mem_); - assert(res_mem_ != nullptr); + //Add it to resource list + add_resource(new Resource(unmasked_val, pci__size), res_mem_); + assert(res_mem_ != nullptr); } INFO2(""); @@ -159,14 +159,14 @@ namespace hw { switch (devtype_.classcode) { case PCI::BRIDGE: INFO2("+--+ %s %s (0x%x)", - bridge_subclasses[devtype_.subclass < SS_BR ? devtype_.subclass : SS_BR-1], - classcodes[devtype_.classcode],devtype_.subclass); + bridge_subclasses[devtype_.subclass < SS_BR ? devtype_.subclass : SS_BR-1], + classcodes[devtype_.classcode],devtype_.subclass); break; case PCI::NIC: INFO2("+--+ %s %s (0x%x)", - nic_subclasses[devtype_.subclass < SS_NIC ? devtype_.subclass : SS_NIC-1], - classcodes[devtype_.classcode],devtype_.subclass); + nic_subclasses[devtype_.subclass < SS_NIC ? devtype_.subclass : SS_NIC-1], + classcodes[devtype_.classcode],devtype_.subclass); break; default: diff --git a/src/hw/pit.cpp b/src/hw/pit.cpp index 503eb42538..11ffc8e9e6 100644 --- a/src/hw/pit.cpp +++ b/src/hw/pit.cpp @@ -125,7 +125,7 @@ namespace hw { auto ticks = in_msecs / KHz(current_frequency()).count(); debug(" PIT KHz: %f * %i = %f ms. \n", - KHz(current_frequency()).count(), (uint32_t)ticks.count(), ((uint32_t)ticks.count() * KHz(current_frequency()).count())); + KHz(current_frequency()).count(), (uint32_t)ticks.count(), ((uint32_t)ticks.count() * KHz(current_frequency()).count())); t.setStart(OS::cycles_since_boot()); t.setEnd(t.start() + uint64_t(cycles_pr_millisec.count() * in_msecs.count())); @@ -137,7 +137,7 @@ namespace hw { timers_.insert(std::make_pair(key, t)); debug(" Key: %i id: %i, t.cond()(): %s There are %i timers. \n", - (uint32_t)key, t.id(), t.cond()() ? "true" : "false", timers_.size()); + (uint32_t)key, t.id(), t.cond()() ? "true" : "false", timers_.size()); } @@ -154,7 +154,7 @@ namespace hw { Timer t(Timer::ONE_SHOT, handler, msec); debug(" setting a %i ms. one-shot timer. Id: %i \n", - (uint32_t)msec.count(), t.id()); + (uint32_t)msec.count(), t.id()); start_timer(t, msec); @@ -193,22 +193,22 @@ namespace hw { // Map-keys are sorted. If this timer isn't expired, neither are the rest if (it->first > millisec_counter) - break; + break; debug2 ("\n**** Timer type %i, id: %i expired. Running handler **** \n", - it->second.type(), it->second.id()); + it->second.type(), it->second.id()); // Execute the handler it->second.handler()(); // Re-queue repeating timers if (it->second.type() == Timer::REPEAT) { - debug2 (" REPEAT: Requeuing the timer \n"); - start_timer(it->second, it->second.interval()); + debug2 (" REPEAT: Requeuing the timer \n"); + start_timer(it->second, it->second.interval()); }else if (it->second.type() == Timer::REPEAT_WHILE and it->second.cond()()) { - debug2 (" REPEAT_WHILE: Requeuing the timer COND \n"); - start_timer(it->second, it->second.interval()); + debug2 (" REPEAT_WHILE: Requeuing the timer COND \n"); + start_timer(it->second, it->second.interval()); } debug2 ("Timer done. Erasing. \n"); @@ -222,19 +222,19 @@ namespace hw { // If this was the last timer, we can turn off the clock if (timers_.empty()){ - // Disable the PIT - oneshot(1); + // Disable the PIT + oneshot(1); - debug2 ("Timers done. PIT disabled for now. \n"); - // Escape iterator death - break; + debug2 ("Timers done. PIT disabled for now. \n"); + // Escape iterator death + break; } debug2 ("Timers left: %i \n", timers_.size()); #ifdef DEBUG2 for (auto t : timers_) - debug2("Key: %i , id: %i, Type: %i", (uint32_t)t.first, t.second.id(), t.second.type()); + debug2("Key: %i , id: %i, Type: %i", (uint32_t)t.first, t.second.id(), t.second.type()); #endif debug2("\n---------------------------\n\n"); diff --git a/src/kernel/cpuid.cpp b/src/kernel/cpuid.cpp index 0a38bfb572..d5b9ba34d6 100644 --- a/src/kernel/cpuid.cpp +++ b/src/kernel/cpuid.cpp @@ -95,10 +95,10 @@ static cpuid_t cpuid_info(const unsigned int func, const unsigned int subfunc) { cpuid_t info; __asm__ __volatile__ ( - "cpuid" - : "=a"(info.EAX), "=b"(info.EBX), "=c"(info.ECX), "=d"(info.EDX) - : "a"(func), "c"(subfunc) : "%eax", "%ebx", "%ecx", "%edx" - ); + "cpuid" + : "=a"(info.EAX), "=b"(info.EBX), "=c"(info.ECX), "=d"(info.EDX) + : "a"(func), "c"(subfunc) : "%eax", "%ebx", "%ecx", "%edx" + ); return info; } diff --git a/src/kernel/irq_manager.cpp b/src/kernel/irq_manager.cpp index 21dbfa2230..61496f1314 100644 --- a/src/kernel/irq_manager.cpp +++ b/src/kernel/irq_manager.cpp @@ -49,9 +49,9 @@ enum { static inline void cpuid(int code, uint32_t *a, uint32_t *d) { asm volatile("cpuid" - :"=a"(*a),"=d"(*d) - :"a"(code) - :"ecx","ebx"); + :"=a"(*a),"=d"(*d) + :"a"(code) + :"ecx","ebx"); } bool cpuHasAPIC() { @@ -66,21 +66,21 @@ extern "C" } /** Default Exception-handler, which just prints its number */ -#define EXCEPTION_HANDLER(I) \ - void exception_##I##_handler() { \ - printf("\n\n>>>> !!! CPU EXCEPTION %i !!! <<<<<\n", I); \ - printf("Heap end: %#x \n", (uint32_t)&_end); \ - kill(1, 9); \ +#define EXCEPTION_HANDLER(I) \ + void exception_##I##_handler() { \ + printf("\n\n>>>> !!! CPU EXCEPTION %i !!! <<<<<\n", I); \ + printf("Heap end: %#x \n", (uint32_t)&_end); \ + kill(1, 9); \ } void exception_handler() { -#define frp(N, ra) \ - (__builtin_frame_address(N) != nullptr) && \ +#define frp(N, ra) \ + (__builtin_frame_address(N) != nullptr) && \ (ra = __builtin_return_address(N)) != nullptr printf("\n"); -#define PRINT_TRACE(N, ra) \ +#define PRINT_TRACE(N, ra) \ printf("[%d] Return %p\n", N, ra); void* ra; @@ -89,16 +89,16 @@ void exception_handler() if (frp(1, ra)) { PRINT_TRACE(1, ra); if (frp(2, ra)) { - PRINT_TRACE(2, ra); - if (frp(3, ra)) { - PRINT_TRACE(3, ra); - if (frp(4, ra)) { - PRINT_TRACE(4, ra); - if (frp(5, ra)) { - PRINT_TRACE(5, ra); - if (frp(6, ra)) - PRINT_TRACE(6, ra); - }}}}}} + PRINT_TRACE(2, ra); + if (frp(3, ra)) { + PRINT_TRACE(3, ra); + if (frp(4, ra)) { + PRINT_TRACE(4, ra); + if (frp(5, ra)) { + PRINT_TRACE(5, ra); + if (frp(6, ra)) + PRINT_TRACE(6, ra); + }}}}}} printf(">>>> !!! CPU EXCEPTION !!! <<<<\n"); extern char _end; @@ -115,17 +115,17 @@ void exception_handler() uint32_t IRQ_manager::irq_counters_[32] {0}; -#define IRQ_HANDLER(I) \ - void irq_##I##_handler() { \ - IRQ_manager::register_interrupt(I); \ +#define IRQ_HANDLER(I) \ + void irq_##I##_handler() { \ + IRQ_manager::register_interrupt(I); \ } /* Macro magic to register default gates */ -#define REG_DEFAULT_EXCPT(I) create_gate(&(idt[I]),exception_entry, \ - default_sel, default_attr ); +#define REG_DEFAULT_EXCPT(I) create_gate(&(idt[I]),exception_entry, \ + default_sel, default_attr ); #define REG_DEFAULT_IRQ(I) create_gate(&(idt[I + irq_base]),irq_##I##_entry, \ - default_sel, default_attr ); + default_sel, default_attr ); /* EXCEPTIONS */ #define EXCEPTION_PAIR(I) void exception_entry(); @@ -232,9 +232,9 @@ union addr_union { }; void IRQ_manager::create_gate(IDTDescr* idt_entry, - void (*function_addr)(), - uint16_t segment_sel, - char attributes) { + void (*function_addr)(), + uint16_t segment_sel, + char attributes) { addr_union addr; addr.whole = (uint32_t)function_addr; idt_entry->offset_1 = addr.lo16; @@ -365,7 +365,7 @@ void irq_timer_handler() { } inline void disable_pic() { - asm volatile("mov $0xff,%al; " \ - "out %al,$0xa1; " \ - "out %al,$0x21; "); + asm volatile("mov $0xff,%al; " \ + "out %al,$0xa1; " \ + "out %al,$0x21; "); } diff --git a/src/kernel/terminal.cpp b/src/kernel/terminal.cpp index 38e97b13ad..f2b86be68c 100644 --- a/src/kernel/terminal.cpp +++ b/src/kernel/terminal.cpp @@ -61,25 +61,25 @@ Terminal::Terminal(hw::Serial& serial) : Terminal() { serial.on_data( - [this, &serial] (char c) - { - this->read(&c, 1); - if (c == CR) - { - c = LF; - this->read(&c, 1); - } - else - { - serial.write(c); - } - }); + [this, &serial] (char c) + { + this->read(&c, 1); + if (c == CR) + { + c = LF; + this->read(&c, 1); + } + else + { + serial.write(c); + } + }); on_write = [&serial] (const char* buffer, size_t len) { for (size_t i = 0; i < len; i++) - serial.write(buffer[i]); + serial.write(buffer[i]); }; on_exit = @@ -95,40 +95,40 @@ void Terminal::read(const char* buf, size_t len) while (len) { if (this->subcmd) - { - // execute options - option(this->subcmd, (uint8_t) *buf); - this->subcmd = 0; - } + { + // execute options + option(this->subcmd, (uint8_t) *buf); + this->subcmd = 0; + } else if (this->iac) - { - command(*(uint8_t*) buf); - this->iac = false; - } + { + command(*(uint8_t*) buf); + this->iac = false; + } else if (*buf == 13 && !newline) - { - newline = true; - } + { + newline = true; + } else if (*buf == 10 && newline) - { - newline = false; - // parse message - run(buffer); - buffer.clear(); - } + { + newline = false; + // parse message + run(buffer); + buffer.clear(); + } else if (*buf == 0) - { - // NOP - } + { + // NOP + } else if ((uint8_t) *buf == 0xFF) - { - // Interpret as Command - this->iac = true; - } + { + // Interpret as Command + this->iac = true; + } else - { - buffer.append(buf, 1); - } + { + buffer.append(buf, 1); + } buf++; len--; } } @@ -189,8 +189,8 @@ split(const std::string& text, std::string& command) // early return for cmd-only msg if (x == std::string::npos) { - command = text; - return retv; + command = text; + return retv; } // command is substring command = text.substr(0, x); @@ -203,23 +203,23 @@ split(const std::string& text, std::string& command) size_t y = text.find(":", x+1); // find last param if (y == x+1) - { - // single argument - retv.push_back(text.substr(p, x-p)); - // ending text argument - retv.push_back(text.substr(y+1)); - break; - } + { + // single argument + retv.push_back(text.substr(p, x-p)); + // ending text argument + retv.push_back(text.substr(y+1)); + break; + } else if (x != std::string::npos) - { - // single argument - retv.push_back(text.substr(p, x-p)); - } + { + // single argument + retv.push_back(text.substr(p, x-p)); + } else - { - // last argument - retv.push_back(text.substr(p)); - } + { + // last argument + retv.push_back(text.substr(p)); + } p = x+1; } while (x != std::string::npos); @@ -237,14 +237,14 @@ void Terminal::run(const std::string& cmd_string) auto it = commands.find(cmd_name); if (it != commands.end()) - { - int retv = it->second.main(cmd_vec); - if (retv) write("%s returned: %d\r\n", cmd_name.c_str(), retv); - } + { + int retv = it->second.main(cmd_vec); + if (retv) write("%s returned: %d\r\n", cmd_name.c_str(), retv); + } else - { - write("No such command: '%s'\r\n", cmd_name.c_str()); - } + { + write("No such command: '%s'\r\n", cmd_name.c_str()); + } } prompt(); } @@ -256,19 +256,19 @@ void Terminal::add_basic_commands() "?", "List available commands", [this] (const std::vector&) -> int { - for (auto cmd : this->commands) - { - write("%s \t-- %s\r\n", cmd.first.c_str(), cmd.second.desc.c_str()); - } - return 0; + for (auto cmd : this->commands) + { + write("%s \t-- %s\r\n", cmd.first.c_str(), cmd.second.desc.c_str()); + } + return 0; }); // exit: add( "exit", "Close the terminal", [this] (const std::vector&) -> int { - this->on_exit(); - return 0; + this->on_exit(); + return 0; }); } @@ -290,8 +290,8 @@ void Terminal::intro() "-:;::;:;: ':;::;:'' ;.-' ""`---...________...---'"" - > Banana Terminal v1 < - )baaa"; + > Banana Terminal v1 < + )baaa"; write("%s", banana.c_str()); prompt(); diff --git a/src/kernel/terminal_disk.cpp b/src/kernel/terminal_disk.cpp index 77b8586a1c..62db898cfd 100644 --- a/src/kernel/terminal_disk.cpp +++ b/src/kernel/terminal_disk.cpp @@ -47,114 +47,114 @@ void Terminal::add_disk_commands(Disk_ptr disk) add("cd", "Change current directory", [this, curdir, disk] (const std::vector& args) -> int { - // current directory, somehow... - std::string target = "/"; - if (!args.empty()) target = args[0]; + // current directory, somehow... + std::string target = "/"; + if (!args.empty()) target = args[0]; - Path path(*curdir); - path += target; + Path path(*curdir); + path += target; - int rv = target_directory(disk, path); - if (rv) - { - this->write("cd: %s: No such file or directory\r\n", target.c_str()); - return rv; - } - *curdir = path.to_string(); - return 0; + int rv = target_directory(disk, path); + if (rv) + { + this->write("cd: %s: No such file or directory\r\n", target.c_str()); + return rv; + } + *curdir = path.to_string(); + return 0; }); // add 'ls' command add("ls", "List files in a folder", [this, curdir, disk] (const std::vector& args) -> int { - // current directory, somehow... - Path path(*curdir); - if (!args.empty()) path += args[0]; + // current directory, somehow... + Path path(*curdir); + if (!args.empty()) path += args[0]; - int rv = target_directory(disk, path); - if (rv) - { - this->write("ls: %s: No such file or directory\r\n", path.to_string().c_str()); - return rv; - } + int rv = target_directory(disk, path); + if (rv) + { + this->write("ls: %s: No such file or directory\r\n", path.to_string().c_str()); + return rv; + } - std::string target = path.to_string(); + std::string target = path.to_string(); - auto& fs = disk->fs(); - auto vec = fs::new_shared_vector(); - auto err = fs.ls(target, vec); - if (!err) - { - this->write("%s \t%s \t%s \t%s\r\n", - "Name", "Size", "Type", "Sector"); - for (auto& ent : *vec) - { - this->write("%s \t%llu \t%s \t%llu\r\n", - ent.name().c_str(), ent.size, ent.type_string().c_str(), ent.block); - } - this->write("Total %u\r\n", vec->size()); - return 0; - } - else - { - this->write("Could not list %s\r\n", args[0].c_str()); - return 1; - } + auto& fs = disk->fs(); + auto vec = fs::new_shared_vector(); + auto err = fs.ls(target, vec); + if (!err) + { + this->write("%s \t%s \t%s \t%s\r\n", + "Name", "Size", "Type", "Sector"); + for (auto& ent : *vec) + { + this->write("%s \t%llu \t%s \t%llu\r\n", + ent.name().c_str(), ent.size, ent.type_string().c_str(), ent.block); + } + this->write("Total %u\r\n", vec->size()); + return 0; + } + else + { + this->write("Could not list %s\r\n", args[0].c_str()); + return 1; + } }); // add 'stat' command add("stat", "List file information", [this, disk] (const std::vector& args) -> int { - if (!args.empty()) - { - auto& fs = disk->fs(); - auto ent = fs.stat(args[0]); - if (ent.is_valid()) - { - this->write("%s \t%s \t%s \t%s\r\n", - "Name", "Size", "Type", "Sector"); - this->write("%s \t%llu \t%s \t%llu\r\n", - ent.name().c_str(), ent.size, ent.type_string().c_str(), ent.block); - return 0; - } - else - { - this->write("stat: Cannot stat '%s'\r\n", args[0].c_str()); - return 1; - } - } - else - { - this->write("%s\r\n", "stat: Not enough arguments"); - return 1; - } + if (!args.empty()) + { + auto& fs = disk->fs(); + auto ent = fs.stat(args[0]); + if (ent.is_valid()) + { + this->write("%s \t%s \t%s \t%s\r\n", + "Name", "Size", "Type", "Sector"); + this->write("%s \t%llu \t%s \t%llu\r\n", + ent.name().c_str(), ent.size, ent.type_string().c_str(), ent.block); + return 0; + } + else + { + this->write("stat: Cannot stat '%s'\r\n", args[0].c_str()); + return 1; + } + } + else + { + this->write("%s\r\n", "stat: Not enough arguments"); + return 1; + } }); // add 'cat' command add("cat", "Concatenate files and print", [this, disk] (const std::vector& args) -> int { - auto& fs = disk->fs(); + auto& fs = disk->fs(); - for (const auto& file : args) - { - // get file information - auto ent = fs.stat(file); - if (!ent.is_valid()) - { - this->write("cat: '%s': No such file or directory\r\n", file.c_str()); - return 1; - } - // read file contents - auto buf = fs.read(ent, 0, ent.size); - if (!buf.buffer) - { - this->write("cat: '%s': I/O error\r\n", file.c_str()); - return 1; - } - // write to terminal client - std::string buffer((char*) buf.buffer.get(), buf.len); - this->write("%s\r\n", buffer.c_str()); - } - return 0; + for (const auto& file : args) + { + // get file information + auto ent = fs.stat(file); + if (!ent.is_valid()) + { + this->write("cat: '%s': No such file or directory\r\n", file.c_str()); + return 1; + } + // read file contents + auto buf = fs.read(ent, 0, ent.size); + if (!buf.buffer) + { + this->write("cat: '%s': I/O error\r\n", file.c_str()); + return 1; + } + // write to terminal client + std::string buffer((char*) buf.buffer.get(), buf.len); + this->write("%s\r\n", buffer.c_str()); + } + return 0; }); } diff --git a/src/kernel/vga.cpp b/src/kernel/vga.cpp index d48340b320..117f819487 100644 --- a/src/kernel/vga.cpp +++ b/src/kernel/vga.cpp @@ -25,7 +25,7 @@ static uint16_t make_vgaentry(const char c, const uint8_t color) noexcept { return c16 | color16 << 8; } const uint16_t ConsoleVGA::DEFAULT_ENTRY = - make_vgaentry(32, make_color(COLOR_LIGHT_GREY, COLOR_BLACK)); + make_vgaentry(32, make_color(COLOR_LIGHT_GREY, COLOR_BLACK)); ConsoleVGA::ConsoleVGA() noexcept: row{0}, column{0} diff --git a/src/net/buffer_store.cpp b/src/net/buffer_store.cpp index 8b575538e4..d94afe3a64 100644 --- a/src/net/buffer_store.cpp +++ b/src/net/buffer_store.cpp @@ -33,13 +33,13 @@ namespace net { assert(pool_); debug (" Creating buffer store of %i * %i bytes.\n", - num, bufsize); + num, bufsize); for (buffer_t b = pool_; b < pool_ + (num * bufsize); b += bufsize) available_buffers_.push_back(b); debug (" I now have %i free buffers in range %p -> %p.\n", - available_buffers_.size(), pool_, pool_ + (bufcount_ * bufsize_)); + available_buffers_.size(), pool_, pool_ + (bufcount_ * bufsize_)); } BufferStore::~BufferStore() { @@ -61,7 +61,7 @@ namespace net { available_buffers_.pop_front(); debug2(" Provisioned a buffer. %i buffers remaining.\n", - available_buffers_.size()); + available_buffers_.size()); return buf; } @@ -74,12 +74,12 @@ namespace net { debug2(" Trying to release %i sized buffer @%p.\n", bufsize, b); // Make sure the buffer comes from here. Otherwise, ignore it. if (address_is_from_pool(b) - and address_is_bufstart(b) - and bufsize == bufsize_) + and address_is_bufstart(b) + and bufsize == bufsize_) { - available_buffers_.push_back(b); - debug(" Releasing %p. %i available buffers.\n", b, available_buffers_.size()); - return; + available_buffers_.push_back(b); + debug(" Releasing %p. %i available buffers.\n", b, available_buffers_.size()); + return; } debug(" IGNORING buffer @%p. It isn't mine.\n", b); @@ -89,12 +89,12 @@ namespace net { debug2(" Trying to release %i + %i sized buffer @%p.\n", bufsize, device_offset_, b); // Make sure the buffer comes from here. Otherwise, ignore it. if (address_is_from_pool(b) - and address_is_offset_bufstart(b) - and bufsize == bufsize_ - device_offset_) + and address_is_offset_bufstart(b) + and bufsize == bufsize_ - device_offset_) { - available_buffers_.push_back(b - device_offset_); - debug(" Releasing %p. %i available buffers.\n", b, available_buffers_.size()); - return; + available_buffers_.push_back(b - device_offset_); + debug(" Releasing %p. %i available buffers.\n", b, available_buffers_.size()); + return; } debug(" IGNORING buffer @%p. It isn't mine.\n", b); diff --git a/src/net/dhcp/dh4client.cpp b/src/net/dhcp/dh4client.cpp index 94d5341fa8..9a7341be5a 100644 --- a/src/net/dhcp/dh4client.cpp +++ b/src/net/dhcp/dh4client.cpp @@ -220,19 +220,19 @@ namespace net socket.bcast(IP4::INADDR_ANY, DHCP_DEST_PORT, packet, packetlen); socket.onRead( - [this] (Socket& sock, IP4::addr addr, UDP::port_t port, - const char* data, int len) -> int - { - (void) addr; - if (port == DHCP_DEST_PORT) - { - // we have got a DHCP Offer - debug("Received possible DHCP OFFER from %s:%d\n", - addr.str().c_str(), DHCP_DEST_PORT); - this->offer(sock, data, len); - } - return -1; - }); + [this] (Socket& sock, IP4::addr addr, UDP::port_t port, + const char* data, int len) -> int + { + (void) addr; + if (port == DHCP_DEST_PORT) + { + // we have got a DHCP Offer + debug("Received possible DHCP OFFER from %s:%d\n", + addr.str().c_str(), DHCP_DEST_PORT); + this->offer(sock, data, len); + } + return -1; + }); } const dhcp_option_t* get_option(const uint8_t* options, uint8_t code) @@ -240,8 +240,8 @@ namespace net const dhcp_option_t* opt = (const dhcp_option_t*) options; while (opt->code != code && opt->code != DHO_END) { - // go to next option - opt = (const dhcp_option_t*) (((const uint8_t*) opt) + 2 + opt->length); + // go to next option + opt = (const dhcp_option_t*) (((const uint8_t*) opt) + 2 + opt->length); } return opt; } @@ -261,12 +261,12 @@ namespace net if (opt->code == DHO_DHCP_MESSAGE_TYPE) { - // verify that the type is indeed DHCPOFFER - debug("Found DHCP message type %d (DHCP Offer = %d)\n", - opt->val[0], DHCPOFFER); + // verify that the type is indeed DHCPOFFER + debug("Found DHCP message type %d (DHCP Offer = %d)\n", + opt->val[0], DHCPOFFER); - // ignore when not a DHCP Offer - if (opt->val[0] != DHCPOFFER) return; + // ignore when not a DHCP Offer + if (opt->val[0] != DHCPOFFER) return; } // ignore message when DHCP message type is missing else return; @@ -274,53 +274,53 @@ namespace net // the offered IP address: this->ipaddr = dhcp->yiaddr; MYINFO("IP ADDRESS: \t%s", - this->ipaddr.str().c_str()); + this->ipaddr.str().c_str()); opt = get_option(dhcp->options, DHO_SUBNET_MASK); if (opt->code == DHO_SUBNET_MASK) { - memcpy(&this->netmask, opt->val, sizeof(IP4::addr)); - MYINFO("SUBNET MASK: \t%s", - this->netmask.str().c_str()); + memcpy(&this->netmask, opt->val, sizeof(IP4::addr)); + MYINFO("SUBNET MASK: \t%s", + this->netmask.str().c_str()); } opt = get_option(dhcp->options, DHO_DHCP_LEASE_TIME); if (opt->code == DHO_DHCP_LEASE_TIME) { - memcpy(&this->lease_time, opt->val, sizeof(this->lease_time)); - MYINFO("LEASE TIME: \t%u mins", this->lease_time / 60); + memcpy(&this->lease_time, opt->val, sizeof(this->lease_time)); + MYINFO("LEASE TIME: \t%u mins", this->lease_time / 60); } // now validate the offer, checking for minimum information opt = get_option(dhcp->options, DHO_ROUTERS); if (opt->code == DHO_ROUTERS) { - memcpy(&this->router, opt->val, sizeof(IP4::addr)); - MYINFO("GATEWAY: \t%s", - this->router.str().c_str()); + memcpy(&this->router, opt->val, sizeof(IP4::addr)); + MYINFO("GATEWAY: \t%s", + this->router.str().c_str()); } // assume that the server we received the request from is the gateway else { - opt = get_option(dhcp->options, DHO_DHCP_SERVER_IDENTIFIER); - if (opt->code == DHO_DHCP_SERVER_IDENTIFIER) - { - memcpy(&this->router, opt->val, sizeof(IP4::addr)); - MYINFO("GATEWAY: \t%s", - this->router.str().c_str()); - } - // silently ignore when both ROUTER and SERVER_ID is missing - else return; + opt = get_option(dhcp->options, DHO_DHCP_SERVER_IDENTIFIER); + if (opt->code == DHO_DHCP_SERVER_IDENTIFIER) + { + memcpy(&this->router, opt->val, sizeof(IP4::addr)); + MYINFO("GATEWAY: \t%s", + this->router.str().c_str()); + } + // silently ignore when both ROUTER and SERVER_ID is missing + else return; } opt = get_option(dhcp->options, DHO_DOMAIN_NAME_SERVERS); if (opt->code == DHO_DOMAIN_NAME_SERVERS) { - memcpy(&this->dns_server, opt->val, sizeof(IP4::addr)); + memcpy(&this->dns_server, opt->val, sizeof(IP4::addr)); } else { // just try using ROUTER as DNS server - this->dns_server = this->router; + this->dns_server = this->router; } MYINFO("DNS SERVER: \t%s", this->dns_server.str().c_str()); @@ -396,19 +396,19 @@ namespace net // set our onRead function to point to a hopeful DHCP ACK! sock.onRead( - [this] (Socket&, IP4::addr addr, UDP::port_t port, - const char* data, int len) -> int - { - (void) addr; - if (port == DHCP_DEST_PORT) - { - // we have hopefully got a DHCP Ack - debug("\tReceived DHCP ACK from %s:%d\n", - addr.str().c_str(), DHCP_DEST_PORT); - this->acknowledge(data, len); - } - return -1; - }); + [this] (Socket&, IP4::addr addr, UDP::port_t port, + const char* data, int len) -> int + { + (void) addr; + if (port == DHCP_DEST_PORT) + { + // we have hopefully got a DHCP Ack + debug("\tReceived DHCP ACK from %s:%d\n", + addr.str().c_str(), DHCP_DEST_PORT); + this->acknowledge(data, len); + } + return -1; + }); // send our DHCP Request sock.bcast(IP4::INADDR_ANY, DHCP_DEST_PORT, packet, packetlen); @@ -429,12 +429,12 @@ namespace net if (opt->code == DHO_DHCP_MESSAGE_TYPE) { - // verify that the type is indeed DHCPOFFER - debug("\tFound DHCP message type %d (DHCP Ack = %d)\n", - opt->val[0], DHCPACK); + // verify that the type is indeed DHCPOFFER + debug("\tFound DHCP message type %d (DHCP Ack = %d)\n", + opt->val[0], DHCPACK); - // ignore when not a DHCP Offer - if (opt->val[0] != DHCPACK) return; + // ignore when not a DHCP Offer + if (opt->val[0] != DHCPACK) return; } // ignore message when DHCP message type is missing else return; diff --git a/src/net/dns/client.cpp b/src/net/dns/client.cpp index d17d9d570b..69951c8b8f 100644 --- a/src/net/dns/client.cpp +++ b/src/net/dns/client.cpp @@ -39,14 +39,14 @@ namespace net // wait for response // FIXME: WE DO NOT CHECK TRANSACTION IDS HERE (yet), GOD HELP US ALL sock.onRead( [this, hostname, request, func] - (Socket&, IP4::addr, UDP::port_t, const char* data, int) mutable -> int - { - // original request ID = this->id; - request.parseResponse(data); + (Socket&, IP4::addr, UDP::port_t, const char* data, int) mutable -> int + { + // original request ID = this->id; + request.parseResponse(data); - // fire onResolve event - func(this->stack, hostname, request.getFirstIP4()); - return -1; - }); + // fire onResolve event + func(this->stack, hostname, request.getFirstIP4()); + return -1; + }); } } diff --git a/src/net/dns/dns.cpp b/src/net/dns/dns.cpp index 56f28e6c0d..c8b6131b7c 100644 --- a/src/net/dns/dns.cpp +++ b/src/net/dns/dns.cpp @@ -33,10 +33,10 @@ namespace net while (*(tmp)!=0) { - int len = *tmp++; - resp.append((char*) tmp, len); - resp.append("."); - tmp += len; + int len = *tmp++; + resp.append((char*) tmp, len); + resp.append("."); + tmp += len; } return resp; } @@ -92,43 +92,43 @@ namespace net std::vector* addrs = lookup(parsed_query); if (addrs == nullptr) { - // not found - debug("*** Could not find: %s", parsed_query.c_str()); - hdr.ans_count = 0; - hdr.rcode = DNS::NO_ERROR; + // not found + debug("*** Could not find: %s", parsed_query.c_str()); + hdr.ans_count = 0; + hdr.rcode = DNS::NO_ERROR; } else { - debug("*** Found %lu results for %s", addrs->size(), parsed_query.c_str()); - // append answers - for (auto addr : *addrs) - { - debug("*** Result: %s", addr.str().c_str()); - // add query - int qlen = parsed_query.size() + 1; - memcpy(buffer, query, qlen); - buffer += qlen; - packetlen += qlen; // (!) + debug("*** Found %lu results for %s", addrs->size(), parsed_query.c_str()); + // append answers + for (auto addr : *addrs) + { + debug("*** Result: %s", addr.str().c_str()); + // add query + int qlen = parsed_query.size() + 1; + memcpy(buffer, query, qlen); + buffer += qlen; + packetlen += qlen; // (!) - // add resource record - rr_data* data = (rr_data*) buffer; + // add resource record + rr_data* data = (rr_data*) buffer; - data->type = htons(DNS_TYPE_A); - data->_class = htons(DNS_CLASS_INET); - data->ttl = htons(0x7FFF); // just because - data->data_len = htons(sizeof(IP4::addr)); - buffer += sizeof(rr_data); + data->type = htons(DNS_TYPE_A); + data->_class = htons(DNS_CLASS_INET); + data->ttl = htons(0x7FFF); // just because + data->data_len = htons(sizeof(IP4::addr)); + buffer += sizeof(rr_data); - // add resource itself - *((IP4::addr*) buffer) = addr; // IPv4 address - buffer += sizeof(IP4::addr); + // add resource itself + *((IP4::addr*) buffer) = addr; // IPv4 address + buffer += sizeof(IP4::addr); - packetlen += sizeof(rr_data) + sizeof(IP4::addr); // (!) - } // addr + packetlen += sizeof(rr_data) + sizeof(IP4::addr); // (!) + } // addr - // set dns header answer count (!) - hdr.ans_count = htons((addrs->size() & 0xFFFF)); - hdr.rcode = DNS::NO_ERROR; + // set dns header answer count (!) + hdr.ans_count = htons((addrs->size() & 0xFFFF)); + hdr.rcode = DNS::NO_ERROR; } return packetlen; } @@ -238,14 +238,14 @@ namespace net for(int i = 0; i < len; i++) { - if (copy[i] == '.') + if (copy[i] == '.') { - *dns++ = i - lock; - for(; lock < i; lock++) + *dns++ = i - lock; + for(; lock < i; lock++) { - *dns++ = copy[lock]; + *dns++ = copy[lock]; } - lock++; + lock++; } } *dns++ = '\0'; @@ -264,15 +264,15 @@ namespace net // if its an ipv4 address if (ntohs(resource.type) == DNS_TYPE_A) { - int len = ntohs(resource.data_len); + int len = ntohs(resource.data_len); - this->rdata = std::string(reader, len); - reader += len; + this->rdata = std::string(reader, len); + reader += len; } else { - this->rdata = readName(reader, buffer, stop); - reader += stop; + this->rdata = readName(reader, buffer, stop); + reader += stop; } } @@ -281,14 +281,14 @@ namespace net switch (ntohs(resource.type)) { case DNS_TYPE_A: - { - IP4::addr* addr = (IP4::addr*) rdata.c_str(); - return *addr; - } + { + IP4::addr* addr = (IP4::addr*) rdata.c_str(); + return *addr; + } case DNS_TYPE_ALIAS: case DNS_TYPE_NS: default: - return IP4::addr{{0}}; + return IP4::addr{{0}}; } } void DNS::Request::rr_t::print() @@ -297,19 +297,19 @@ namespace net switch (ntohs(resource.type)) { case DNS_TYPE_A: - { - IP4::addr* addr = (IP4::addr*) rdata.c_str(); - printf("has IPv4 address: %s", addr->str().c_str()); - } - break; + { + IP4::addr* addr = (IP4::addr*) rdata.c_str(); + printf("has IPv4 address: %s", addr->str().c_str()); + } + break; case DNS_TYPE_ALIAS: - printf("has alias: %s", rdata.c_str()); - break; + printf("has alias: %s", rdata.c_str()); + break; case DNS_TYPE_NS: - printf("has authoritative nameserver : %s", rdata.c_str()); - break; + printf("has authoritative nameserver : %s", rdata.c_str()); + break; default: - printf("has unknown resource type: %d", ntohs(resource.type)); + printf("has unknown resource type: %d", ntohs(resource.type)); } printf("\n"); } @@ -326,20 +326,20 @@ namespace net while (*ureader) { - if (*ureader >= 192) - { - offset = (*ureader) * 256 + *(ureader+1) - 49152; // = 11000000 00000000 - ureader = (unsigned char*) buffer + offset - 1; - jumped = true; // we have jumped to another location so counting wont go up! - } - else - { - name[p++] = *ureader; - } - ureader++; + if (*ureader >= 192) + { + offset = (*ureader) * 256 + *(ureader+1) - 49152; // = 11000000 00000000 + ureader = (unsigned char*) buffer + offset - 1; + jumped = true; // we have jumped to another location so counting wont go up! + } + else + { + name[p++] = *ureader; + } + ureader++; - // if we havent jumped to another location then we can count up - if (jumped == false) count++; + // if we havent jumped to another location then we can count up + if (jumped == false) count++; } name.resize(p); @@ -352,14 +352,14 @@ namespace net int i; for(i = 0; i < len; i++) { - p = name[i]; + p = name[i]; - for(unsigned j = 0; j < p; j++) - { - name[i] = name[i+1]; - i++; - } - name[i] = '.'; + for(unsigned j = 0; j < p; j++) + { + name[i] = name[i+1]; + i++; + } + name[i] = '.'; } name[i - 1] = '\0'; // remove the last dot return name; diff --git a/src/net/ethernet.cpp b/src/net/ethernet.cpp index 75af7441e2..c116fc908c 100644 --- a/src/net/ethernet.cpp +++ b/src/net/ethernet.cpp @@ -60,7 +60,7 @@ namespace net { hdr->src = mac_; debug2(" Transmitting %i b, from %s -> %s. Type: %i\n", - pckt->size(), mac_.str().c_str(), hdr->dest.str().c_str(), hdr->type); + pckt->size(), mac_.str().c_str(), hdr->dest.str().c_str(), hdr->type); physical_out_(pckt); } @@ -71,11 +71,11 @@ namespace net { header* eth = reinterpret_cast(pckt->buffer()); /** Do we pass on ethernet headers? As for now, yes. - data += sizeof(header); - len -= sizeof(header); + data += sizeof(header); + len -= sizeof(header); */ debug2(" %s => %s , Eth.type: 0x%x ", - eth->src.str().c_str(), eth->dest.str().c_str(), eth->type); + eth->src.str().c_str(), eth->dest.str().c_str(), eth->type); switch(eth->type) { case ETH_IP4: @@ -104,9 +104,9 @@ namespace net { default: // This might be 802.3 LLC traffic if (net::ntohs(eth->type) > 1500) { - debug(" UNKNOWN ethertype 0x%x\n", ntohs(eth->type)); + debug(" UNKNOWN ethertype 0x%x\n", ntohs(eth->type)); }else { - debug2("IEEE802.3 Length field: 0x%x\n", ntohs(eth->type)); + debug2("IEEE802.3 Length field: 0x%x\n", ntohs(eth->type)); } break; } diff --git a/src/net/ip4/arp.cpp b/src/net/ip4/arp.cpp index 1b0187a4b9..a502f16f6b 100644 --- a/src/net/ip4/arp.cpp +++ b/src/net/ip4/arp.cpp @@ -51,28 +51,28 @@ namespace net { case H_request: { debug2("\t ARP REQUEST: "); debug2("%s is looking for %s\n", - hdr->sipaddr.str().c_str(), - hdr->dipaddr.str().c_str()); + hdr->sipaddr.str().c_str(), + hdr->dipaddr.str().c_str()); if (hdr->dipaddr == inet_.ip_addr()) { - arp_respond(hdr); + arp_respond(hdr); } else { - debug2("\t NO MATCH for My IP (%s). DROP!\n", - inet_.ip_addr().str().c_str()); + debug2("\t NO MATCH for My IP (%s). DROP!\n", + inet_.ip_addr().str().c_str()); } break; } case H_reply: { debug2("\t ARP REPLY: %s belongs to %s\n", - hdr->sipaddr.str().c_str(), hdr->shwaddr.str().c_str()); + hdr->sipaddr.str().c_str(), hdr->shwaddr.str().c_str()); auto waiting = waiting_packets_.find(hdr->sipaddr); if (waiting != waiting_packets_.end()) { - debug("Had a packet waiting for this IP. Sending\n"); - transmit(waiting->second); - waiting_packets_.erase(waiting); + debug("Had a packet waiting for this IP. Sending\n"); + transmit(waiting->second); + waiting_packets_.erase(waiting); } break; } @@ -90,7 +90,7 @@ namespace net { if (entry != cache_.end()) { debug2("Cached entry found: %s recorded @ %llu. Updating timestamp\n", - entry->second.mac_.str().c_str(), entry->second.timestamp_); + entry->second.mac_.str().c_str(), entry->second.timestamp_); // Update entry->second.update(); @@ -105,8 +105,8 @@ namespace net { if (entry != cache_.end()) { debug("Cached entry, mac: %s time: %llu Expiry: %llu\n", - entry->second.mac_.str().c_str(), - entry->second.timestamp_, entry->second.timestamp_ + cache_exp_t_); + entry->second.mac_.str().c_str(), + entry->second.timestamp_, entry->second.timestamp_ + cache_exp_t_); debug("Time now: %llu\n", static_cast(OS::uptime())); } @@ -130,7 +130,7 @@ namespace net { res->set_opcode(H_reply); debug2("\t My IP: %s belongs to My Mac: %s\n", - res->source_ip().str().c_str(), res->source_mac().str().c_str()); + res->source_ip().str().c_str(), res->source_mac().str().c_str()); linklayer_out_(res); } @@ -140,12 +140,12 @@ namespace net { /** Get destination IP from IP header */ IP4::ip_header* iphdr = reinterpret_cast(pckt->buffer() - + sizeof(Ethernet::header)); + + sizeof(Ethernet::header)); IP4::addr sip = iphdr->saddr; IP4::addr dip = pckt->next_hop(); debug2(" physical> Transmitting %i bytes to %s\n", - pckt->size(), dip.str().c_str()); + pckt->size(), dip.str().c_str()); Ethernet::addr dest_mac; @@ -154,18 +154,18 @@ namespace net { // our own IP or 0.0.0.0 if (sip != inet_.ip_addr() && sip != IP4::INADDR_ANY) { - debug2(" Dropping outbound broadcast packet due to " - "invalid source IP %s\n", sip.str().c_str()); - return; + debug2(" Dropping outbound broadcast packet due to " + "invalid source IP %s\n", sip.str().c_str()); + return; } // mui importante dest_mac = Ethernet::addr::BROADCAST_FRAME; } else { if (sip != inet_.ip_addr()) { - debug2(" physical> Not bound to source IP %s. My IP is %s. DROP!\n", - sip.str().c_str(), inet_.ip_addr().str().c_str()); - return; + debug2(" physical> Not bound to source IP %s. My IP is %s. DROP!\n", + sip.str().c_str(), inet_.ip_addr().str().c_str()); + return; } // If we don't have a cached IP, perform address resolution diff --git a/src/net/ip4/icmpv4.cpp b/src/net/ip4/icmpv4.cpp index 3f9e897135..5c7b589dfd 100644 --- a/src/net/ip4/icmpv4.cpp +++ b/src/net/ip4/icmpv4.cpp @@ -61,7 +61,7 @@ namespace net { hdr->sequence = full_hdr->icmp_hdr.sequence; debug(" Rest of header IN: 0x%lx OUT: 0x%lx\n", - full_hdr->icmp_hdr.rest, hdr->rest); + full_hdr->icmp_hdr.rest, hdr->rest); debug(" Transmitting answer\n"); @@ -79,7 +79,7 @@ namespace net { hdr->checksum = 0; hdr->checksum = net::checksum(reinterpret_cast(hdr), - size - sizeof(full_header) + sizeof(icmp_header)); + size - sizeof(full_header) + sizeof(icmp_header)); network_layer_out_(packet_ptr); } diff --git a/src/net/ip4/ip4.cpp b/src/net/ip4/ip4.cpp index afd08e44e0..3b58782ec7 100644 --- a/src/net/ip4/ip4.cpp +++ b/src/net/ip4/ip4.cpp @@ -42,7 +42,7 @@ namespace net { ip_header* hdr = &reinterpret_cast(data)->ip_hdr; debug2("\t Source IP: %s Dest.IP: %s\n", - hdr->saddr.str().c_str(), hdr->daddr.str().c_str()); + hdr->saddr.str().c_str(), hdr->daddr.str().c_str()); switch(hdr->protocol){ case IP4_ICMP: @@ -85,18 +85,18 @@ namespace net { pckt->next_hop(target == local ? hdr->daddr : stack_.router()); debug(" Next hop for %s, (netmask %s, local IP: %s, gateway: %s) == %s\n", - hdr->daddr.str().c_str(), - stack_.netmask().str().c_str(), - stack_.ip_addr().str().c_str(), - stack_.router().str().c_str(), - target == local ? "DIRECT" : "GATEWAY"); + hdr->daddr.str().c_str(), + stack_.netmask().str().c_str(), + stack_.ip_addr().str().c_str(), + stack_.router().str().c_str(), + target == local ? "DIRECT" : "GATEWAY"); debug(" my ip: %s, Next hop: %s, Packet size: %i IP4-size: %i\n", - stack_.ip_addr().str().c_str(), - pckt->next_hop().str().c_str(), - pckt->size(), - ip4_pckt->ip4_segment_size() - ); + stack_.ip_addr().str().c_str(), + pckt->next_hop().str().c_str(), + pckt->size(), + ip4_pckt->ip4_segment_size() + ); linklayer_out_(pckt); } diff --git a/src/net/ip4/udp.cpp b/src/net/ip4/udp.cpp index 9517873299..caa4c98b19 100644 --- a/src/net/ip4/udp.cpp +++ b/src/net/ip4/udp.cpp @@ -30,13 +30,13 @@ namespace net { std::static_pointer_cast (pckt); debug("\t Source port: %i, Dest. Port: %i Length: %i\n", - udp->src_port(), udp->dst_port(), udp->length()); + udp->src_port(), udp->dst_port(), udp->length()); auto it = ports_.find(udp->dst_port()); if (it != ports_.end()) { - debug(" Someone's listening to this port. Forwarding...\n"); - it->second.internal_read(udp); + debug(" Someone's listening to this port. Forwarding...\n"); + it->second.internal_read(udp); } debug(" Nobody's listening to this port. Drop!\n"); @@ -50,9 +50,9 @@ namespace net { if (it == ports_.end()) { // create new socket auto res = ports_.emplace( - std::piecewise_construct, - std::forward_as_tuple(port), - std::forward_as_tuple(stack_, port)); + std::piecewise_construct, + std::forward_as_tuple(port), + std::forward_as_tuple(stack_, port)); it = res.first; } return it->second; @@ -73,9 +73,9 @@ namespace net { void UDP::transmit(std::shared_ptr udp) { debug2(" Transmitting %i bytes (seg=%i) from %s to %s:%i\n", - udp->length(), udp->ip4_segment_size(), - udp->src().str().c_str(), - udp->dst().str().c_str(), udp->dst_port()); + udp->length(), udp->ip4_segment_size(), + udp->src().str().c_str(), + udp->dst().str().c_str(), udp->dst_port()); assert(udp->length() >= sizeof(UDP::udp_header)); assert(udp->protocol() == IP4::IP4_UDP); diff --git a/src/net/ip4/udp_socket.cpp b/src/net/ip4/udp_socket.cpp index a5eea02023..c54ae411ae 100644 --- a/src/net/ip4/udp_socket.cpp +++ b/src/net/ip4/udp_socket.cpp @@ -29,7 +29,7 @@ namespace net } void Socket::packet_init(std::shared_ptr p, - addr srcIP, addr destIP, port port, uint16_t length) + addr srcIP, addr destIP, port port, uint16_t length) { p->init(); p->header().sport = htons(this->l_port); @@ -42,7 +42,7 @@ namespace net } int Socket::internal_write(addr srcIP, addr destIP, - port port, const uint8_t* buffer, int length) + port port, const uint8_t* buffer, int length) { // the maximum we can write per packet: const int WRITE_MAX = stack.MTU() - PacketUDP::HEADERS_SIZE; @@ -51,46 +51,46 @@ namespace net while (rem >= WRITE_MAX) { - // create some packet p (and convert it to PacketUDP) - auto p = stack.createPacket(stack.MTU()); - // fill buffer (at payload position) - memcpy(p->buffer() + PacketUDP::HEADERS_SIZE, buffer, WRITE_MAX); + // create some packet p (and convert it to PacketUDP) + auto p = stack.createPacket(stack.MTU()); + // fill buffer (at payload position) + memcpy(p->buffer() + PacketUDP::HEADERS_SIZE, buffer, WRITE_MAX); - // initialize packet with several infos - auto p2 = std::static_pointer_cast(p); - packet_init(p2, srcIP, destIP, port, WRITE_MAX); - // ship the packet - stack.udp().transmit(p2); + // initialize packet with several infos + auto p2 = std::static_pointer_cast(p); + packet_init(p2, srcIP, destIP, port, WRITE_MAX); + // ship the packet + stack.udp().transmit(p2); - // next buffer part - buffer += WRITE_MAX; rem -= WRITE_MAX; + // next buffer part + buffer += WRITE_MAX; rem -= WRITE_MAX; } if (rem) { - // copy remainder - size_t size = PacketUDP::HEADERS_SIZE + rem; + // copy remainder + size_t size = PacketUDP::HEADERS_SIZE + rem; - // create some packet p - auto p = stack.createPacket(size); - memcpy(p->buffer() + PacketUDP::HEADERS_SIZE, buffer, rem); + // create some packet p + auto p = stack.createPacket(size); + memcpy(p->buffer() + PacketUDP::HEADERS_SIZE, buffer, rem); - // initialize packet with several infos - auto p2 = std::static_pointer_cast(p); - packet_init(p2, srcIP, destIP, port, rem); - // ship the packet - stack.udp().transmit(p2); + // initialize packet with several infos + auto p2 = std::static_pointer_cast(p); + packet_init(p2, srcIP, destIP, port, rem); + // ship the packet + stack.udp().transmit(p2); } return length; } // internal_write() int Socket::sendto(addr destIP, port port, - const void* buffer, int len) + const void* buffer, int len) { return internal_write(local_addr(), destIP, port, (const uint8_t*) buffer, len); } int Socket::bcast(addr srcIP, port port, - const void* buffer, int len) + const void* buffer, int len) { return internal_write(srcIP, IP4::INADDR_BCAST, port, (const uint8_t*) buffer, len); diff --git a/src/net/ip6/icmp6.cpp b/src/net/ip6/icmp6.cpp index f36c2e18da..1ee406fcaa 100644 --- a/src/net/ip6/icmp6.cpp +++ b/src/net/ip6/icmp6.cpp @@ -45,90 +45,90 @@ namespace net { switch (type) { - /// error codes /// + /// error codes /// case 1: - /// delivery problems /// - switch (code) - { - case 0: - return "No route to destination"; - case 1: - return "Communication with dest administratively prohibited"; - case 2: - return "Beyond scope of source address"; - case 3: - return "Address unreachable"; - case 4: - return "Port unreachable"; - case 5: - return "Source address failed ingress/egress policy"; - case 6: - return "Reject route to destination"; - case 7: - return "Error in source routing header"; - default: - return "ERROR Invalid ICMP type"; - } + /// delivery problems /// + switch (code) + { + case 0: + return "No route to destination"; + case 1: + return "Communication with dest administratively prohibited"; + case 2: + return "Beyond scope of source address"; + case 3: + return "Address unreachable"; + case 4: + return "Port unreachable"; + case 5: + return "Source address failed ingress/egress policy"; + case 6: + return "Reject route to destination"; + case 7: + return "Error in source routing header"; + default: + return "ERROR Invalid ICMP type"; + } case 2: - /// size problems /// - return "Packet too big"; + /// size problems /// + return "Packet too big"; case 3: - /// time problems /// - switch (code) - { - case 0: - return "Hop limit exceeded in traffic"; - case 1: - return "Fragment reassembly time exceeded"; - default: - return "ERROR Invalid ICMP code"; - } + /// time problems /// + switch (code) + { + case 0: + return "Hop limit exceeded in traffic"; + case 1: + return "Fragment reassembly time exceeded"; + default: + return "ERROR Invalid ICMP code"; + } case 4: - /// parameter problems /// - switch (code) - { - case 0: - return "Erroneous header field"; - case 1: - return "Unrecognized next header"; - case 2: - return "Unrecognized IPv6 option"; - default: - return "ERROR Invalid ICMP code"; - } + /// parameter problems /// + switch (code) + { + case 0: + return "Erroneous header field"; + case 1: + return "Unrecognized next header"; + case 2: + return "Unrecognized IPv6 option"; + default: + return "ERROR Invalid ICMP code"; + } - /// echo feature /// + /// echo feature /// case ECHO_REQUEST: - return "Echo request"; + return "Echo request"; case ECHO_REPLY: - return "Echo reply"; + return "Echo reply"; - /// multicast feature /// + /// multicast feature /// case 130: - return "Multicast listener query"; + return "Multicast listener query"; case 131: - return "Multicast listener report"; + return "Multicast listener report"; case 132: - return "Multicast listener done"; + return "Multicast listener done"; - /// neighbor discovery protocol /// + /// neighbor discovery protocol /// case ND_ROUTER_SOL: - return "NDP Router solicitation request"; + return "NDP Router solicitation request"; case ND_ROUTER_ADV: - return "NDP Router advertisement"; + return "NDP Router advertisement"; case ND_NEIGHB_SOL: - return "NDP Neighbor solicitation request"; + return "NDP Neighbor solicitation request"; case ND_NEIGHB_ADV: - return "NDP Neighbor advertisement"; + return "NDP Neighbor advertisement"; case ND_REDIRECT: - return "NDP Redirect message"; + return "NDP Redirect message"; case 143: - return "Multicast Listener Discovery (MLDv2) reports (RFC 3810)"; + return "Multicast Listener Discovery (MLDv2) reports (RFC 3810)"; default: - return "Unknown type: " + std::to_string((int) type); + return "Unknown type: " + std::to_string((int) type); } } @@ -140,25 +140,25 @@ namespace net if (listeners.find(type) != listeners.end()) { - return listeners[type](*this, icmp); + return listeners[type](*this, icmp); } else { - debug(">>> IPv6 -> ICMPv6 bottom (no handler installed)\n"); - debug("ICMPv6 type %d: %s\n", - (int) icmp->type(), code_string(icmp->type(), icmp->code()).c_str()); + debug(">>> IPv6 -> ICMPv6 bottom (no handler installed)\n"); + debug("ICMPv6 type %d: %s\n", + (int) icmp->type(), code_string(icmp->type(), icmp->code()).c_str()); - /* - // show correct checksum - intptr_t chksum = icmp->checksum(); - debug("ICMPv6 checksum: %p \n",(void*) chksum); + /* + // show correct checksum + intptr_t chksum = icmp->checksum(); + debug("ICMPv6 checksum: %p \n",(void*) chksum); - // show our recalculated checksum - icmp->header().checksum_ = 0; - chksum = checksum(icmp); - debug("ICMPv6 our estimate: %p \n", (void*) chksum ); - */ - return -1; + // show our recalculated checksum + icmp->header().checksum_ = 0; + chksum = checksum(icmp); + debug("ICMPv6 our estimate: %p \n", (void*) chksum ); + */ + return -1; } } int ICMPv6::transmit(std::shared_ptr& pckt) @@ -244,19 +244,19 @@ namespace net if (pckt->dst().is_multicast()) { - // We won't be changing source address for multicast ping - debug("Was multicast ping6: no change for source and dest\n"); + // We won't be changing source address for multicast ping + debug("Was multicast ping6: no change for source and dest\n"); } else { - printf("Normal ping6: source is us\n"); - printf("src is %s\n", pckt->src().str().c_str()); - printf("dst is %s\n", pckt->dst().str().c_str()); + printf("Normal ping6: source is us\n"); + printf("src is %s\n", pckt->src().str().c_str()); + printf("dst is %s\n", pckt->dst().str().c_str()); - printf("multicast is %s\n", IP6::addr::link_all_nodes.str().c_str()); - // normal ping: send packet to source, from us - pckt->set_dst(pckt->src()); - pckt->set_src(caller.local_ip()); + printf("multicast is %s\n", IP6::addr::link_all_nodes.str().c_str()); + // normal ping: send packet to source, from us + pckt->set_dst(pckt->src()); + pckt->set_src(caller.local_ip()); } // calculate and set checksum // NOTE: do this after changing packet contents! @@ -288,9 +288,9 @@ namespace net // ether-broadcast an IPv6 packet to all routers // IPv6mcast_02: 33:33:00:00:00:02 auto pckt = IP6::create( - IP6::PROTO_ICMPv6, - Ethernet::addr::IPv6mcast_02, - IP6::addr::link_unspecified); + IP6::PROTO_ICMPv6, + Ethernet::addr::IPv6mcast_02, + IP6::addr::link_unspecified); // RFC4861 4.1. Router Solicitation Message Format pckt->set_hoplimit(255); diff --git a/src/net/ip6/ip6.cpp b/src/net/ip6/ip6.cpp index 8ff9de8e1d..dab269a491 100644 --- a/src/net/ip6/ip6.cpp +++ b/src/net/ip6/ip6.cpp @@ -50,25 +50,25 @@ namespace net { case PROTO_HOPOPT: case PROTO_OPTSv6: - { - debug(">>> IPv6 options header %s", protocol_name(next).c_str()); + { + debug(">>> IPv6 options header %s", protocol_name(next).c_str()); - options_header& opts = *(options_header*) reader; - reader += opts.size(); + options_header& opts = *(options_header*) reader; + reader += opts.size(); - debug("OPTSv6 size: %d\n", opts.size()); - debug("OPTSv6 ext size: %d\n", opts.extended()); + debug("OPTSv6 size: %d\n", opts.size()); + debug("OPTSv6 ext size: %d\n", opts.extended()); - next = opts.next(); - debug("OPTSv6 next: %s\n", protocol_name(next).c_str()); - } break; + next = opts.next(); + debug("OPTSv6 next: %s\n", protocol_name(next).c_str()); + } break; case PROTO_ICMPv6: - break; + break; case PROTO_UDP: - break; + break; default: - debug("Not parsing: %s\n", protocol_name(next).c_str()); + debug("Not parsing: %s\n", protocol_name(next).c_str()); } return next; @@ -93,16 +93,16 @@ namespace net while (next != PROTO_NoNext) { - auto it = proto_handlers.find(next); - if (it != proto_handlers.end()) - { - // forward packet to handler - pckt->set_payload(reader); - it->second(pckt); - } - else - // just print information - next = parse6(reader, next); + auto it = proto_handlers.find(next); + if (it != proto_handlers.end()) + { + // forward packet to handler + pckt->set_payload(reader); + it->second(pckt); + } + else + // just print information + next = parse6(reader, next); } }; @@ -118,10 +118,10 @@ namespace net for (int i = 0; i < 16; i++) { - ret[counter++] = lut[(octet[i] & 0xF0) >> 4]; - ret[counter++] = lut[(octet[i] & 0x0F) >> 0]; - if (i & 1) - ret[counter++] = ':'; + ret[counter++] = lut[(octet[i] & 0xF0) >> 4]; + ret[counter++] = lut[(octet[i] & 0x0F) >> 0]; + if (i & 1) + ret[counter++] = ':'; } ret.resize(counter-1); return ret; @@ -138,7 +138,7 @@ namespace net } std::shared_ptr IP6::create(uint8_t proto, - Ethernet::addr ether_dest, const IP6::addr& ip6_dest) + Ethernet::addr ether_dest, const IP6::addr& ip6_dest) { // arbitrarily big buffer uint8_t* data = new uint8_t[1500]; diff --git a/src/net/ip6/udp6.cpp b/src/net/ip6/udp6.cpp index 550fa7aad4..efe24fbea4 100644 --- a/src/net/ip6/udp6.cpp +++ b/src/net/ip6/udp6.cpp @@ -36,8 +36,8 @@ namespace net // check for listeners on dst port if (listeners.find(port) != listeners.end()) { - // make the call to the listener on that port - return listeners[port](P6); + // make the call to the listener on that port + return listeners[port](P6); } // was not forwarded, so just return -1 debug("... dumping packet, no listeners\n"); @@ -83,7 +83,7 @@ namespace net // normally we would start at &icmp_echo::type, but // it is after all the first element of the icmp message memcpy(data + sizeof(UDPv6::pseudo_header), this->payload(), - datalen - sizeof(UDPv6::pseudo_header)); + datalen - sizeof(UDPv6::pseudo_header)); // calculate csum and free data on return header().chksum = net::checksum(data, datalen); @@ -91,7 +91,7 @@ namespace net } std::shared_ptr UDPv6::create( - Ethernet::addr ether_dest, const IP6::addr& ip6_dest, UDPv6::port_t port) + Ethernet::addr ether_dest, const IP6::addr& ip6_dest, UDPv6::port_t port) { auto packet = IP6::create(IP6::PROTO_UDP, ether_dest, ip6_dest); auto udp_packet = view_packet_as (packet); diff --git a/src/net/tcp.cpp b/src/net/tcp.cpp index 518ac7c191..dce08a0239 100644 --- a/src/net/tcp.cpp +++ b/src/net/tcp.cpp @@ -137,7 +137,7 @@ uint16_t TCP::checksum(TCP::Packet_ptr packet) { } debug2("(packet_ptr); debug(" TCP Packet received - Source: %s, Destination: %s \n", - packet->source().to_string().c_str(), packet->destination().to_string().c_str()); + packet->source().to_string().c_str(), packet->destination().to_string().c_str()); // Do checksum if(checksum(packet)) { @@ -237,10 +237,10 @@ string TCP::status() const { TCP::Connection_ptr TCP::add_connection(Port local_port, TCP::Socket remote) { - return (connections_.emplace( - Connection::Tuple{ local_port, remote }, - std::make_shared(*this, local_port, remote)) - ).first->second; + return (connections_.emplace( + Connection::Tuple{ local_port, remote }, + std::make_shared(*this, local_port, remote)) + ).first->second; } void TCP::close_connection(TCP::Connection& conn) { diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index 154f048742..4945b43935 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -161,7 +161,7 @@ size_t Connection::send(const char* buffer, size_t remaining, size_t& packet_cou remaining -= written; debug2(" Packet Limit: %u - Written: %u - Remaining: %u - Packet count: %u\n", - packet_limit, written, remaining, packet_count); + packet_limit, written, remaining, packet_count); // If last packet, add PUSH. if(!remaining and PUSH) @@ -297,7 +297,7 @@ void Connection::transmit(TCP::Packet_ptr packet) { host_.transmit(packet); // Don't think we would like to retransmit reset packets..? //if(!packet->isset(RST)) - // add_retransmission(packet); + // add_retransmission(packet); } TCP::Seq Connection::generate_iss() { @@ -308,7 +308,7 @@ void Connection::set_state(State& state) { prev_state_ = state_; state_ = &state; debug(" %s => %s \n", - prev_state_->to_string().c_str(), state_->to_string().c_str()); + prev_state_->to_string().c_str(), state_->to_string().c_str()); } void Connection::add_retransmission(TCP::Packet_ptr packet) { @@ -317,11 +317,11 @@ void Connection::add_retransmission(TCP::Packet_ptr packet) { hw::PIT::instance().onTimeout(RTO(), [packet, self] { // Packet hasnt been ACKed. if(packet->seq() > self->tcb().SND.UNA) { - debug(" Packet unacknowledge, retransmitting...\n"); - self->transmit(packet); + debug(" Packet unacknowledge, retransmitting...\n"); + self->transmit(packet); } else { - debug2(" Packet acknowledged %s \n", packet->to_string().c_str()); - // Signal user? + debug2(" Packet acknowledged %s \n", packet->to_string().c_str()); + // Signal user? } }); } @@ -351,9 +351,9 @@ void Connection::start_time_wait_timeout() { hw::PIT::instance().onTimeout(timeout,[this, timeout] { // The timer hasnt been updated if( OS::cycles_since_boot() >= (time_wait_started + timeout.count()) ) { - signal_close(); + signal_close(); } else { - debug2(" time_wait_started has been updated. \n"); + debug2(" time_wait_started has been updated. \n"); } }); } @@ -384,7 +384,7 @@ std::string Connection::TCB::to_string() const { void Connection::parse_options(TCP::Packet_ptr packet) { assert(packet->has_options()); debug(" Parsing options. Offset: %u, Options: %u \n", - packet->offset(), packet->options_length()); + packet->offset(), packet->options_length()); auto* opt = packet->options(); @@ -406,10 +406,10 @@ void Connection::parse_options(TCP::Packet_ptr packet) { case Option::MSS: { // unlikely if(option->length != 4) - throw TCPBadOptionException{Option::MSS, "length != 4"}; + throw TCPBadOptionException{Option::MSS, "length != 4"}; // unlikely if(!packet->isset(SYN)) - throw TCPBadOptionException{Option::MSS, "Non-SYN packet"}; + throw TCPBadOptionException{Option::MSS, "Non-SYN packet"}; auto* opt_mss = (Option::opt_mss*)option; uint16_t mss = ntohs(opt_mss->mss); @@ -432,7 +432,7 @@ void Connection::add_option(TCP::Option::Kind kind, TCP::Packet_ptr packet) { case Option::MSS: { packet->add_option(host_.MSS()); debug2(" Packet: %s - MSS: %u\n", - packet->to_string().c_str(), ntohs(*(uint16_t*)(packet->options()+2))); + packet->to_string().c_str(), ntohs(*(uint16_t*)(packet->options()+2))); break; } default: diff --git a/src/net/tcp_connection_states.cpp b/src/net/tcp_connection_states.cpp index 03d0ba5a46..c7fe146ea5 100644 --- a/src/net/tcp_connection_states.cpp +++ b/src/net/tcp_connection_states.cpp @@ -108,7 +108,7 @@ bool Connection::State::check_seq(Connection& tcp, TCP::Packet_ptr in) { } // #4 else if( (tcb.RCV.NXT <= in->seq() and in->seq() < tcb.RCV.NXT + tcb.RCV.WND) - or ( tcb.RCV.NXT <= in->seq()+in->data_length()-1 and in->seq()+in->data_length()-1 < tcb.RCV.NXT+tcb.RCV.WND ) ) { + or ( tcb.RCV.NXT <= in->seq()+in->data_length()-1 and in->seq()+in->data_length()-1 < tcb.RCV.NXT+tcb.RCV.WND ) ) { acceptable = true; } /* @@ -169,7 +169,7 @@ bool Connection::State::check_seq(Connection& tcp, TCP::Packet_ptr in) { void Connection::State::unallowed_syn_reset_connection(Connection& tcp, TCP::Packet_ptr in) { assert(in->isset(SYN)); debug(" Unallowed SYN for STATE: %s, reseting connection.\n", - tcp.state().to_string().c_str()); + tcp.state().to_string().c_str()); // Not sure if this is the correct way to send a "reset response" auto packet = tcp.outgoing_packet(); packet->set_seq(in->ack()).set_flag(RST); @@ -211,22 +211,22 @@ bool Connection::State::check_ack(Connection& tcp, TCP::Packet_ptr in) { // return that buffer has been SENT - currently no support to receipt sent buffer. /* - If SND.UNA < SEG.ACK =< SND.NXT, the send window should be - updated. If (SND.WL1 < SEG.SEQ or (SND.WL1 = SEG.SEQ and - SND.WL2 =< SEG.ACK)), set SND.WND <- SEG.WND, set - SND.WL1 <- SEG.SEQ, and set SND.WL2 <- SEG.ACK. + If SND.UNA < SEG.ACK =< SND.NXT, the send window should be + updated. If (SND.WL1 < SEG.SEQ or (SND.WL1 = SEG.SEQ and + SND.WL2 =< SEG.ACK)), set SND.WND <- SEG.WND, set + SND.WL1 <- SEG.SEQ, and set SND.WL2 <- SEG.ACK. */ if( tcb.SND.WL1 < in->seq() or ( tcb.SND.WL1 = in->seq() and tcb.SND.WL2 <= in->ack() ) ) { - tcb.SND.WND = in->win(); - tcb.SND.WL1 = in->seq(); - tcb.SND.WL2 = in->ack(); + tcb.SND.WND = in->win(); + tcb.SND.WL1 = in->seq(); + tcb.SND.WL2 = in->ack(); } /* - Note that SND.WND is an offset from SND.UNA, that SND.WL1 - records the sequence number of the last segment used to update - SND.WND, and that SND.WL2 records the acknowledgment number of - the last segment used to update SND.WND. The check here - prevents using old segments to update the window. + Note that SND.WND is an offset from SND.UNA, that SND.WL1 + records the sequence number of the last segment used to update + SND.WND, and that SND.WL2 records the acknowledgment number of + the last segment used to update SND.WND. The check here + prevents using old segments to update the window. */ } /* If the ACK acks something not yet sent (SEG.ACK > SND.NXT) then send an ACK, drop the segment, and return. */ @@ -725,7 +725,7 @@ State::Result Connection::Listen::handle(Connection& tcp, TCP::Packet_ptr in) { tcb.SND.NXT = tcb.ISS+1; tcb.SND.UNA = tcb.ISS; debug(" Received SYN Packet: %s TCB Updated:\n %s \n", - in->to_string().c_str(), tcp.tcb().to_string().c_str()); + in->to_string().c_str(), tcp.tcb().to_string().c_str()); auto packet = tcp.outgoing_packet(); packet->set_seq(tcb.ISS).set_ack(tcb.RCV.NXT).set_flags(SYN | ACK); diff --git a/src/virtio/block.cpp b/src/virtio/block.cpp index 6c42fff3b7..d05bcad32a 100644 --- a/src/virtio/block.cpp +++ b/src/virtio/block.cpp @@ -30,8 +30,8 @@ VirtioBlk::VirtioBlk(hw::PCI_Device& d) : Virtio(d), - req(queue_size(0), 0, iobase()), - request_counter(0) + req(queue_size(0), 0, iobase()), + request_counter(0) { INFO("VirtioBlk", "Driver initializing"); @@ -40,30 +40,30 @@ VirtioBlk::VirtioBlk(hw::PCI_Device& d) negotiate_features(needed_features); CHECK(features() & FEAT(VIRTIO_BLK_F_BARRIER), - "Barrier is enabled"); + "Barrier is enabled"); CHECK(features() & FEAT(VIRTIO_BLK_F_SIZE_MAX), - "Size-max is known"); + "Size-max is known"); CHECK(features() & FEAT(VIRTIO_BLK_F_SEG_MAX), - "Seg-max is known"); + "Seg-max is known"); CHECK(features() & FEAT(VIRTIO_BLK_F_GEOMETRY), - "Geometry structure is used"); + "Geometry structure is used"); CHECK(features() & FEAT(VIRTIO_BLK_F_RO), - "Device is read-only"); + "Device is read-only"); CHECK(features() & FEAT(VIRTIO_BLK_F_BLK_SIZE), - "Block-size is known"); + "Block-size is known"); CHECK(features() & FEAT(VIRTIO_BLK_F_SCSI), - "SCSI is enabled :("); + "SCSI is enabled :("); CHECK(features() & FEAT(VIRTIO_BLK_F_FLUSH), - "Flush enabled"); + "Flush enabled"); CHECK ((features() & needed_features) == needed_features, - "Negotiated needed features"); + "Negotiated needed features"); // Step 1 - Initialize REQ queue auto success = assign_queue(0, (uint32_t) req.queue_desc()); CHECK(success, "Request queue assigned (0x%x) to device", - (uint32_t) req.queue_desc()); + (uint32_t) req.queue_desc()); // Step 3 - Fill receive queue with buffers // DEBUG: Disable @@ -136,7 +136,7 @@ void VirtioBlk::service_RX() while ((hdr = (request_t*) req.dequeue(len)) != nullptr) { printf("service_RX() received %u bytes for sector %llu\n", - len, hdr->hdr.sector); + len, hdr->hdr.sector); vbr = &hdr->data; printf("service_RX() received %u bytes data response\n", len); diff --git a/src/virtio/console.cpp b/src/virtio/console.cpp index 1d73459d21..8e12e5d562 100644 --- a/src/virtio/console.cpp +++ b/src/virtio/console.cpp @@ -27,10 +27,10 @@ extern "C" VirtioCon::VirtioCon(hw::PCI_Device& d) : Virtio(d), - rx(queue_size(0), 0, iobase()), - tx(queue_size(1), 1, iobase()), - ctl_rx(queue_size(2), 2, iobase()), - ctl_tx(queue_size(3), 3, iobase()) + rx(queue_size(0), 0, iobase()), + tx(queue_size(1), 1, iobase()), + ctl_rx(queue_size(2), 2, iobase()), + ctl_tx(queue_size(3), 3, iobase()) { INFO("VirtioCon", "Driver initializing"); @@ -39,31 +39,31 @@ VirtioCon::VirtioCon(hw::PCI_Device& d) negotiate_features(needed_features); CHECK(features() & FEAT(VIRTIO_CONSOLE_F_SIZE), - "Valid console dimensions"); + "Valid console dimensions"); CHECK(features() & FEAT(VIRTIO_CONSOLE_F_MULTIPORT), - "Multiple ports support"); + "Multiple ports support"); CHECK(features() & FEAT(VIRTIO_CONSOLE_F_EMERG_WRITE), - "Emergency write support"); + "Emergency write support"); CHECK ((features() & needed_features) == needed_features, - "Negotiated needed features"); + "Negotiated needed features"); // Step 1 - Initialize queues auto success = assign_queue(0, (uint32_t) rx.queue_desc()); CHECK(success, "Receive queue assigned (0x%x) to device", - (uint32_t) rx.queue_desc()); + (uint32_t) rx.queue_desc()); success = assign_queue(1, (uint32_t) tx.queue_desc()); CHECK(success, "Transmit queue assigned (0x%x) to device", - (uint32_t) tx.queue_desc()); + (uint32_t) tx.queue_desc()); success = assign_queue(2, (uint32_t) ctl_rx.queue_desc()); CHECK(success, "Control rx queue assigned (0x%x) to device", - (uint32_t) ctl_rx.queue_desc()); + (uint32_t) ctl_rx.queue_desc()); success = assign_queue(3, (uint32_t) ctl_tx.queue_desc()); CHECK(success, "Control tx queue assigned (0x%x) to device", - (uint32_t) ctl_tx.queue_desc()); + (uint32_t) ctl_tx.queue_desc()); /* success = assign_queue(4, (uint32_t) rx1.queue_desc()); @@ -143,24 +143,24 @@ void VirtioCon::service_RX() rx.dequeue(&dontcare); if (condata) - { - //printf("service_RX() received %u bytes from virtio console\n", len); - //printf("Data: %s\n", condata); - //vbr->handler(0, vbr->sector); - } + { + //printf("service_RX() received %u bytes from virtio console\n", len); + //printf("Data: %s\n", condata); + //vbr->handler(0, vbr->sector); + } else - { - // acknowledgement - //printf("No data, just len = %d\n", len); - } + { + // acknowledgement + //printf("No data, just len = %d\n", len); + } } rx.enable_interrupts(); } void VirtioCon::write ( - const void* data, - size_t len) + const void* data, + size_t len) { char* heapdata = new char[len]; memcpy(heapdata, data, len); diff --git a/src/virtio/virtio.cpp b/src/virtio/virtio.cpp index db78c0e026..28c45faa3e 100644 --- a/src/virtio/virtio.cpp +++ b/src/virtio/virtio.cpp @@ -52,8 +52,8 @@ Virtio::Virtio(hw::PCI_Device& dev) and _pcidev.product_id() <= 0x103f; CHECK(_STD_ID or _LEGACY_ID, "Device ID 0x%x is in a valid range (%s)", - _pcidev.product_id(), - _STD_ID ? ">= Virtio 1.0" : (_LEGACY_ID ? "Virtio LEGACY" : "INVALID")); + _pcidev.product_id(), + _STD_ID ? ">= Virtio 1.0" : (_LEGACY_ID ? "Virtio LEGACY" : "INVALID")); assert(_STD_ID or _LEGACY_ID); @@ -65,7 +65,7 @@ Virtio::Virtio(hw::PCI_Device& dev) CHECK(rev_id_ok and version_supported(_pcidev.rev_id()), - "Device Revision ID (0x%x) supported", _pcidev.rev_id()); + "Device Revision ID (0x%x) supported", _pcidev.rev_id()); assert(rev_id_ok); // We'll try to continue if it's newer than supported. @@ -85,9 +85,9 @@ Virtio::Virtio(hw::PCI_Device& dev) // 3. Set DRIVER status bit hw::outp(_iobase + VIRTIO_PCI_STATUS, - hw::inp(_iobase + VIRTIO_PCI_STATUS) | - VIRTIO_CONFIG_S_ACKNOWLEDGE | - VIRTIO_CONFIG_S_DRIVER); + hw::inp(_iobase + VIRTIO_PCI_STATUS) | + VIRTIO_CONFIG_S_ACKNOWLEDGE | + VIRTIO_CONFIG_S_DRIVER); // THE REMAINING STEPS MUST BE DONE IN A SUBCLASS diff --git a/src/virtio/virtionet.cpp b/src/virtio/virtionet.cpp index 89322215e9..daf305396b 100644 --- a/src/virtio/virtionet.cpp +++ b/src/virtio/virtionet.cpp @@ -57,11 +57,11 @@ VirtioNet::VirtioNet(hw::PCI_Device& d) | (1 << VIRTIO_NET_F_STATUS); //| (1 << VIRTIO_NET_F_MRG_RXBUF); //Merge RX Buffers (Everything i 1 buffer) uint32_t wanted_features = needed_features; /*; - | (1 << VIRTIO_NET_F_CSUM) - | (1 << VIRTIO_F_ANY_LAYOUT) - | (1 << VIRTIO_NET_F_CTRL_VQ) - | (1 << VIRTIO_NET_F_GUEST_ANNOUNCE) - | (1 << VIRTIO_NET_F_CTRL_MAC_ADDR);*/ + | (1 << VIRTIO_NET_F_CSUM) + | (1 << VIRTIO_F_ANY_LAYOUT) + | (1 << VIRTIO_NET_F_CTRL_VQ) + | (1 << VIRTIO_NET_F_GUEST_ANNOUNCE) + | (1 << VIRTIO_NET_F_CTRL_MAC_ADDR);*/ negotiate_features(wanted_features); @@ -79,10 +79,10 @@ VirtioNet::VirtioNet(hw::PCI_Device& d) "Guest handles packets w. partial checksum"); CHECK(features() & (1 << VIRTIO_NET_F_CTRL_VQ), - "There's a control queue"); + "There's a control queue"); CHECK(features() & (1 << VIRTIO_F_ANY_LAYOUT), - "Queue can handle any header/data layout"); + "Queue can handle any header/data layout"); CHECK(features() & (1 << VIRTIO_F_RING_INDIRECT_DESC), "We can use indirect descriptors"); @@ -218,7 +218,7 @@ void VirtioNet::irq_handler(){ void VirtioNet::service_queues(){ debug2(" %i new packets, %i available tokens \n", - rx_q.new_incoming(),rx_q.num_avail()); + rx_q.new_incoming(),rx_q.num_avail()); diff --git a/test/IDE/service.cpp b/test/IDE/service.cpp index eb8453f91c..658c5239f4 100644 --- a/test/IDE/service.cpp +++ b/test/IDE/service.cpp @@ -40,7 +40,7 @@ void Service::start() uint8_t* buf = (uint8_t*)data.get(); printf("Async read, Block %d:\n", i); for (int i = 0; i < 512; i++) - printf("%x ", buf[i]); + printf("%x ", buf[i]); printf("\n"); i++; }); @@ -54,7 +54,7 @@ void Service::start() uint8_t* buf = (uint8_t*)data.get(); printf("Async read, Block %d:\n", 4); for (int i = 0; i < 512; i++) - printf("%x ", buf[i]); + printf("%x ", buf[i]); printf("\n"); }); } diff --git a/test/STL/service.cpp b/test/STL/service.cpp index d08d5b3c3f..85b27bafe5 100644 --- a/test/STL/service.cpp +++ b/test/STL/service.cpp @@ -46,52 +46,52 @@ const lest::test specification[] = SCENARIO( "vectors can be sized and resized" "[vector]" ) { - GIVEN( "A vector with some items" ) { - std::vector v( 5 ); - - EXPECT( v.size() == 5u ); - EXPECT( v.capacity() >= 5u ); - - WHEN( "the size is increased" ) { - v.resize( 10 ); - - THEN( "the size and capacity change" ) { - EXPECT( v.size() == 10u); - EXPECT( v.capacity() >= 10u ); - } - } - WHEN( "the size is reduced" ) { - v.resize( 0 ); - - THEN( "the size changes but not capacity" ) { - EXPECT( v.size() == 0u ); - EXPECT( v.capacity() >= 5u ); - } - } - WHEN( "more capacity is reserved" ) { - v.reserve( 10 ); - - THEN( "the capacity changes but not the size" ) { - EXPECT( v.size() == 5u ); - EXPECT( v.capacity() >= 10u ); - } - WHEN( "less capacity is reserved again" ) { - v.reserve( 7 ); - - THEN( "capacity remains unchanged" ) { - EXPECT( v.capacity() >= 10u ); - } - } - } - WHEN( "less capacity is reserved" ) { - v.reserve( 0 ); - - THEN( "neither size nor capacity are changed" ) { - EXPECT( v.size() == 5u ); - EXPECT( v.capacity() >= 5u ); - } - } - } + GIVEN( "A vector with some items" ) { + std::vector v( 5 ); + + EXPECT( v.size() == 5u ); + EXPECT( v.capacity() >= 5u ); + + WHEN( "the size is increased" ) { + v.resize( 10 ); + + THEN( "the size and capacity change" ) { + EXPECT( v.size() == 10u); + EXPECT( v.capacity() >= 10u ); + } + } + WHEN( "the size is reduced" ) { + v.resize( 0 ); + + THEN( "the size changes but not capacity" ) { + EXPECT( v.size() == 0u ); + EXPECT( v.capacity() >= 5u ); + } + } + WHEN( "more capacity is reserved" ) { + v.reserve( 10 ); + + THEN( "the capacity changes but not the size" ) { + EXPECT( v.size() == 5u ); + EXPECT( v.capacity() >= 10u ); + } + WHEN( "less capacity is reserved again" ) { + v.reserve( 7 ); + + THEN( "capacity remains unchanged" ) { + EXPECT( v.capacity() >= 10u ); + } + } + } + WHEN( "less capacity is reserved" ) { + v.reserve( 0 ); + + THEN( "neither size nor capacity are changed" ) { + EXPECT( v.size() == 5u ); + EXPECT( v.capacity() >= 5u ); + } + } + } } } }; diff --git a/test/bufstore/service.cpp b/test/bufstore/service.cpp index 2643e76d7a..9b4e280945 100644 --- a/test/bufstore/service.cpp +++ b/test/bufstore/service.cpp @@ -64,7 +64,7 @@ void Service::start() // Reinitialize the first packet packet = std::make_shared(bufstore_.get_offset_buffer(), - bufstore_.offset_bufsize(), 1500, release); + bufstore_.offset_bufsize(), 1500, release); CHECKSERT(bufstore_.buffers_available() == bufcount_ - 1, "Bufcount is now %i", bufcount_ -1); @@ -84,8 +84,8 @@ void Service::start() while(tail && i < bufcount_ - 1 ) { tail = tail->detach_tail(); CHECKSERT(bufstore_.buffers_available() == i, - "Bufcount is now %i == %i", i, - bufstore_.buffers_available()); + "Bufcount is now %i == %i", i, + bufstore_.buffers_available()); i++; } diff --git a/test/fat/fat16.cpp b/test/fat/fat16.cpp index ba9d27c139..9f2d62cc6e 100644 --- a/test/fat/fat16.cpp +++ b/test/fat/fat16.cpp @@ -35,40 +35,40 @@ void Service::start() // auto-mount filesystem disk->mount( - [disk] (fs::error_t err) - { - CHECKSERT(!err, "Filesystem auto-mounted"); + [disk] (fs::error_t err) + { + CHECKSERT(!err, "Filesystem auto-mounted"); - auto& fs = disk->fs(); - printf("\t\t%s filesystem\n", fs.name().c_str()); + auto& fs = disk->fs(); + printf("\t\t%s filesystem\n", fs.name().c_str()); - auto vec = fs::new_shared_vector(); - err = fs.ls("/", vec); - CHECKSERT(!err, "List root directory"); + auto vec = fs::new_shared_vector(); + err = fs.ls("/", vec); + CHECKSERT(!err, "List root directory"); - CHECKSERT(vec->size() == 1, "Exactly one ent in root dir"); + CHECKSERT(vec->size() == 1, "Exactly one ent in root dir"); - auto& e = vec->at(0); - CHECKSERT(e.is_file(), "Ent is a file"); - CHECKSERT(e.name() == "banana.txt", "Ents name is 'banana.txt'"); + auto& e = vec->at(0); + CHECKSERT(e.is_file(), "Ent is a file"); + CHECKSERT(e.name() == "banana.txt", "Ents name is 'banana.txt'"); - }); + }); // re-mount on VBR1 disk->mount(disk->VBR1, - [disk] (fs::error_t err) - { - CHECKSERT(!err, "Filesystem mounted on VBR1"); + [disk] (fs::error_t err) + { + CHECKSERT(!err, "Filesystem mounted on VBR1"); - // verify that we can read file - auto& fs = disk->fs(); - auto ent = fs.stat("/banana.txt"); - CHECKSERT(ent.is_valid(), "Stat file in root dir"); - CHECKSERT(ent.is_file(), "Entity is file"); - CHECKSERT(!ent.is_dir(), "Entity is not directory"); - CHECKSERT(ent.name() == "banana.txt", "Name is 'banana.txt'"); + // verify that we can read file + auto& fs = disk->fs(); + auto ent = fs.stat("/banana.txt"); + CHECKSERT(ent.is_valid(), "Stat file in root dir"); + CHECKSERT(ent.is_file(), "Entity is file"); + CHECKSERT(!ent.is_dir(), "Entity is not directory"); + CHECKSERT(ent.name() == "banana.txt", "Name is 'banana.txt'"); - std::string internal_banana = -R"( ____ ___ + std::string internal_banana = + R"( ____ ___ | _ \ ___ _ _.' _ `. _ | [_) )' _ `._ _ ___ ! \ | | (_) | _ |:;.| _ <| (_) | \ | |' _ `| \| | _ | .:;| @@ -77,16 +77,16 @@ R"( ____ ___ !::, `-!_| | | |\ | | | | | \ !_!.' ':;! !::; ":;:!.!.\_!_!_!.!-'-':;:'' '''! ';:' `::;::;' '' ., . - `: .,. `' .::... . .::;::;' - `..:;::;:.. ::;::;:;:;, :;::;' + `: .,. `' .::... . .::;::;' + `..:;::;:.. ::;::;:;:;, :;::;' "-:;::;:;: ':;::;:'' ;.-' ""`---...________...---'"" -)"; + )"; printf("%s\n", internal_banana.c_str()); - // try reading banana-file - auto buf = fs.read(ent, 0, ent.size); - auto banana = buf.to_string(); + // try reading banana-file + auto buf = fs.read(ent, 0, ent.size); + auto banana = buf.to_string(); CHECKSERT(banana == internal_banana, "Correct banana #1"); diff --git a/test/fat/fat32.cpp b/test/fat/fat32.cpp index 6891eb5a84..5e00cdd05b 100644 --- a/test/fat/fat32.cpp +++ b/test/fat/fat32.cpp @@ -24,7 +24,7 @@ std::shared_ptr disk; std::string internal_banana = -R"( ____ ___ + R"( ____ ___ | _ \ ___ _ _.' _ `. _ | [_) )' _ `._ _ ___ ! \ | | (_) | _ |:;.| _ <| (_) | \ | |' _ `| \| | _ | .:;| @@ -33,11 +33,11 @@ R"( ____ ___ !::, `-!_| | | |\ | | | | | \ !_!.' ':;! !::; ":;:!.!.\_!_!_!.!-'-':;:'' '''! ';:' `::;::;' '' ., . - `: .,. `' .::... . .::;::;' - `..:;::;:.. ::;::;:;:;, :;::;' + `: .,. `' .::... . .::;::;' + `..:;::;:.. ::;::;:;:;, :;::;' "-:;::;:;: ':;::;:'' ;.-' ""`---...________...---'"" -)"; + )"; void Service::start() { diff --git a/test/memdisk/twosector.cpp b/test/memdisk/twosector.cpp index 1c2694f9c2..99e29aaf1d 100644 --- a/test/memdisk/twosector.cpp +++ b/test/memdisk/twosector.cpp @@ -53,7 +53,7 @@ void Service::start() // verify that reading outside of disk returns a 0x0 pointer buf = disk->dev().read_sync(disk->dev().size()); CHECK(!buf, "Buffer outside of disk range (sector=%llu) is 0x0", - disk->dev().size()); + disk->dev().size()); assert(!buf); INFO("MemDisk", "SUCCESS"); diff --git a/test/tcp/service.cpp b/test/tcp/service.cpp index 479626efa4..af3bbf74ac 100644 --- a/test/tcp/service.cpp +++ b/test/tcp/service.cpp @@ -63,7 +63,7 @@ void FINISH_TEST() { INFO("TEST", "Verify release of resources"); CHECK(inet->tcp().activeConnections() == 0, "tcp.activeConnections() == 0"); CHECK(inet->buffers_available() == buffers_available, - "inet->buffers_available() == buffers_available"); + "inet->buffers_available() == buffers_available"); INFO("Buffers available", "%u", inet->buffers_available()); printf("# TEST DONE #\n"); }); @@ -79,16 +79,16 @@ void OUTGOING_TEST_INTERNET(const HostAddress& address) { CHECK(ip_address != 0, "Resolved host"); if(ip_address != 0) { - inet->tcp().connect(ip_address, port) - ->onConnect([](Connection_ptr conn) { - CHECK(true, "Connected"); - conn->read(1024, [](buffer_t, size_t n) { - CHECK(n > 0, "Received data"); - }); - }) - .onError([](Connection_ptr, TCP::TCPException err) { - CHECK(false, "Error occured: %s", err.what()); - }); + inet->tcp().connect(ip_address, port) + ->onConnect([](Connection_ptr conn) { + CHECK(true, "Connected"); + conn->read(1024, [](buffer_t, size_t n) { + CHECK(n > 0, "Received data"); + }); + }) + .onError([](Connection_ptr, TCP::TCPException err) { + CHECK(false, "Error occured: %s", err.what()); + }); } }); } @@ -100,15 +100,15 @@ void OUTGOING_TEST(TCP::Socket outgoing) { INFO("TEST", "Outgoing Connection (%s)", outgoing.to_string().c_str()); inet->tcp().connect(outgoing) ->onConnect([](Connection_ptr conn) { - conn->write(small.data(), small.size()); - conn->read(small.size(), [](buffer_t buffer, size_t n) { - CHECK(std::string((char*)buffer.get(), n) == small, "conn->read() == small"); - }); + conn->write(small.data(), small.size()); + conn->read(small.size(), [](buffer_t buffer, size_t n) { + CHECK(std::string((char*)buffer.get(), n) == small, "conn->read() == small"); + }); }) .onDisconnect([](Connection_ptr, TCP::Connection::Disconnect) { - CHECK(true, "Connection closed by server"); + CHECK(true, "Connection closed by server"); - OUTGOING_TEST_INTERNET(TEST_ADDR_TIME); + OUTGOING_TEST_INTERNET(TEST_ADDR_TIME); }); } @@ -136,9 +136,9 @@ void Service::start() inet = std::make_unique>(eth0); inet->network_config( {{ 10,0,0,42 }}, // IP - {{ 255,255,255,0 }}, // Netmask - {{ 10,0,0,1 }}, // Gateway - {{ 8,8,8,8 }} ); // DNS + {{ 255,255,255,0 }}, // Netmask + {{ 10,0,0,1 }}, // Gateway + {{ 8,8,8,8 }} ); // DNS buffers_available = inet->buffers_available(); INFO("Buffers available", "%u", inet->buffers_available()); @@ -160,11 +160,11 @@ void Service::start() tcp.bind(TEST1).onConnect([](Connection_ptr conn) { INFO("TEST", "SMALL string (%u)", small.size()); conn->read(small.size(), [conn](buffer_t buffer, size_t n) { - CHECK(inet->buffers_available() < buffers_available, - "inet->buffers_available() < buffers_available"); - CHECK(std::string((char*)buffer.get(), n) == small, "conn.read() == small"); - conn->close(); - }); + CHECK(inet->buffers_available() < buffers_available, + "inet->buffers_available() < buffers_available"); + CHECK(std::string((char*)buffer.get(), n) == small, "conn.read() == small"); + conn->close(); + }); conn->write(small.data(), small.size()); INFO("Buffers available", "%u", inet->buffers_available()); }); @@ -181,13 +181,13 @@ void Service::start() INFO("TEST", "BIG string (%u)", big.size()); auto response = std::make_shared(); conn->read(big.size(), [response, conn](buffer_t buffer, size_t n) { - *response += std::string((char*)buffer.get(), n); - if(response->size() == big.size()) { - bool OK = (*response == big); - CHECK(OK, "conn.read() == big"); - conn->close(); - } - }); + *response += std::string((char*)buffer.get(), n); + if(response->size() == big.size()) { + bool OK = (*response == big); + CHECK(OK, "conn.read() == big"); + conn->close(); + } + }); conn->write(big.data(), big.size()); INFO("Buffers available", "%u", inet->buffers_available()); }); @@ -199,16 +199,16 @@ void Service::start() INFO("TEST", "HUGE string (%u)", huge.size()); auto temp = std::make_shared(huge.size()); conn->read(huge.size(), [temp, conn](buffer_t buffer, size_t n) { - memcpy(temp->data + temp->written, buffer.get(), n); - temp->written += n; - - // when all expected data is read - if(temp->written == huge.size()) { - bool OK = (temp->str() == huge); - CHECK(OK, "conn.read() == huge"); - conn->close(); - } - }); + memcpy(temp->data + temp->written, buffer.get(), n); + temp->written += n; + + // when all expected data is read + if(temp->written == huge.size()) { + bool OK = (temp->str() == huge); + CHECK(OK, "conn.read() == huge"); + conn->close(); + } + }); conn->write(huge.data(), huge.size()); INFO("Buffers available", "%u", inet->buffers_available()); }); @@ -239,14 +239,14 @@ void Service::start() CHECK(conn->is_state({"FIN-WAIT-1"}), "conn.is_state(FIN-WAIT-1)"); }) .onDisconnect([](Connection_ptr conn, TCP::Connection::Disconnect) { - CHECK(conn->is_state({"FIN-WAIT-2"}), "conn.is_state(FIN-WAIT-2)"); - hw::PIT::instance().onTimeout(1s,[conn]{ - CHECK(conn->is_state({"TIME-WAIT"}), "conn.is_state(TIME-WAIT)"); + CHECK(conn->is_state({"FIN-WAIT-2"}), "conn.is_state(FIN-WAIT-2)"); + hw::PIT::instance().onTimeout(1s,[conn]{ + CHECK(conn->is_state({"TIME-WAIT"}), "conn.is_state(TIME-WAIT)"); - OUTGOING_TEST({inet->router(), TEST5}); - }); + OUTGOING_TEST({inet->router(), TEST5}); + }); - hw::PIT::instance().onTimeout(5s, [] { FINISH_TEST(); }); + hw::PIT::instance().onTimeout(5s, [] { FINISH_TEST(); }); }); } diff --git a/test/term/term.cpp b/test/term/term.cpp index 2b5b97da83..eb4885dd6c 100644 --- a/test/term/term.cpp +++ b/test/term/term.cpp @@ -33,10 +33,10 @@ void Service::start() hw::Nic& eth0 = hw::Dev::eth<0,VirtioNet>(); inet = std::make_unique >(eth0); inet->network_config( - {{ 10,0,0,42 }}, // IP - {{ 255,255,255,0 }}, // Netmask - {{ 10,0,0,1 }}, // Gateway - {{ 8,8,8,8 }} ); // DNS + {{ 10,0,0,42 }}, // IP + {{ 255,255,255,0 }}, // Netmask + {{ 10,0,0,1 }}, // Gateway + {{ 8,8,8,8 }} ); // DNS INFO("TERM", "Running tests for Terminal"); auto disk = fs::new_shared_memdisk(); @@ -44,42 +44,42 @@ void Service::start() // auto-mount filesystem disk->mount( - [disk] (fs::error_t err) - { - CHECKSERT(!err, "Filesystem auto-mounted"); + [disk] (fs::error_t err) + { + CHECKSERT(!err, "Filesystem auto-mounted"); - /// terminal /// - #define SERVICE_TELNET 23 - auto& tcp = inet->tcp(); - auto& server = tcp.bind(SERVICE_TELNET); - server.onConnect( - [disk] (auto client) - { - // create terminal with open TCP connection - term = std::make_unique (client); - term->add_disk_commands(disk); + /// terminal /// +#define SERVICE_TELNET 23 + auto& tcp = inet->tcp(); + auto& server = tcp.bind(SERVICE_TELNET); + server.onConnect( + [disk] (auto client) + { + // create terminal with open TCP connection + term = std::make_unique (client); + term->add_disk_commands(disk); - /// work on network commands /// - // add 'ifconfig' command - term->add( - "ifconfig", "Configure a network interface", - [] (const std::vector&) -> int - { - term->write("Link encap:%s\r\n", inet->tcp().status().c_str()); - return 0; - }); - // add 'netstat' command - term->add( - "netstat", "Print network connections", - [] (const std::vector&) -> int - { - term->write("%s\r\n", inet->tcp().status().c_str()); - return 0; - }); - }); + /// work on network commands /// + // add 'ifconfig' command + term->add( + "ifconfig", "Configure a network interface", + [] (const std::vector&) -> int + { + term->write("Link encap:%s\r\n", inet->tcp().status().c_str()); + return 0; + }); + // add 'netstat' command + term->add( + "netstat", "Print network connections", + [] (const std::vector&) -> int + { + term->write("%s\r\n", inet->tcp().status().c_str()); + return 0; + }); + }); - INFO("TERM", "Connect to terminal with $ telnet %s ", - inet->ip_addr().str().c_str()); - /// terminal /// - }); + INFO("TERM", "Connect to terminal with $ telnet %s ", + inet->ip_addr().str().c_str()); + /// terminal /// + }); } diff --git a/test/timers/service.cpp b/test/timers/service.cpp index 8726f3cab8..a469b018e6 100644 --- a/test/timers/service.cpp +++ b/test/timers/service.cpp @@ -57,16 +57,16 @@ void Service::start() time.onRepeatedTimeout(1s, []{ printf("1sec. PULSE \n"); }); time.onRepeatedTimeout(2s, []{ printf("2sec. PULSE, "); }, - - // A continue-condition. The timer stops when false is returned - []{ - static int i = 0; i++; - printf("%i / 10 times \n", i); - if (i >= 10) { - printf("2sec. pulse DONE!"); - return false; - } - return true; }); + + // A continue-condition. The timer stops when false is returned + []{ + static int i = 0; i++; + printf("%i / 10 times \n", i); + if (i >= 10) { + printf("2sec. pulse DONE!"); + return false; + } + return true; }); } diff --git a/test/transmit/service.cpp b/test/transmit/service.cpp index 66c8dca086..c9cad0a578 100644 --- a/test/transmit/service.cpp +++ b/test/transmit/service.cpp @@ -48,7 +48,7 @@ void Service::start() auto& sock = inet->udp().bind(port); sock.onRead([&] (UDP::Socket& conn, UDP::addr_t addr, UDP::port_t port, - const char* data, int len) -> int { + const char* data, int len) -> int { string received = std::string(data,len-1); INFO("Test 2","Starting UDP-test (got UDP data from %s: %i: '%s')", addr.str().c_str(), port, received.c_str()); diff --git a/test/vga/vga.cpp b/test/vga/vga.cpp index 6e61dffdac..c098599bff 100644 --- a/test/vga/vga.cpp +++ b/test/vga/vga.cpp @@ -57,7 +57,7 @@ void Service::start() vga.setColor(col % 256); vga.putEntryAt(c,col % 80, row % 25); - if (col++ % 80 == 79){ + if (col++ % 80 == 79){ row++; } @@ -69,17 +69,17 @@ void Service::start() auto test1_1 = [] () -> bool { if ( c >= '4') { - hw::PIT::instance().onRepeatedTimeout(100ms, [] { - vga.newline(); - iterations++; - if (iterations == 24) - write_goodbye(); - - }, - - [] { - return iterations < 36; - }); + hw::PIT::instance().onRepeatedTimeout(100ms, [] { + vga.newline(); + iterations++; + if (iterations == 24) + write_goodbye(); + + }, + + [] { + return iterations < 36; + }); } return c < '4'; }; From 21aa82a189c7892ae0e6fc0c668a9ad3e5cc3f03 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Mon, 4 Apr 2016 10:04:18 +0200 Subject: [PATCH 100/311] Save the FAT-tests ascii art from future formatting --- test/fat/banana.ascii | 15 +++++++++++ test/fat/fat16.cpp | 58 +++++++++++++++++-------------------------- test/fat/fat32.cpp | 56 ++++++++++++++++------------------------- 3 files changed, 60 insertions(+), 69 deletions(-) create mode 100644 test/fat/banana.ascii diff --git a/test/fat/banana.ascii b/test/fat/banana.ascii new file mode 100644 index 0000000000..02f78d0cf6 --- /dev/null +++ b/test/fat/banana.ascii @@ -0,0 +1,15 @@ +const std::string internal_banana= +R"( ____ ___ + | _ \ ___ _ _.' _ `. + _ | [_) )' _ `._ _ ___ ! \ | | (_) | _ +|:;.| _ <| (_) | \ | |' _ `| \| | _ | .:;| +| `.[_) ) _ | \| | (_) | | | | |.',..| +':. `. /| | | | | _ | |\ | | |.' :;::' + !::, `-!_| | | |\ | | | | | \ !_!.' ':;! + !::; ":;:!.!.\_!_!_!.!-'-':;:'' '''! + ';:' `::;::;' '' ., . + `: .,. `' .::... . .::;::;' + `..:;::;:.. ::;::;:;:;, :;::;' + "-:;::;:;: ':;::;:'' ;.-' + ""`---...________...---'"" +)"; diff --git a/test/fat/fat16.cpp b/test/fat/fat16.cpp index 9f2d62cc6e..1e36976ccd 100644 --- a/test/fat/fat16.cpp +++ b/test/fat/fat16.cpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -21,44 +21,47 @@ #include +// Includes std::string internal_banana +#include "banana.ascii" + void Service::start() { INFO("FAT16", "Running tests for FAT16"); auto disk = fs::new_shared_memdisk(); assert(disk); - + // verify that the size is indeed N sectors CHECKSERT(disk->dev().size() == 16500, "Disk size 16500 sectors"); - + // which means that the disk can't be empty CHECKSERT(!disk->empty(), "Disk not empty"); - + // auto-mount filesystem disk->mount( [disk] (fs::error_t err) { CHECKSERT(!err, "Filesystem auto-mounted"); - + auto& fs = disk->fs(); printf("\t\t%s filesystem\n", fs.name().c_str()); - + auto vec = fs::new_shared_vector(); err = fs.ls("/", vec); CHECKSERT(!err, "List root directory"); - + CHECKSERT(vec->size() == 1, "Exactly one ent in root dir"); - + auto& e = vec->at(0); CHECKSERT(e.is_file(), "Ent is a file"); CHECKSERT(e.name() == "banana.txt", "Ents name is 'banana.txt'"); - + }); // re-mount on VBR1 disk->mount(disk->VBR1, [disk] (fs::error_t err) { CHECKSERT(!err, "Filesystem mounted on VBR1"); - + // verify that we can read file auto& fs = disk->fs(); auto ent = fs.stat("/banana.txt"); @@ -66,39 +69,24 @@ void Service::start() CHECKSERT(ent.is_file(), "Entity is file"); CHECKSERT(!ent.is_dir(), "Entity is not directory"); CHECKSERT(ent.name() == "banana.txt", "Name is 'banana.txt'"); - - std::string internal_banana = - R"( ____ ___ - | _ \ ___ _ _.' _ `. - _ | [_) )' _ `._ _ ___ ! \ | | (_) | _ -|:;.| _ <| (_) | \ | |' _ `| \| | _ | .:;| -| `.[_) ) _ | \| | (_) | | | | |.',..| -':. `. /| | | | | _ | |\ | | |.' :;::' - !::, `-!_| | | |\ | | | | | \ !_!.' ':;! - !::; ":;:!.!.\_!_!_!.!-'-':;:'' '''! - ';:' `::;::;' '' ., . - `: .,. `' .::... . .::;::;' - `..:;::;:.. ::;::;:;:;, :;::;' - "-:;::;:;: ':;::;:'' ;.-' - ""`---...________...---'"" - )"; - printf("%s\n", internal_banana.c_str()); - + + printf("%s\n", internal_banana.c_str()); + // try reading banana-file auto buf = fs.read(ent, 0, ent.size); auto banana = buf.to_string(); - + CHECKSERT(banana == internal_banana, "Correct banana #1"); - + bool test = true; - + for (size_t i = 0; i < internal_banana.size(); i++) { // read one byte at a time buf = fs.read(ent, i, 1); /// @buf should evaluate to 'true' if its valid CHECKSERT(buf, "Validate buffer"); - + // verify that it matches the same location in test-string test = ((char) buf.buffer.get()[0] == internal_banana[i]); if (!test) @@ -108,11 +96,11 @@ void Service::start() } } CHECKSERT(test, "Validate random access sync read"); - + buf = fs.readFile("/banana.txt"); banana = buf.to_string(); CHECKSERT(banana == internal_banana, "Correct banana #2"); }); - + INFO("FAT16", "SUCCESS"); } diff --git a/test/fat/fat32.cpp b/test/fat/fat32.cpp index 5e00cdd05b..65cfc76f02 100644 --- a/test/fat/fat32.cpp +++ b/test/fat/fat32.cpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -21,23 +21,11 @@ #include #include -std::shared_ptr disk; -std::string internal_banana = - R"( ____ ___ - | _ \ ___ _ _.' _ `. - _ | [_) )' _ `._ _ ___ ! \ | | (_) | _ -|:;.| _ <| (_) | \ | |' _ `| \| | _ | .:;| -| `.[_) ) _ | \| | (_) | | | | |.',..| -':. `. /| | | | | _ | |\ | | |.' :;::' - !::, `-!_| | | |\ | | | | | \ !_!.' ':;! - !::; ":;:!.!.\_!_!_!.!-'-':;:'' '''! - ';:' `::;::;' '' ., . - `: .,. `' .::... . .::;::;' - `..:;::;:.. ::;::;:;:;, :;::;' - "-:;::;:;: ':;::;:'' ;.-' - ""`---...________...---'"" - )"; +// Includes std::string internal_banana +#include "banana.ascii" + +std::shared_ptr disk; void Service::start() { @@ -45,30 +33,30 @@ void Service::start() auto& device = hw::Dev::disk<0, hw::IDE>(hw::IDE::SLAVE); disk = std::make_shared (device); assert(disk); - + // verify that the size is indeed N sectors const size_t SIZE = 4194304; printf("Size: %llu\n", disk->dev().size()); CHECKSERT(disk->dev().size() == SIZE, "Disk size 4194304 sectors"); - + // which means that the disk can't be empty CHECKSERT(!disk->empty(), "Disk not empty"); - + // auto-mount filesystem disk->mount(disk->MBR, [] (fs::error_t err) { CHECKSERT(!err, "Filesystem auto-mounted"); - + auto& fs = disk->fs(); printf("\t\t%s filesystem\n", fs.name().c_str()); - + auto vec = fs::new_shared_vector(); err = fs.ls("/", vec); CHECKSERT(!err, "List root directory"); - + CHECKSERT(vec->size() == 2, "Exactly two ents in root dir"); - + auto& e = vec->at(0); CHECKSERT(e.is_file(), "Ent is a file"); CHECKSERT(e.name() == "banana.txt", "Ents name is 'banana.txt'"); @@ -79,23 +67,23 @@ void Service::start() { CHECK(!err, "Filesystem mounted on VBR1"); assert(!err); - + auto& fs = disk->fs(); auto ent = fs.stat("/banana.txt"); CHECKSERT(ent.is_valid(), "Stat file in root dir"); CHECKSERT(ent.is_file(), "Entity is file"); CHECKSERT(!ent.is_dir(), "Entity is not directory"); CHECKSERT(ent.name() == "banana.txt", "Name is 'banana.txt'"); - + ent = fs.stat("/dir1/dir2/dir3/dir4/dir5/dir6/banana.txt"); CHECKSERT(ent.is_valid(), "Stat file in deep dir"); CHECKSERT(ent.is_file(), "Entity is file"); CHECKSERT(!ent.is_dir(), "Entity is not directory"); - + CHECKSERT(ent.name() == "banana.txt", "Name is 'banana.txt'"); - + printf("%s\n", internal_banana.c_str()); - + // asynch file reading test fs.read(ent, 0, ent.size, [&fs] (fs::error_t err, fs::buffer_t buf, uint64_t len) @@ -105,10 +93,10 @@ void Service::start() { panic("Failed to read file async"); } - + std::string banana((char*) buf.get(), len); CHECKSERT(banana == internal_banana, "Correct banana #1"); - + fs.readFile("/banana.txt", [&fs] (fs::error_t err, fs::buffer_t buf, uint64_t len) { @@ -117,12 +105,12 @@ void Service::start() { panic("Failed to read file async"); } - + std::string banana((char*) buf.get(), len); CHECKSERT(banana == internal_banana, "Correct banana #2"); }); }); }); - + INFO("FAT32", "SUCCESS"); } From c632c954d954499704f0c791205e66d88daab13a Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Mon, 4 Apr 2016 10:08:58 +0200 Subject: [PATCH 101/311] Editorconfig batch script now depends on my .emacs --- etc/batch_apply_editorconfig.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/etc/batch_apply_editorconfig.sh b/etc/batch_apply_editorconfig.sh index 22afe5d786..9c3e4a9869 100755 --- a/etc/batch_apply_editorconfig.sh +++ b/etc/batch_apply_editorconfig.sh @@ -1,5 +1,9 @@ #! /bin/bash +# NOTE: This script requires emacs, and the emacs editorconfig plugin +# It's loading the .emacs config located here: +# https://github.com/alfred-bratterud/emacs.d + SRC=$1 for file in `find $SRC \( -not -path "*/cxxabi/*" -not -path "*/STREAM/*" -not -path "*/lest/*" -not -path "*/mod/*" \) -type f \( -name *.cpp -or -name *.hpp -or -name *.inc \)` From 4cc30c39b0d5c52f6f7305d475e0db79f764c2ca Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Mon, 4 Apr 2016 19:36:35 +0200 Subject: [PATCH 102/311] make: Initial C11 support --- src/seed/Makefile | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/seed/Makefile b/src/seed/Makefile index f34c510519..8ca7a8f325 100644 --- a/src/seed/Makefile +++ b/src/seed/Makefile @@ -20,7 +20,7 @@ CAPABS_COMMON = -mstackrealign -msse3 WARNS = -Wall -Wextra #-pedantic DEBUG_OPTS = -ggdb3 -v -OPTIONS = $(WARNS) $(CAPABS) +OPTIONS = $(WARNS) $(CAPABS) $(EXTRA_FLAGS) # External Libraries ################################################### @@ -35,6 +35,7 @@ LIBCXX = $(INSTALL)/libcxx/libc++.a $(INSTALL)/libcxx/libc++abi.a INC_NEWLIB=$(INSTALL)/newlib/include INC_LIBCXX=$(INSTALL)/libcxx/include +CC = clang-3.6 -target i686-elf CPP = clang++-3.6 -target i686-elf ifndef LD_INC LD_INC = ld @@ -46,7 +47,7 @@ all: CAPABS = $(CAPABS_COMMON) -O2 debug: CAPABS = $(CAPABS_COMMON) -O0 stripped: CAPABS = $(CAPABS_COMMON) -Oz -CPPOPTS = $(CAPABS) $(WARNS) -c -m32 -std=c++14 -fno-stack-protector $(INCLUDES) -D_LIBCPP_HAS_NO_THREADS=1 #-flto -fno-exceptions +CPPOPTS = $(CAPABS) $(WARNS) -c -m32 -std=c++14 -fno-stack-protector $(INCLUDES) -D_LIBCPP_HAS_NO_THREADS=1 LDOPTS = -nostdlib -melf_i386 -N --script=$(INSTALL)/linker.ld # Objects @@ -142,6 +143,10 @@ crt%.o: $(INSTALL)/crt/crt%.s @echo "\n>> Compiling $<..." $(CPP) $(CPPOPTS) -o $@ $< +%.o: %.c + @echo "\n>> Compiling $<..." + $(CC) $(WARNS) $(CAPABS) $(EXTRA_FLAGS) -c -m32 -std=c11 -I$(INSTALL)/api/sys -I$(INC_NEWLIB) -o $@ $< + # AS-assembled object files %.o: %.s @echo "\n>> Assembling GNU 'as' files" From 7327c4ad8c1e5244de8dd6a82bd7fb136a7abe67 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Wed, 6 Apr 2016 12:08:00 +0200 Subject: [PATCH 103/311] udp: Rename Socket to UDPSocket --- api/net/dhcp/dh4client.hpp | 8 ++-- api/net/ip4/udp.hpp | 28 +++++------- api/net/ip4/udp_socket.hpp | 54 +++++++++++------------ api/net/socket.hpp | 40 ----------------- src/net/dhcp/dh4client.cpp | 54 +++++++++++------------ src/net/dns/client.cpp | 19 ++++---- src/net/ip4/udp.cpp | 10 ++--- src/net/ip4/udp_socket.cpp | 88 ++++++++++++++++++++++---------------- test/UDP/service.cpp | 29 +++++++------ 9 files changed, 149 insertions(+), 181 deletions(-) delete mode 100644 api/net/socket.hpp diff --git a/api/net/dhcp/dh4client.hpp b/api/net/dhcp/dh4client.hpp index 1047d3ec38..e538246b4d 100644 --- a/api/net/dhcp/dh4client.hpp +++ b/api/net/dhcp/dh4client.hpp @@ -26,9 +26,7 @@ namespace net { - template - class Socket; - class UDP; + class UDPSocket; template class Inet; @@ -50,8 +48,8 @@ namespace net } private: - void offer(Socket&, const char* data, int len); - void request(Socket&); // --> acknowledge + void offer(UDPSocket&, const char* data, int len); + void request(UDPSocket&); // --> acknowledge void acknowledge(const char* data, int len); uint32_t xid; diff --git a/api/net/ip4/udp.hpp b/api/net/ip4/udp.hpp index 016e40267c..3dd670b3c4 100644 --- a/api/net/ip4/udp.hpp +++ b/api/net/ip4/udp.hpp @@ -26,9 +26,7 @@ namespace net { class PacketUDP; - - template - class Socket; + class UDPSocket; void ignore_udp(Packet_ptr); @@ -36,11 +34,9 @@ namespace net { class UDP { public: using addr_t = IP4::addr; - - /** UDP port number */ using port_t = uint16_t; - - using Socket = Socket; + + using Packet_ptr = std::shared_ptr; using Stack = Inet; /** UDP header */ @@ -63,7 +59,7 @@ namespace net { { return stack_.ip_addr(); } /** Input from network layer */ - void bottom(Packet_ptr); + void bottom(net::Packet_ptr); /** Delegate output to network layer */ inline void set_network_out(downstream del) @@ -75,13 +71,13 @@ namespace net { @param sport Local port @param dip Remote IP-address @param dport Remote port */ - void transmit(std::shared_ptr udp); + void transmit(UDP::Packet_ptr udp); //! @param port local port - Socket& bind(port_t port); + UDPSocket& bind(port_t port); //! returns a new UDP socket bound to a random port - Socket& bind(); + UDPSocket& bind(); //! construct this UDP module with @inet UDP(Stack& inet) : @@ -89,12 +85,10 @@ namespace net { stack_ {inet} { } private: - downstream network_layer_out_; - Stack& stack_; - std::map ports_; - port_t current_port_ {1024}; - - friend class SocketUDP; + downstream network_layer_out_; + Stack& stack_; + std::map ports_; + port_t current_port_ {1024}; }; //< class UDP } //< namespace net diff --git a/api/net/ip4/udp_socket.hpp b/api/net/ip4/udp_socket.hpp index 7ca4ff7d26..782b6539a6 100644 --- a/api/net/ip4/udp_socket.hpp +++ b/api/net/ip4/udp_socket.hpp @@ -15,6 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#pragma once #ifndef NET_IP4_UDP_SOCKET_HPP #define NET_IP4_UDP_SOCKET_HPP #include "udp.hpp" @@ -22,71 +23,70 @@ namespace net { - template - class Socket; - - template<> - class Socket + class UDPSocket { public: - typedef UDP::port_t port; - typedef IP4::addr addr; + typedef UDP::port_t port_t; + typedef IP4::addr addr_t; typedef IP4::addr multicast_group_addr; + typedef UDP::Packet_ptr PacketUDP_ptr; - typedef delegate&, addr, port, const char*, int)> recvfrom_handler; - typedef delegate&, addr, port, const char*, int)> sendto_handler; + using Stack = Inet; + + typedef delegate recvfrom_handler; + typedef delegate sendto_handler; // constructors - Socket(Inet&, port port); - Socket(const Socket&) = delete; + UDPSocket(Stack&, port_t port); + UDPSocket(const UDPSocket&) = delete; // ^ DON'T USE THESE. We could create our own allocators just to prevent // you from creating sockets, but then everyone is wasting time. // These are public to allow us to use emplace(...). // Use Stack.udp().bind(port) to get a valid Socket reference. // functions - inline void onRead(recvfrom_handler func) + void onRead(recvfrom_handler func) { on_read = func; } - inline void onWrite(sendto_handler func) + void onWrite(sendto_handler func) { on_send = func; } - int sendto(addr destIP, port port, + int sendto(addr_t destIP, port_t port, const void* buffer, int length); - int bcast(addr srcIP, port port, + int bcast(addr_t srcIP, port_t port, const void* buffer, int length); void close(); - void join(multicast_group_addr&); - void leave(multicast_group_addr&); + void join(multicast_group_addr); + void leave(multicast_group_addr); // stuff - addr local_addr() const + addr_t local_addr() const { return stack.ip_addr(); } - port local_port() const + port_t local_port() const { return l_port; } private: - void packet_init(std::shared_ptr, addr, addr, port, uint16_t); - int internal_read(std::shared_ptr); - int internal_write(addr, addr, port, const uint8_t*, int); + void packet_init(PacketUDP_ptr, addr_t, addr_t, port_t, uint16_t); + int internal_read(PacketUDP_ptr); + int internal_write(addr_t, addr_t, port_t, const uint8_t*, int); - Inet& stack; - port l_port; - recvfrom_handler on_read = [](Socket&, addr, port, const char*, int)->int{ return 0; }; - sendto_handler on_send = [](Socket&, addr, port, const char*, int)->int{ return 0; }; + Stack& stack; + port_t l_port; + recvfrom_handler on_read = [](addr_t, port_t, const char*, int)->int{ return 0; }; + sendto_handler on_send = [](addr_t, port_t, const char*, int)->int{ return 0; }; bool reuse_addr; bool loopback; // true means multicast data is looped back to sender friend class UDP; - friend class std::allocator; + friend class std::allocator; }; } diff --git a/api/net/socket.hpp b/api/net/socket.hpp deleted file mode 100644 index 2fa655a44e..0000000000 --- a/api/net/socket.hpp +++ /dev/null @@ -1,40 +0,0 @@ -// This file is a part of the IncludeOS unikernel - www.includeos.org -// -// Copyright 2015 Oslo and Akershus University College of Applied Sciences -// and Alfred Bratterud -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include "packet.hpp" -#include -#include - -namespace net -{ - class Socket - { - // we could probably have bind() here too, - // but it needs to return the correct Socket *class* type - - int read(std::string& data); - int write(const std::string& data); - void close(); - - private: - int transmit(std::shared_ptr& pckt); - int bottom(std::shared_ptr& pckt); - - }; -} diff --git a/src/net/dhcp/dh4client.cpp b/src/net/dhcp/dh4client.cpp index 9a7341be5a..4b3a27e511 100644 --- a/src/net/dhcp/dh4client.cpp +++ b/src/net/dhcp/dh4client.cpp @@ -220,19 +220,18 @@ namespace net socket.bcast(IP4::INADDR_ANY, DHCP_DEST_PORT, packet, packetlen); socket.onRead( - [this] (Socket& sock, IP4::addr addr, UDP::port_t port, - const char* data, int len) -> int - { - (void) addr; - if (port == DHCP_DEST_PORT) - { - // we have got a DHCP Offer - debug("Received possible DHCP OFFER from %s:%d\n", - addr.str().c_str(), DHCP_DEST_PORT); - this->offer(sock, data, len); - } - return -1; - }); + [this, &socket] (IP4::addr, UDP::port_t port, + const char* data, int len) -> int + { + if (port == DHCP_DEST_PORT) + { + // we have got a DHCP Offer + debug("Received possible DHCP OFFER from %s:%d\n", + addr.str().c_str(), DHCP_DEST_PORT); + this->offer(socket, data, len); + } + return -1; + }); } const dhcp_option_t* get_option(const uint8_t* options, uint8_t code) @@ -246,7 +245,7 @@ namespace net return opt; } - void DHClient::offer(Socket& sock, const char* data, int datalen) + void DHClient::offer(UDPSocket& sock, const char* data, int datalen) { (void) datalen; const dhcp_packet_t* dhcp = (const dhcp_packet_t*) data; @@ -328,7 +327,7 @@ namespace net this->request(sock); } - void DHClient::request(Socket& sock) + void DHClient::request(UDPSocket& sock) { // form a response const size_t packetlen = sizeof(dhcp_packet_t); @@ -396,19 +395,18 @@ namespace net // set our onRead function to point to a hopeful DHCP ACK! sock.onRead( - [this] (Socket&, IP4::addr addr, UDP::port_t port, - const char* data, int len) -> int - { - (void) addr; - if (port == DHCP_DEST_PORT) - { - // we have hopefully got a DHCP Ack - debug("\tReceived DHCP ACK from %s:%d\n", - addr.str().c_str(), DHCP_DEST_PORT); - this->acknowledge(data, len); - } - return -1; - }); + [this] (IP4::addr, UDP::port_t port, + const char* data, int len) -> int + { + if (port == DHCP_DEST_PORT) + { + // we have hopefully got a DHCP Ack + debug("\tReceived DHCP ACK from %s:%d\n", + addr.str().c_str(), DHCP_DEST_PORT); + this->acknowledge(data, len); + } + return -1; + }); // send our DHCP Request sock.bcast(IP4::INADDR_ANY, DHCP_DEST_PORT, packet, packetlen); diff --git a/src/net/dns/client.cpp b/src/net/dns/client.cpp index 69951c8b8f..d5d8cdcf66 100644 --- a/src/net/dns/client.cpp +++ b/src/net/dns/client.cpp @@ -38,15 +38,16 @@ namespace net // wait for response // FIXME: WE DO NOT CHECK TRANSACTION IDS HERE (yet), GOD HELP US ALL - sock.onRead( [this, hostname, request, func] - (Socket&, IP4::addr, UDP::port_t, const char* data, int) mutable -> int - { - // original request ID = this->id; - request.parseResponse(data); + sock.onRead( + [this, hostname, request, func] + (IP4::addr, UDP::port_t, const char* data, int) mutable -> int + { + // original request ID = this->id; + request.parseResponse(data); - // fire onResolve event - func(this->stack, hostname, request.getFirstIP4()); - return -1; - }); + // fire onResolve event + func(this->stack, hostname, request.getFirstIP4()); + return -1; + }); } } diff --git a/src/net/ip4/udp.cpp b/src/net/ip4/udp.cpp index caa4c98b19..a0e5625623 100644 --- a/src/net/ip4/udp.cpp +++ b/src/net/ip4/udp.cpp @@ -23,7 +23,7 @@ namespace net { - void UDP::bottom(Packet_ptr pckt) + void UDP::bottom(net::Packet_ptr pckt) { debug(" Got data"); std::shared_ptr udp = @@ -42,7 +42,7 @@ namespace net { debug(" Nobody's listening to this port. Drop!\n"); } - UDP::Socket& UDP::bind(UDP::port_t port) + UDPSocket& UDP::bind(UDP::port_t port) { debug(" Binding to port %i\n", port); /// ... !!! @@ -58,7 +58,7 @@ namespace net { return it->second; } - UDP::Socket& UDP::bind() { + UDPSocket& UDP::bind() { if (ports_.size() >= 0xfc00) panic("UPD Socket: All ports taken!"); @@ -77,10 +77,10 @@ namespace net { udp->src().str().c_str(), udp->dst().str().c_str(), udp->dst_port()); - assert(udp->length() >= sizeof(UDP::udp_header)); + assert(udp->length() >= sizeof(udp_header)); assert(udp->protocol() == IP4::IP4_UDP); - Packet_ptr pckt = Packet::packet(udp); + auto pckt = Packet::packet(udp); network_layer_out_(pckt); } diff --git a/src/net/ip4/udp_socket.cpp b/src/net/ip4/udp_socket.cpp index c54ae411ae..35cccae303 100644 --- a/src/net/ip4/udp_socket.cpp +++ b/src/net/ip4/udp_socket.cpp @@ -20,16 +20,20 @@ namespace net { - Socket::Socket(Inet& _stack, port port) - : stack(_stack), l_port(port) {} + UDPSocket::UDPSocket(UDPSocket::Stack& stk, port_t port) + : stack(stk), l_port(port) {} - int Socket::internal_read(std::shared_ptr udp) + int UDPSocket::internal_read(UDP::Packet_ptr udp) { - return on_read(*this, udp->src(), udp->src_port(), udp->data(), udp->data_length()); + return on_read(udp->src(), udp->src_port(), udp->data(), udp->data_length()); } - void Socket::packet_init(std::shared_ptr p, - addr srcIP, addr destIP, port port, uint16_t length) + void UDPSocket::packet_init( + UDP::Packet_ptr p, + addr_t srcIP, + addr_t destIP, + port_t port, + uint16_t length) { p->init(); p->header().sport = htons(this->l_port); @@ -41,8 +45,12 @@ namespace net assert(p->data_length() == length); } - int Socket::internal_write(addr srcIP, addr destIP, - port port, const uint8_t* buffer, int length) + int UDPSocket::internal_write( + addr_t srcIP, + addr_t destIP, + port_t port, + const uint8_t* buffer, + int length) { // the maximum we can write per packet: const int WRITE_MAX = stack.MTU() - PacketUDP::HEADERS_SIZE; @@ -50,47 +58,53 @@ namespace net int rem = length; while (rem >= WRITE_MAX) - { - // create some packet p (and convert it to PacketUDP) - auto p = stack.createPacket(stack.MTU()); - // fill buffer (at payload position) - memcpy(p->buffer() + PacketUDP::HEADERS_SIZE, buffer, WRITE_MAX); + { + // create some packet p (and convert it to PacketUDP) + auto p = stack.createPacket(stack.MTU()); + // fill buffer (at payload position) + memcpy(p->buffer() + PacketUDP::HEADERS_SIZE, buffer, WRITE_MAX); - // initialize packet with several infos - auto p2 = std::static_pointer_cast(p); - packet_init(p2, srcIP, destIP, port, WRITE_MAX); - // ship the packet - stack.udp().transmit(p2); + // initialize packet with several infos + auto p2 = std::static_pointer_cast(p); + packet_init(p2, srcIP, destIP, port, WRITE_MAX); + // ship the packet + stack.udp().transmit(p2); - // next buffer part - buffer += WRITE_MAX; rem -= WRITE_MAX; - } + // next buffer part + buffer += WRITE_MAX; rem -= WRITE_MAX; + } if (rem) - { - // copy remainder - size_t size = PacketUDP::HEADERS_SIZE + rem; + { + // copy remainder + size_t size = PacketUDP::HEADERS_SIZE + rem; - // create some packet p - auto p = stack.createPacket(size); - memcpy(p->buffer() + PacketUDP::HEADERS_SIZE, buffer, rem); + // create some packet p + auto p = stack.createPacket(size); + memcpy(p->buffer() + PacketUDP::HEADERS_SIZE, buffer, rem); - // initialize packet with several infos - auto p2 = std::static_pointer_cast(p); - packet_init(p2, srcIP, destIP, port, rem); - // ship the packet - stack.udp().transmit(p2); - } + // initialize packet with several infos + auto p2 = std::static_pointer_cast(p); + packet_init(p2, srcIP, destIP, port, rem); + // ship the packet + stack.udp().transmit(p2); + } return length; } // internal_write() - int Socket::sendto(addr destIP, port port, - const void* buffer, int len) + int UDPSocket::sendto( + addr_t destIP, + port_t port, + const void* buffer, + int len) { return internal_write(local_addr(), destIP, port, (const uint8_t*) buffer, len); } - int Socket::bcast(addr srcIP, port port, - const void* buffer, int len) + int UDPSocket::bcast( + addr_t srcIP, + port_t port, + const void* buffer, + int len) { return internal_write(srcIP, IP4::INADDR_BCAST, port, (const uint8_t*) buffer, len); diff --git a/test/UDP/service.cpp b/test/UDP/service.cpp index a4c9ae1480..1d3f6ec59f 100644 --- a/test/UDP/service.cpp +++ b/test/UDP/service.cpp @@ -34,7 +34,7 @@ void Service::start() auto& mac = eth0.mac(); auto& inet = *new net::Inet4(eth0, // Device - {{ mac.part[2],mac.part[3],mac.part[4],mac.part[5] }}, // IP + {{ 10,0,0,42 }}, // IP {{ 255,255,0,0 }} ); // Netmask printf("Service IP address: %s \n", inet.ip_addr().str().c_str()); @@ -43,16 +43,19 @@ void Service::start() UDP::port_t port = 4242; auto& sock = inet.udp().bind(port); - sock.onRead([] (UDP::Socket& conn, UDP::addr_t addr, UDP::port_t port, - const char* data, int len) -> int - { - CHECK(1,"Getting UDP data from %s: %i: %s", - addr.str().c_str(), port, data); - // send the same thing right back! - conn.sendto(addr, port, data, len); - return 0; - }); - - INFO("UDP test", "listening to %i \n",port); - + sock.onRead( + [&sock] (UDP::addr_t addr, UDP::port_t port, + const char* data, int len) -> int + { + std::string strdata(data, len); + CHECK(1, "Getting UDP data from %s: %d -> %s", + addr.str().c_str(), port, strdata.c_str()); + // send the same thing right back! + sock.sendto(addr, port, data, len); + + INFO("UDP test", "SUCCESS"); + return 0; + }); + + INFO("UDP test", "Listening on port %d\n", port); } From 7993769e458d13007736dcb8e10282dc4b494b17 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Wed, 6 Apr 2016 13:34:45 +0200 Subject: [PATCH 104/311] udp: Remove return value in callbacks, use size_t --- api/net/dhcp/dh4client.hpp | 14 +++++--------- api/net/ip4/udp_socket.hpp | 25 +++++++++++++------------ src/net/dhcp/dh4client.cpp | 34 +++++++++++++++------------------- src/net/dns/client.cpp | 7 +++---- src/net/ip4/udp_socket.cpp | 34 +++++++++++++++++----------------- test/UDP/service.cpp | 13 +++++-------- 6 files changed, 58 insertions(+), 69 deletions(-) diff --git a/api/net/dhcp/dh4client.hpp b/api/net/dhcp/dh4client.hpp index e538246b4d..c55bfa3b5f 100644 --- a/api/net/dhcp/dh4client.hpp +++ b/api/net/dhcp/dh4client.hpp @@ -15,13 +15,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +#pragma once #ifndef NET_DHCP_DH4CLIENT_HPP #define NET_DHCP_DH4CLIENT_HPP -#define DEBUG #include "../packet.hpp" - -#include #include namespace net @@ -39,7 +37,8 @@ namespace net DHClient() = delete; DHClient(DHClient&) = delete; - DHClient(Stack&); + DHClient(Stack& inet) + : stack(inet) {} Stack& stack; void negotiate(); // --> offer @@ -48,18 +47,15 @@ namespace net } private: - void offer(UDPSocket&, const char* data, int len); + void offer(UDPSocket&, const char* data, size_t len); void request(UDPSocket&); // --> acknowledge - void acknowledge(const char* data, int len); + void acknowledge(const char* data, size_t len); uint32_t xid; IP4::addr ipaddr, netmask, router, dns_server; uint32_t lease_time; On_config config_handler = [](Stack&){ INFO("DHCPv4::On_config","Config complete"); }; }; - - inline DHClient::DHClient(Stack& inet) - : stack(inet) {} } #endif diff --git a/api/net/ip4/udp_socket.hpp b/api/net/ip4/udp_socket.hpp index 782b6539a6..e5193d31b4 100644 --- a/api/net/ip4/udp_socket.hpp +++ b/api/net/ip4/udp_socket.hpp @@ -29,12 +29,11 @@ namespace net typedef UDP::port_t port_t; typedef IP4::addr addr_t; typedef IP4::addr multicast_group_addr; - typedef UDP::Packet_ptr PacketUDP_ptr; using Stack = Inet; - typedef delegate recvfrom_handler; - typedef delegate sendto_handler; + typedef delegate recvfrom_handler; + typedef delegate sendto_handler; // constructors UDPSocket(Stack&, port_t port); @@ -53,10 +52,10 @@ namespace net { on_send = func; } - int sendto(addr_t destIP, port_t port, - const void* buffer, int length); - int bcast(addr_t srcIP, port_t port, - const void* buffer, int length); + void sendto(addr_t destIP, port_t port, + const void* buffer, size_t length); + void bcast(addr_t srcIP, port_t port, + const void* buffer, size_t length); void close(); void join(multicast_group_addr); @@ -73,14 +72,16 @@ namespace net } private: - void packet_init(PacketUDP_ptr, addr_t, addr_t, port_t, uint16_t); - int internal_read(PacketUDP_ptr); - int internal_write(addr_t, addr_t, port_t, const uint8_t*, int); + void packet_init(UDP::Packet_ptr, addr_t, addr_t, port_t, uint16_t); + void internal_read(UDP::Packet_ptr); + void internal_write(addr_t, addr_t, port_t, const uint8_t*, size_t); Stack& stack; port_t l_port; - recvfrom_handler on_read = [](addr_t, port_t, const char*, int)->int{ return 0; }; - sendto_handler on_send = [](addr_t, port_t, const char*, int)->int{ return 0; }; + recvfrom_handler on_read = + [](addr_t, port_t, const char*, size_t) {}; + sendto_handler on_send = + [](addr_t, port_t, const char*, size_t) {}; bool reuse_addr; bool loopback; // true means multicast data is looped back to sender diff --git a/src/net/dhcp/dh4client.cpp b/src/net/dhcp/dh4client.cpp index 4b3a27e511..06fd1c713e 100644 --- a/src/net/dhcp/dh4client.cpp +++ b/src/net/dhcp/dh4client.cpp @@ -221,7 +221,7 @@ namespace net socket.onRead( [this, &socket] (IP4::addr, UDP::port_t port, - const char* data, int len) -> int + const char* data, size_t len) { if (port == DHCP_DEST_PORT) { @@ -230,7 +230,6 @@ namespace net addr.str().c_str(), DHCP_DEST_PORT); this->offer(socket, data, len); } - return -1; }); } @@ -238,16 +237,15 @@ namespace net { const dhcp_option_t* opt = (const dhcp_option_t*) options; while (opt->code != code && opt->code != DHO_END) - { - // go to next option - opt = (const dhcp_option_t*) (((const uint8_t*) opt) + 2 + opt->length); - } + { + // go to next option + opt = (const dhcp_option_t*) (((const uint8_t*) opt) + 2 + opt->length); + } return opt; } - void DHClient::offer(UDPSocket& sock, const char* data, int datalen) + void DHClient::offer(UDPSocket& sock, const char* data, size_t) { - (void) datalen; const dhcp_packet_t* dhcp = (const dhcp_packet_t*) data; uint32_t xid = htonl(dhcp->xid); @@ -396,7 +394,7 @@ namespace net // set our onRead function to point to a hopeful DHCP ACK! sock.onRead( [this] (IP4::addr, UDP::port_t port, - const char* data, int len) -> int + const char* data, size_t len) { if (port == DHCP_DEST_PORT) { @@ -405,16 +403,14 @@ namespace net addr.str().c_str(), DHCP_DEST_PORT); this->acknowledge(data, len); } - return -1; }); // send our DHCP Request sock.bcast(IP4::INADDR_ANY, DHCP_DEST_PORT, packet, packetlen); } - void DHClient::acknowledge(const char* data, int datalen) + void DHClient::acknowledge(const char* data, size_t) { - (void) datalen; const dhcp_packet_t* dhcp = (const dhcp_packet_t*) data; uint32_t xid = htonl(dhcp->xid); @@ -426,14 +422,14 @@ namespace net opt = get_option(dhcp->options, DHO_DHCP_MESSAGE_TYPE); if (opt->code == DHO_DHCP_MESSAGE_TYPE) - { - // verify that the type is indeed DHCPOFFER - debug("\tFound DHCP message type %d (DHCP Ack = %d)\n", - opt->val[0], DHCPACK); + { + // verify that the type is indeed DHCPOFFER + debug("\tFound DHCP message type %d (DHCP Ack = %d)\n", + opt->val[0], DHCPACK); - // ignore when not a DHCP Offer - if (opt->val[0] != DHCPACK) return; - } + // ignore when not a DHCP Offer + if (opt->val[0] != DHCPACK) return; + } // ignore message when DHCP message type is missing else return; diff --git a/src/net/dns/client.cpp b/src/net/dns/client.cpp index d5d8cdcf66..44931c689c 100644 --- a/src/net/dns/client.cpp +++ b/src/net/dns/client.cpp @@ -29,8 +29,8 @@ namespace net // create DNS request DNS::Request request; - char* data = new char[256]; - int len = request.create(data, hostname); + char* data = new char[256]; + size_t len = request.create(data, hostname); // send request to DNS server sock.sendto(dns_server, DNS::DNS_SERVICE_PORT, data, len); @@ -40,14 +40,13 @@ namespace net // FIXME: WE DO NOT CHECK TRANSACTION IDS HERE (yet), GOD HELP US ALL sock.onRead( [this, hostname, request, func] - (IP4::addr, UDP::port_t, const char* data, int) mutable -> int + (IP4::addr, UDP::port_t, const char* data, size_t) mutable { // original request ID = this->id; request.parseResponse(data); // fire onResolve event func(this->stack, hostname, request.getFirstIP4()); - return -1; }); } } diff --git a/src/net/ip4/udp_socket.cpp b/src/net/ip4/udp_socket.cpp index 35cccae303..2bf3a5407b 100644 --- a/src/net/ip4/udp_socket.cpp +++ b/src/net/ip4/udp_socket.cpp @@ -21,12 +21,8 @@ namespace net { UDPSocket::UDPSocket(UDPSocket::Stack& stk, port_t port) - : stack(stk), l_port(port) {} - - int UDPSocket::internal_read(UDP::Packet_ptr udp) - { - return on_read(udp->src(), udp->src_port(), udp->data(), udp->data_length()); - } + : stack(stk), l_port(port) + {} void UDPSocket::packet_init( UDP::Packet_ptr p, @@ -45,12 +41,17 @@ namespace net assert(p->data_length() == length); } - int UDPSocket::internal_write( + void UDPSocket::internal_read(UDP::Packet_ptr udp) + { + on_read(udp->src(), udp->src_port(), udp->data(), udp->data_length()); + } + + void UDPSocket::internal_write( addr_t srcIP, addr_t destIP, port_t port, const uint8_t* buffer, - int length) + size_t length) { // the maximum we can write per packet: const int WRITE_MAX = stack.MTU() - PacketUDP::HEADERS_SIZE; @@ -88,26 +89,25 @@ namespace net // ship the packet stack.udp().transmit(p2); } - return length; } // internal_write() - int UDPSocket::sendto( + void UDPSocket::sendto( addr_t destIP, port_t port, const void* buffer, - int len) + size_t len) { - return internal_write(local_addr(), destIP, port, - (const uint8_t*) buffer, len); + internal_write(local_addr(), destIP, port, + (const uint8_t*) buffer, len); } - int UDPSocket::bcast( + void UDPSocket::bcast( addr_t srcIP, port_t port, const void* buffer, - int len) + size_t len) { - return internal_write(srcIP, IP4::INADDR_BCAST, port, - (const uint8_t*) buffer, len); + internal_write(srcIP, IP4::INADDR_BCAST, port, + (const uint8_t*) buffer, len); } } diff --git a/test/UDP/service.cpp b/test/UDP/service.cpp index 1d3f6ec59f..217dc0aa81 100644 --- a/test/UDP/service.cpp +++ b/test/UDP/service.cpp @@ -31,21 +31,19 @@ void Service::start() { // Assign an IP-address, using Hårek-mapping :-) auto& eth0 = hw::Dev::eth<0,VirtioNet>(); - auto& mac = eth0.mac(); - auto& inet = *new net::Inet4(eth0, // Device {{ 10,0,0,42 }}, // IP {{ 255,255,0,0 }} ); // Netmask - printf("Service IP address: %s \n", inet.ip_addr().str().c_str()); - + printf("Service IP address is %s\n", inet.ip_addr().str().c_str()); + // UDP UDP::port_t port = 4242; auto& sock = inet.udp().bind(port); - + sock.onRead( [&sock] (UDP::addr_t addr, UDP::port_t port, - const char* data, int len) -> int + const char* data, size_t len) { std::string strdata(data, len); CHECK(1, "Getting UDP data from %s: %d -> %s", @@ -54,8 +52,7 @@ void Service::start() sock.sendto(addr, port, data, len); INFO("UDP test", "SUCCESS"); - return 0; - }); + }); INFO("UDP test", "Listening on port %d\n", port); } From 2f1482b08ccab4ebfe0d9179c997e303f99f6ad3 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Thu, 7 Apr 2016 10:42:07 +0200 Subject: [PATCH 105/311] udp: Add write callback, rename onRead to on_read --- api/net/ip4/udp_socket.hpp | 25 ++++++------- src/net/dhcp/dh4client.cpp | 74 +++++++++++++++++++------------------- src/net/dns/client.cpp | 2 +- src/net/ip4/udp_socket.cpp | 20 ++++++----- test/UDP/service.cpp | 7 ++-- 5 files changed, 65 insertions(+), 63 deletions(-) diff --git a/api/net/ip4/udp_socket.hpp b/api/net/ip4/udp_socket.hpp index e5193d31b4..87e18deb11 100644 --- a/api/net/ip4/udp_socket.hpp +++ b/api/net/ip4/udp_socket.hpp @@ -33,7 +33,7 @@ namespace net using Stack = Inet; typedef delegate recvfrom_handler; - typedef delegate sendto_handler; + typedef delegate sendto_handler; // constructors UDPSocket(Stack&, port_t port); @@ -44,18 +44,16 @@ namespace net // Use Stack.udp().bind(port) to get a valid Socket reference. // functions - void onRead(recvfrom_handler func) + void on_read(recvfrom_handler callback) { - on_read = func; - } - void onWrite(sendto_handler func) - { - on_send = func; + on_read_handler = callback; } void sendto(addr_t destIP, port_t port, - const void* buffer, size_t length); + const void* buffer, size_t length, + sendto_handler cb = [] {}); void bcast(addr_t srcIP, port_t port, - const void* buffer, size_t length); + const void* buffer, size_t length, + sendto_handler cb = [] {}); void close(); void join(multicast_group_addr); @@ -74,14 +72,13 @@ namespace net private: void packet_init(UDP::Packet_ptr, addr_t, addr_t, port_t, uint16_t); void internal_read(UDP::Packet_ptr); - void internal_write(addr_t, addr_t, port_t, const uint8_t*, size_t); + void internal_write( + addr_t, addr_t, port_t, const uint8_t*, size_t, sendto_handler); Stack& stack; port_t l_port; - recvfrom_handler on_read = - [](addr_t, port_t, const char*, size_t) {}; - sendto_handler on_send = - [](addr_t, port_t, const char*, size_t) {}; + recvfrom_handler on_read_handler = + [] (addr_t, port_t, const char*, size_t) {}; bool reuse_addr; bool loopback; // true means multicast data is looped back to sender diff --git a/src/net/dhcp/dh4client.cpp b/src/net/dhcp/dh4client.cpp index 06fd1c713e..948f21ee7b 100644 --- a/src/net/dhcp/dh4client.cpp +++ b/src/net/dhcp/dh4client.cpp @@ -219,7 +219,7 @@ namespace net /// broadcast our DHCP plea as 0.0.0.0:67 socket.bcast(IP4::INADDR_ANY, DHCP_DEST_PORT, packet, packetlen); - socket.onRead( + socket.on_read( [this, &socket] (IP4::addr, UDP::port_t port, const char* data, size_t len) { @@ -257,14 +257,14 @@ namespace net opt = get_option(dhcp->options, DHO_DHCP_MESSAGE_TYPE); if (opt->code == DHO_DHCP_MESSAGE_TYPE) - { - // verify that the type is indeed DHCPOFFER - debug("Found DHCP message type %d (DHCP Offer = %d)\n", - opt->val[0], DHCPOFFER); + { + // verify that the type is indeed DHCPOFFER + debug("Found DHCP message type %d (DHCP Offer = %d)\n", + opt->val[0], DHCPOFFER); - // ignore when not a DHCP Offer - if (opt->val[0] != DHCPOFFER) return; - } + // ignore when not a DHCP Offer + if (opt->val[0] != DHCPOFFER) return; + } // ignore message when DHCP message type is missing else return; @@ -275,50 +275,50 @@ namespace net opt = get_option(dhcp->options, DHO_SUBNET_MASK); if (opt->code == DHO_SUBNET_MASK) - { - memcpy(&this->netmask, opt->val, sizeof(IP4::addr)); - MYINFO("SUBNET MASK: \t%s", - this->netmask.str().c_str()); - } + { + memcpy(&this->netmask, opt->val, sizeof(IP4::addr)); + MYINFO("SUBNET MASK: \t%s", + this->netmask.str().c_str()); + } opt = get_option(dhcp->options, DHO_DHCP_LEASE_TIME); if (opt->code == DHO_DHCP_LEASE_TIME) - { - memcpy(&this->lease_time, opt->val, sizeof(this->lease_time)); - MYINFO("LEASE TIME: \t%u mins", this->lease_time / 60); - } + { + memcpy(&this->lease_time, opt->val, sizeof(this->lease_time)); + MYINFO("LEASE TIME: \t%u mins", this->lease_time / 60); + } // now validate the offer, checking for minimum information opt = get_option(dhcp->options, DHO_ROUTERS); if (opt->code == DHO_ROUTERS) + { + memcpy(&this->router, opt->val, sizeof(IP4::addr)); + MYINFO("GATEWAY: \t%s", + this->router.str().c_str()); + } + // assume that the server we received the request from is the gateway + else + { + opt = get_option(dhcp->options, DHO_DHCP_SERVER_IDENTIFIER); + if (opt->code == DHO_DHCP_SERVER_IDENTIFIER) { memcpy(&this->router, opt->val, sizeof(IP4::addr)); MYINFO("GATEWAY: \t%s", this->router.str().c_str()); } - // assume that the server we received the request from is the gateway - else - { - opt = get_option(dhcp->options, DHO_DHCP_SERVER_IDENTIFIER); - if (opt->code == DHO_DHCP_SERVER_IDENTIFIER) - { - memcpy(&this->router, opt->val, sizeof(IP4::addr)); - MYINFO("GATEWAY: \t%s", - this->router.str().c_str()); - } - // silently ignore when both ROUTER and SERVER_ID is missing - else return; - } + // silently ignore when both ROUTER and SERVER_ID is missing + else return; + } opt = get_option(dhcp->options, DHO_DOMAIN_NAME_SERVERS); if (opt->code == DHO_DOMAIN_NAME_SERVERS) - { - memcpy(&this->dns_server, opt->val, sizeof(IP4::addr)); - } + { + memcpy(&this->dns_server, opt->val, sizeof(IP4::addr)); + } else - { // just try using ROUTER as DNS server - this->dns_server = this->router; - } + { // just try using ROUTER as DNS server + this->dns_server = this->router; + } MYINFO("DNS SERVER: \t%s", this->dns_server.str().c_str()); // we can accept the offer now by requesting the IP! @@ -392,7 +392,7 @@ namespace net opt->length = 0; // set our onRead function to point to a hopeful DHCP ACK! - sock.onRead( + sock.on_read( [this] (IP4::addr, UDP::port_t port, const char* data, size_t len) { diff --git a/src/net/dns/client.cpp b/src/net/dns/client.cpp index 44931c689c..68ddfc3284 100644 --- a/src/net/dns/client.cpp +++ b/src/net/dns/client.cpp @@ -38,7 +38,7 @@ namespace net // wait for response // FIXME: WE DO NOT CHECK TRANSACTION IDS HERE (yet), GOD HELP US ALL - sock.onRead( + sock.on_read( [this, hostname, request, func] (IP4::addr, UDP::port_t, const char* data, size_t) mutable { diff --git a/src/net/ip4/udp_socket.cpp b/src/net/ip4/udp_socket.cpp index 2bf3a5407b..a544e6bf94 100644 --- a/src/net/ip4/udp_socket.cpp +++ b/src/net/ip4/udp_socket.cpp @@ -43,7 +43,8 @@ namespace net void UDPSocket::internal_read(UDP::Packet_ptr udp) { - on_read(udp->src(), udp->src_port(), udp->data(), udp->data_length()); + on_read_handler + (udp->src(), udp->src_port(), udp->data(), udp->data_length()); } void UDPSocket::internal_write( @@ -51,12 +52,13 @@ namespace net addr_t destIP, port_t port, const uint8_t* buffer, - size_t length) + size_t length, + sendto_handler cb) { // the maximum we can write per packet: - const int WRITE_MAX = stack.MTU() - PacketUDP::HEADERS_SIZE; + const size_t WRITE_MAX = stack.MTU() - PacketUDP::HEADERS_SIZE; // the bytes remaining to be written - int rem = length; + size_t rem = length; while (rem >= WRITE_MAX) { @@ -95,19 +97,21 @@ namespace net addr_t destIP, port_t port, const void* buffer, - size_t len) + size_t len, + sendto_handler cb) { internal_write(local_addr(), destIP, port, - (const uint8_t*) buffer, len); + (const uint8_t*) buffer, len, cb); } void UDPSocket::bcast( addr_t srcIP, port_t port, const void* buffer, - size_t len) + size_t len, + sendto_handler cb) { internal_write(srcIP, IP4::INADDR_BCAST, port, - (const uint8_t*) buffer, len); + (const uint8_t*) buffer, len, cb); } } diff --git a/test/UDP/service.cpp b/test/UDP/service.cpp index 217dc0aa81..2489118669 100644 --- a/test/UDP/service.cpp +++ b/test/UDP/service.cpp @@ -49,10 +49,11 @@ void Service::start() CHECK(1, "Getting UDP data from %s: %d -> %s", addr.str().c_str(), port, strdata.c_str()); // send the same thing right back! - sock.sendto(addr, port, data, len); - - INFO("UDP test", "SUCCESS"); + sock.sendto(addr, port, data, len, + [] { + INFO("UDP test", "SUCCESS"); }); + }); INFO("UDP test", "Listening on port %d\n", port); } From f4ab023194416662cafc417676750ae46f83202d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Thu, 7 Apr 2016 14:52:00 +0200 Subject: [PATCH 106/311] tcp: is now using Window property (still buggy) --- api/net/tcp.hpp | 47 ++++++++++++++++++++++++++-- src/net/tcp.cpp | 20 ++++++++++-- src/net/tcp_connection.cpp | 44 +++++++++++++------------- src/net/tcp_connection_states.cpp | 51 ++++++++++++++++++++++++++----- 4 files changed, 127 insertions(+), 35 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index d9e30d5e18..3701ee2e0c 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -1076,6 +1076,11 @@ namespace net { */ std::queue write_queue; + /* + State if connection is in TCP write queue or not. + */ + bool is_queued_; + /* Bytes queued for transmission. */ @@ -1180,20 +1185,46 @@ namespace net { /* Process the write queue with the given amount of packets. - Returns true if all the jobs are done (queue is empty) + Returns true if the Connection finishes - there is no more doable jobs. */ bool offer(size_t& packets); + /* + Returns if the connection has a doable write job. + */ + inline bool has_doable_job() { + return !write_queue.empty() and usable_window() >= MSDS(); + } + + /* + Try to process the current write queue. + */ + void write_queue_push(); + /* Try to write (some of) queue on connected. */ - void write_queue_on_connect(); + inline void write_queue_on_connect() { write_queue_push(); } /* Reset queue on disconnect. Clears the queue and notice every requests callback. */ void write_queue_reset(); + /* + Returns if the TCP has the Connection in write queue + */ + inline bool is_queued() const { + return is_queued_; + } + + /* + Mark wether the Connection is in TCP write queue or not. + */ + inline void is_queued(bool queued) { + is_queued_ = queued; + } + /* Invoke/signal the diffrent TCP events. */ @@ -1223,6 +1254,11 @@ namespace net { */ inline Connection::TCB& tcb() { return control_block; } + inline int32_t usable_window() const { + auto x = (int64_t)control_block.SND.UNA + (int64_t)control_block.SND.WND - (int64_t)control_block.SND.NXT; + return (int32_t) x; + } + /* Generate a new ISS. */ @@ -1467,6 +1503,13 @@ namespace net { */ size_t send(Connection_ptr, Connection::WriteBuffer&); + /* + Force the TCP to process the it's queue with the current amount of available packets. + */ + inline void kick() { + process_write_queue(inet_.transmit_queue_available()); + } + }; // < class TCP diff --git a/src/net/tcp.cpp b/src/net/tcp.cpp index dce08a0239..7b9c48f375 100644 --- a/src/net/tcp.cpp +++ b/src/net/tcp.cpp @@ -189,8 +189,18 @@ void TCP::process_write_queue(size_t packets) { // foreach connection who wants to write while(packets and !write_queue.empty()) { auto conn = write_queue.front(); - if(conn->offer(packets)) - write_queue.pop(); + write_queue.pop(); + // try to offer if there is any doable job, and if still more to do, requeue. + if(conn->has_doable_job() and !conn->offer(packets)) { + debug2("TCP::process_write_queue> %s still has more to do. Re-queued.\n"); + write_queue.push(conn); + } + else { + // mark the connection as not queued. + conn->is_queued(false); + debug2(" %s Removed from queue. Size is %u\n", + conn->to_string().c_str(), write_queue.size()); + } } } @@ -202,8 +212,12 @@ size_t TCP::send(Connection_ptr conn, Connection::WriteBuffer& buffer) { written = conn->send(buffer, packets); } - if(written < buffer.remaining) + if(written < buffer.remaining and !conn->is_queued()) { write_queue.push(conn); + conn->is_queued(true); + debug2(" %s wrote %u bytes (%u remaining) and is Re-queued.\n", + conn->to_string().c_str(), written, buffer.remaining-written); + } return written; } diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index 4945b43935..75bfeb9bc2 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -36,6 +36,8 @@ Connection::Connection(TCP& host, Port local_port, Socket remote) : prev_state_(state_), control_block(), read_request(), + write_queue(), + is_queued_(false), time_wait_started(0) { @@ -44,15 +46,8 @@ Connection::Connection(TCP& host, Port local_port, Socket remote) : /* This is most likely used in a PASSIVE open */ -Connection::Connection(TCP& host, Port local_port) : - host_(host), - local_port_(local_port), - remote_(TCP::Socket()), - state_(&Connection::Closed::instance()), - prev_state_(state_), - control_block(), - read_request(), - time_wait_started(0) +Connection::Connection(TCP& host, Port local_port) + : Connection(host, local_port, TCP::Socket()) { } @@ -121,23 +116,29 @@ void Connection::write(WriteBuffer buffer, WriteCallback callback) { bool Connection::offer(size_t& packets) { assert(packets); - debug2(" (%s) got offered [%u] packets.\n", tuple().to_string().c_str(), packets); + debug(" %s got offered [%u] packets. Usable window is %i.\n", + to_string().c_str(), packets, usable_window()); - while(!write_queue.empty() and packets) { + while(has_doable_job() and packets) { auto& buf = write_queue.front().first; // segmentize the buffer into packets auto written = send(buf, packets); // advance the buffer buf.advance(written); + debug2(" Wrote %u bytes (%u remaining) with [%u] packets left and a usable window of %i.\n", + written, buf.remaining, packets, usable_window()); // if finished if(!buf.remaining) { // callback and remove object write_queue.front().second(buf.offset); write_queue.pop(); + debug(" Request finished.\n"); } } assert(packets >= 0); - return write_queue.empty(); + debug(" Finished working offer with [%u] packets left and a queue of (%u) with a usable window of %i\n", + packets, write_queue.size(), usable_window()); + return !has_doable_job(); } @@ -145,7 +146,7 @@ size_t Connection::send(const char* buffer, size_t remaining, size_t& packet_cou assert(packet_count && remaining); size_t bytes_written{0}; - while(remaining and packet_count) { + while(remaining and packet_count and usable_window() >= MSDS()) { // retreive a new packet auto packet = create_outgoing_packet(); // reduce the amount of packets available by one @@ -153,15 +154,16 @@ size_t Connection::send(const char* buffer, size_t remaining, size_t& packet_cou // add the seq, ack and flag packet->set_seq(control_block.SND.NXT).set_ack(control_block.RCV.NXT).set_flag(ACK); // calculate how much the packet can be filled with - auto packet_limit = (uint32_t)MSDS() - packet->header_size(); + auto packet_limit = std::min((uint32_t)MSDS() - packet->header_size(), (uint32_t)usable_window()); // fill the packet with data from the request size_t written = packet->fill(buffer+bytes_written, std::min(packet_limit, remaining)); // update local variables bytes_written += written; remaining -= written; - debug2(" Packet Limit: %u - Written: %u - Remaining: %u - Packet count: %u\n", - packet_limit, written, remaining, packet_count); + debug2(" Packet Limit: %u - Written: %u" + " - Remaining: %u - Packet count: %u, Window: %u\n", + packet_limit, written, remaining, packet_count, usable_window()); // If last packet, add PUSH. if(!remaining and PUSH) @@ -175,8 +177,7 @@ size_t Connection::send(const char* buffer, size_t remaining, size_t& packet_cou return bytes_written; } - -void Connection::write_queue_on_connect() { +void Connection::write_queue_push() { while(!write_queue.empty()) { auto& buf = write_queue.front().first; auto written = send(buf); @@ -241,9 +242,6 @@ void Connection::segment_arrived(TCP::Packet_ptr incoming) { } } - // Change window accordingly. TODO: Not sure if this is how you do it. - control_block.SND.WND = incoming->win(); - // Let state handle what to do when incoming packet arrives, and modify the outgoing packet. switch(state_->handle(*this, incoming)) { case State::OK: { @@ -276,6 +274,7 @@ Connection::~Connection() { TCP::Packet_ptr Connection::create_outgoing_packet() { auto packet = std::static_pointer_cast((host_.inet_).createPacket(TCP::Packet::HEADERS_SIZE)); + //auto packet = host_.create_empty_packet(); packet->init(); // Set Source (local == the current connection) @@ -297,7 +296,7 @@ void Connection::transmit(TCP::Packet_ptr packet) { host_.transmit(packet); // Don't think we would like to retransmit reset packets..? //if(!packet->isset(RST)) - // add_retransmission(packet); + // add_retransmission(packet); } TCP::Seq Connection::generate_iss() { @@ -318,6 +317,7 @@ void Connection::add_retransmission(TCP::Packet_ptr packet) { // Packet hasnt been ACKed. if(packet->seq() > self->tcb().SND.UNA) { debug(" Packet unacknowledge, retransmitting...\n"); + packet->set_ack(self->tcb().RCV.NXT); self->transmit(packet); } else { debug2(" Packet acknowledged %s \n", packet->to_string().c_str()); diff --git a/src/net/tcp_connection_states.cpp b/src/net/tcp_connection_states.cpp index c7fe146ea5..40b639f7fc 100644 --- a/src/net/tcp_connection_states.cpp +++ b/src/net/tcp_connection_states.cpp @@ -16,6 +16,7 @@ // limitations under the License. #include +#include using namespace std; @@ -127,7 +128,12 @@ bool Connection::State::check_seq(Connection& tcp, TCP::Packet_ptr in) { packet->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); tcp.transmit(packet); } - tcp.drop(in, "Unacceptable SEQ."); + std::stringstream ss; + ss << "Unacceptable SEQ: " + << "[Packet: SEQ: " << in->seq() << " LEN: " << in->data_length() << "] " + << "[TCB: RCV.NXT: " << tcb.RCV.NXT << " RCV.WND: " << tcb.RCV.WND << "]"; + + tcp.drop(in, ss.str()); return false; } debug2(" Acceptable SEQ: %u \n", in->seq()); @@ -207,6 +213,7 @@ bool Connection::State::check_ack(Connection& tcp, TCP::Packet_ptr in) { */ if( tcb.SND.UNA < in->ack() and in->ack() <= tcb.SND.NXT ) { tcb.SND.UNA = in->ack(); + debug2(" Usable window slided (%i)\n", tcp.usable_window()); // tcp.signal_sent(); // return that buffer has been SENT - currently no support to receipt sent buffer. @@ -289,26 +296,53 @@ void Connection::State::process_segment(Connection& tcp, TCP::Packet_ptr in) { auto& tcb = tcp.tcb(); auto length = in->data_length(); + // Receive could result in a user callback. This is used to avoid sending empty ACK reply. + auto snd_nxt = tcb.SND.NXT; debug(" Received packet with DATA-LENGTH: %i. Add to receive buffer. \n", length); if(tcp.read_request.buffer.capacity()) { auto received = tcp.receive((uint8_t*)in->data(), in->data_length(), in->isset(PSH)); assert(received == length); } tcb.RCV.NXT += length; - auto snd_nxt = tcb.SND.NXT; debug2(" Advanced RCV.NXT: %u. SND.NXT = %u \n", tcb.RCV.NXT, snd_nxt); + + /* + WARNING/NOTE: + Not sure how "dangerous" the following is, and how big of a bottleneck it is. + Maybe has to be implemented with timers or something. + */ + /* Once the TCP takes responsibility for the data it advances RCV.NXT over the data accepted, and adjusts RCV.WND as apporopriate to the current buffer availability. The total of RCV.NXT and RCV.WND should not be reduced. */ - // TODO: SACK (Selective ACK), or if there is a write queue, don't send ACK. - if(tcb.SND.NXT == snd_nxt) { - auto packet = tcp.outgoing_packet(); - packet->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); - tcp.transmit(packet); - } else { + // no data has been sent during user callback + // TODO: A lot of cleanup / refactoring - this is messy. + if(snd_nxt == tcb.SND.NXT) { + // Piggyback ACK with outgoing data + if(tcp.has_doable_job() and !tcp.is_queued()) { + debug2(" Usable window: %i\n", tcp.usable_window()); + tcp.write_queue_push(); + // we tried to push data, but nothing was written, reply the sender immediately + if(tcp.usable_window() == tcb.SND.WND) { + auto packet = tcp.outgoing_packet(); + packet->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); + tcp.transmit(packet); + } + } + // TODO: Selective ACK + // If no outgoing data right now - reply with ACK. + else { + debug2(" ACK. Window: %i, Queue: %u, is_queued: %s\n", + tcp.usable_window(), tcp.write_queue.size(), tcp.is_queued() ? "true" : "false"); + auto packet = tcp.outgoing_packet(); + packet->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); + tcp.transmit(packet); + } + } + else { debug2(" SND.NXT > snd_nxt, this packet has already been acknowledged. \n"); } } @@ -986,6 +1020,7 @@ State::Result Connection::Established::handle(Connection& tcp, TCP::Packet_ptr i tcp.set_state(Connection::CloseWait::instance()); return CLOSE; } + return OK; } From 40f2073f211d779fcb9254b91cc8fe6908944f86 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Thu, 7 Apr 2016 17:18:55 +0200 Subject: [PATCH 107/311] udp: WriteBuffer work --- api/net/ip4/udp.hpp | 67 ++++++++++++++++++++++++++++++-------- api/net/ip4/udp_socket.hpp | 2 +- src/net/dns/client.cpp | 5 ++- src/net/ip4/udp.cpp | 38 ++++++++++++++++++--- src/net/ip4/udp_socket.cpp | 9 ++++- test/UDP/service.cpp | 6 ++-- 6 files changed, 102 insertions(+), 25 deletions(-) diff --git a/api/net/ip4/udp.hpp b/api/net/ip4/udp.hpp index 3dd670b3c4..339421be0c 100644 --- a/api/net/ip4/udp.hpp +++ b/api/net/ip4/udp.hpp @@ -18,18 +18,17 @@ #ifndef NET_IP4_UDP_HPP #define NET_IP4_UDP_HPP +#include #include - #include "../inet.hpp" #include "ip4.hpp" +#include namespace net { class PacketUDP; class UDPSocket; - - void ignore_udp(Packet_ptr); - + /** Basic UDP support. @todo Implement UDP sockets. */ class UDP { public: @@ -38,7 +37,40 @@ namespace net { using Packet_ptr = std::shared_ptr; using Stack = Inet; - + + typedef delegate sendto_handler; + + // write buffer for sendq + struct WriteBuffer + { + WriteBuffer( + const uint8_t* data, size_t length, sendto_handler cb, + addr_t LA, port_t LP, addr_t DA, port_t DP); + + int remaining() const { + return len - offset; + } + bool done() const { + return offset == len; + } + + size_t packets_needed() const; + + // buffer, total length and current write offset + std::shared_ptr buf; + size_t len; + size_t offset; + // the callback for when this buffer is written + sendto_handler callback; + + // the port this was being sent from + addr_t l_addr; + port_t l_port; + // destination address and port + port_t d_port; + addr_t d_addr; + }; + /** UDP header */ struct udp_header { port_t sport; @@ -46,23 +78,23 @@ namespace net { uint16_t length; uint16_t checksum; }; - + /** Full UDP Header with all sub-headers */ struct full_header { IP4::full_header full_hdr; udp_header udp_hdr; }__attribute__((packed)); - + //////////////////////////////////////////// - - inline addr_t local_ip() const + + addr_t local_ip() const { return stack_.ip_addr(); } /** Input from network layer */ void bottom(net::Packet_ptr); /** Delegate output to network layer */ - inline void set_network_out(downstream del) + void set_network_out(downstream del) { network_layer_out_ = del; } /** Send UDP datagram from source ip/port to destination ip/port. @@ -81,15 +113,24 @@ namespace net { //! construct this UDP module with @inet UDP(Stack& inet) : - network_layer_out_ {ignore_udp}, - stack_ {inet} - { } + stack_(inet) + { + network_layer_out_ = [] (net::Packet_ptr) {}; + } + + size_t process_sendq(size_t num); + private: downstream network_layer_out_; Stack& stack_; std::map ports_; port_t current_port_ {1024}; + + // the async send queue + std::deque sendq; + friend class net::UDPSocket; }; //< class UDP + } //< namespace net #include "packet_udp.hpp" diff --git a/api/net/ip4/udp_socket.hpp b/api/net/ip4/udp_socket.hpp index 87e18deb11..fcb03b20d4 100644 --- a/api/net/ip4/udp_socket.hpp +++ b/api/net/ip4/udp_socket.hpp @@ -33,7 +33,7 @@ namespace net using Stack = Inet; typedef delegate recvfrom_handler; - typedef delegate sendto_handler; + typedef UDP::sendto_handler sendto_handler; // constructors UDPSocket(Stack&, port_t port); diff --git a/src/net/dns/client.cpp b/src/net/dns/client.cpp index 68ddfc3284..902caa3106 100644 --- a/src/net/dns/client.cpp +++ b/src/net/dns/client.cpp @@ -24,12 +24,11 @@ namespace net { void DNSClient::resolve(IP4::addr dns_server, const std::string& hostname, Stack::resolve_func func) { - UDP::port_t port = 33314; // <-- FIXME: should be automatic port - auto& sock = stack.udp().bind(port); + auto& sock = stack.udp().bind(); // create DNS request DNS::Request request; - char* data = new char[256]; + auto* data = new char[256]; size_t len = request.create(data, hostname); // send request to DNS server diff --git a/src/net/ip4/udp.cpp b/src/net/ip4/udp.cpp index a0e5625623..5b250abbd9 100644 --- a/src/net/ip4/udp.cpp +++ b/src/net/ip4/udp.cpp @@ -71,7 +71,7 @@ namespace net { return bind(current_port_); } - void UDP::transmit(std::shared_ptr udp) { + void UDP::transmit(UDP::Packet_ptr udp) { debug2(" Transmitting %i bytes (seg=%i) from %s to %s:%i\n", udp->length(), udp->ip4_segment_size(), udp->src().str().c_str(), @@ -83,10 +83,38 @@ namespace net { auto pckt = Packet::packet(udp); network_layer_out_(pckt); } - - void ignore_udp(Packet_ptr) + + size_t UDP::process_sendq(size_t num) { - debug("Network> No handler - DROP!\n"); + if (num == 0) + { + size_t total = 0; + for (auto& buf : sendq) + total += buf.packets_needed(); + } } - + + size_t UDP::WriteBuffer::packets_needed() const + { + int r = remaining(); + // whole packets + size_t P = r / stack.MTU(); + // one packet for remainder + if (r % stack.MTU()) P++; + return P; + } + UDP::WriteBuffer::WriteBuffer( + const uint8_t* data, size_t length, sendto_handler cb, + addr_t LA, port_t LP, addr_t DA, port_t DP) + : len(length), offset(0), callback(cb), + l_addr(LA), l_port(LP), d_port(DP), d_addr(DA) + { + // create a copy of the data, + auto* copy = new uint8_t[len]; + memcpy(copy, data, length); + // make it shared + this->buf = + std::shared_ptr (copy, std::default_delete()); + } + } //< namespace net diff --git a/src/net/ip4/udp_socket.cpp b/src/net/ip4/udp_socket.cpp index a544e6bf94..74bbc4779a 100644 --- a/src/net/ip4/udp_socket.cpp +++ b/src/net/ip4/udp_socket.cpp @@ -51,10 +51,15 @@ namespace net addr_t srcIP, addr_t destIP, port_t port, - const uint8_t* buffer, + const uint8_t* data, size_t length, sendto_handler cb) { + stack.udp().sendq.emplace_back( + data, length, cb, + srcIP, this->l_port, destIP, port); + + /* // the maximum we can write per packet: const size_t WRITE_MAX = stack.MTU() - PacketUDP::HEADERS_SIZE; // the bytes remaining to be written @@ -91,6 +96,8 @@ namespace net // ship the packet stack.udp().transmit(p2); } + */ + } // internal_write() void UDPSocket::sendto( diff --git a/test/UDP/service.cpp b/test/UDP/service.cpp index 2489118669..43922b8ed4 100644 --- a/test/UDP/service.cpp +++ b/test/UDP/service.cpp @@ -38,10 +38,10 @@ void Service::start() printf("Service IP address is %s\n", inet.ip_addr().str().c_str()); // UDP - UDP::port_t port = 4242; + const UDP::port_t port = 4242; auto& sock = inet.udp().bind(port); - sock.onRead( + sock.on_read( [&sock] (UDP::addr_t addr, UDP::port_t port, const char* data, size_t len) { @@ -51,6 +51,8 @@ void Service::start() // send the same thing right back! sock.sendto(addr, port, data, len, [] { + // sent + INFO("UDP test", "SUCCESS"); }); }); From 282e54c160b3dc9acc7267b3592c4d35f77430e5 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Fri, 8 Apr 2016 13:28:47 +0200 Subject: [PATCH 108/311] udp: WriteBuffer write function --- api/net/ip4/udp.hpp | 12 ++++++-- src/net/ip4/udp.cpp | 58 +++++++++++++++++++++++++++++++++++--- src/net/ip4/udp_socket.cpp | 42 +-------------------------- 3 files changed, 65 insertions(+), 47 deletions(-) diff --git a/api/net/ip4/udp.hpp b/api/net/ip4/udp.hpp index 339421be0c..bb1b50179c 100644 --- a/api/net/ip4/udp.hpp +++ b/api/net/ip4/udp.hpp @@ -45,7 +45,7 @@ namespace net { { WriteBuffer( const uint8_t* data, size_t length, sendto_handler cb, - addr_t LA, port_t LP, addr_t DA, port_t DP); + UDP& udp, addr_t LA, port_t LP, addr_t DA, port_t DP); int remaining() const { return len - offset; @@ -55,6 +55,7 @@ namespace net { } size_t packets_needed() const; + void write(); // buffer, total length and current write offset std::shared_ptr buf; @@ -62,8 +63,10 @@ namespace net { size_t offset; // the callback for when this buffer is written sendto_handler callback; + // the UDP stack + UDP& udp; - // the port this was being sent from + // port and addr this was being sent from addr_t l_addr; port_t l_port; // destination address and port @@ -118,6 +121,11 @@ namespace net { network_layer_out_ = [] (net::Packet_ptr) {}; } + Stack& stack() + { + return stack_; + } + size_t process_sendq(size_t num); private: diff --git a/src/net/ip4/udp.cpp b/src/net/ip4/udp.cpp index 5b250abbd9..bd2a197e40 100644 --- a/src/net/ip4/udp.cpp +++ b/src/net/ip4/udp.cpp @@ -86,27 +86,44 @@ namespace net { size_t UDP::process_sendq(size_t num) { + // for gathering phase if (num == 0) { size_t total = 0; for (auto& buf : sendq) total += buf.packets_needed(); + + return total; } + + // for processing phase + while (!sendq.empty() && num != 0) + { + WriteBuffer& buffer = sendq.front(); + // create and transmit packet from writebuffer + buffer.write(); + num--; + + if (buffer.done()) + sendq.pop_front(); + } + + return num; } size_t UDP::WriteBuffer::packets_needed() const { int r = remaining(); // whole packets - size_t P = r / stack.MTU(); + size_t P = r / udp.stack().MTU(); // one packet for remainder - if (r % stack.MTU()) P++; + if (r % udp.stack().MTU()) P++; return P; } UDP::WriteBuffer::WriteBuffer( const uint8_t* data, size_t length, sendto_handler cb, - addr_t LA, port_t LP, addr_t DA, port_t DP) - : len(length), offset(0), callback(cb), + UDP& stack, addr_t LA, port_t LP, addr_t DA, port_t DP) + : len(length), offset(0), callback(cb), udp(stack), l_addr(LA), l_port(LP), d_port(DP), d_addr(DA) { // create a copy of the data, @@ -117,4 +134,37 @@ namespace net { std::shared_ptr (copy, std::default_delete()); } + void UDP::WriteBuffer::write() + { + const size_t MTU = udp.stack().MTU(); + + // the maximum we can write per packet: + const size_t WRITE_MAX = MTU - PacketUDP::HEADERS_SIZE; + // the bytes remaining to be written + size_t total = remaining(); + total = (total > WRITE_MAX) ? WRITE_MAX : total; + + // create some packet p (and convert it to PacketUDP) + auto p = udp.stack().createPacket(MTU); + // fill buffer (at payload position) + memcpy(p->buffer() + PacketUDP::HEADERS_SIZE, + buf.get() + this->offset, total); + + // initialize packet with several infos + auto p2 = std::static_pointer_cast(p); + + p2->init(); + p2->header().sport = htons(l_port); + p2->header().dport = htons(d_port); + p2->set_src(l_addr); + p2->set_dst(d_addr); + p2->set_length(total); + + // ship the packet + udp.transmit(p2); + + // next position in buffer + this->offset += total; + } + } //< namespace net diff --git a/src/net/ip4/udp_socket.cpp b/src/net/ip4/udp_socket.cpp index 74bbc4779a..a0011a52c2 100644 --- a/src/net/ip4/udp_socket.cpp +++ b/src/net/ip4/udp_socket.cpp @@ -56,48 +56,8 @@ namespace net sendto_handler cb) { stack.udp().sendq.emplace_back( - data, length, cb, + data, length, cb, stack.udp(), srcIP, this->l_port, destIP, port); - - /* - // the maximum we can write per packet: - const size_t WRITE_MAX = stack.MTU() - PacketUDP::HEADERS_SIZE; - // the bytes remaining to be written - size_t rem = length; - - while (rem >= WRITE_MAX) - { - // create some packet p (and convert it to PacketUDP) - auto p = stack.createPacket(stack.MTU()); - // fill buffer (at payload position) - memcpy(p->buffer() + PacketUDP::HEADERS_SIZE, buffer, WRITE_MAX); - - // initialize packet with several infos - auto p2 = std::static_pointer_cast(p); - packet_init(p2, srcIP, destIP, port, WRITE_MAX); - // ship the packet - stack.udp().transmit(p2); - - // next buffer part - buffer += WRITE_MAX; rem -= WRITE_MAX; - } - if (rem) - { - // copy remainder - size_t size = PacketUDP::HEADERS_SIZE + rem; - - // create some packet p - auto p = stack.createPacket(size); - memcpy(p->buffer() + PacketUDP::HEADERS_SIZE, buffer, rem); - - // initialize packet with several infos - auto p2 = std::static_pointer_cast(p); - packet_init(p2, srcIP, destIP, port, rem); - // ship the packet - stack.udp().transmit(p2); - } - */ - } // internal_write() void UDPSocket::sendto( From 8a31ffca898189107e276ad7cb68539b7acd593d Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Fri, 8 Apr 2016 17:37:51 +0200 Subject: [PATCH 109/311] net: Distribute free buffers, udp: Remove gather phase --- api/net/inet4.hpp | 16 +++++++++------ api/net/inet4.inc | 49 ++++++++++++++++++++++++++++++++++++++++++++- api/net/ip4/udp.hpp | 9 +++------ src/net/ip4/udp.cpp | 32 +++++++++++++---------------- 4 files changed, 75 insertions(+), 31 deletions(-) diff --git a/api/net/inet4.hpp b/api/net/inet4.hpp index 1ded92c52d..bc671b5997 100644 --- a/api/net/inet4.hpp +++ b/api/net/inet4.hpp @@ -55,14 +55,14 @@ namespace net { Ethernet& link() override { return eth_; } - inline IP4& ip_obj() override + IP4& ip_obj() override { return ip4_; } /** Get the TCP-object belonging to this stack */ - inline TCP& tcp() override { debug(" Returning tcp-reference to %p \n",&tcp_); return tcp_; } + TCP& tcp() override { return tcp_; } /** Get the UDP-object belonging to this stack */ - inline UDP& udp() override { return udp_; } + UDP& udp() override { return udp_; } /** Get the DHCP client (if any) */ inline std::shared_ptr dhclient() override { return dhcp_; } @@ -129,9 +129,10 @@ namespace net { this->dns_server = dns; } - inline virtual void + // register a callback for receiving signal on free packet-buffers + virtual void on_transmit_queue_available(transmit_avail_delg del) override { - nic_.on_transmit_queue_available(del); + tqa.push_back(del); } inline virtual size_t transmit_queue_available() override { @@ -143,7 +144,8 @@ namespace net { } private: - + void transmit_queue_available(size_t); + IP4::addr ip4_addr_; IP4::addr netmask_; IP4::addr router_; @@ -162,6 +164,8 @@ namespace net { std::shared_ptr dhcp_{}; BufferStore& bufstore_; + // delegates registered to get signalled about free packets + std::vector tqa; }; } diff --git a/api/net/inet4.inc b/api/net/inet4.inc index d2e7fdc161..7c6a3f0b63 100644 --- a/api/net/inet4.inc +++ b/api/net/inet4.inc @@ -23,6 +23,9 @@ namespace net auto tcp_bottom(upstream::from(tcp_)); /** Upstream wiring */ + // Packets available + nic.on_transmit_queue_available( + transmit_avail_delg::from, transmit_queue_available>(*this)); // Phys -> Eth (Later, this will be passed through router) nic.set_linklayer_out(eth_bottom); @@ -42,7 +45,6 @@ namespace net // IP4 -> TCP ip4_.set_tcp_handler(tcp_bottom); - /** Downstream delegates */ auto phys_top(downstream ::from,&hw::Nic::transmit>(nic)); @@ -83,4 +85,49 @@ namespace net dhcp_->negotiate(); } + template + void Inet4::transmit_queue_available(size_t packets) + { + //////////////////////////////////////////// + // divide up fairly + size_t div = packets / tqa.size(); + + // give each protocol a chance to take + for (size_t i = 0; i < tqa.size(); i++) + tqa[i](div); + + // hand out remaining + for (size_t i = 0; i < tqa.size(); i++) + { + div = buffers_available(); + if (!div) break; + // give as much as possible + tqa[i](div); + } + //////////////////////////////////////////// + + /* + size_t list[tqa.size()]; + for (size_t i = 0; i < tqa.size(); i++) + list[i] = tqa[i](0); + + size_t give[tqa.size()] = {0}; + int cp = 0; // current protocol + + // distribute packets one at a time for each protocol + while (packets--) + { + if (list[cp]) + { + // give one packet + give[cp]++; list[cp]--; + } + cp = (cp + 1) % tqa.size(); + } + // hand out several packets per protocol + for (size_t i = 0; i < tqa.size(); i++) + if (give[i]) tqa[i](give[i]); + */ + } + } diff --git a/api/net/ip4/udp.hpp b/api/net/ip4/udp.hpp index bb1b50179c..788c691233 100644 --- a/api/net/ip4/udp.hpp +++ b/api/net/ip4/udp.hpp @@ -115,18 +115,15 @@ namespace net { UDPSocket& bind(); //! construct this UDP module with @inet - UDP(Stack& inet) : - stack_(inet) - { - network_layer_out_ = [] (net::Packet_ptr) {}; - } + UDP(Stack& inet); Stack& stack() { return stack_; } - size_t process_sendq(size_t num); + // create packets from send queue + void process_sendq(size_t num); private: downstream network_layer_out_; diff --git a/src/net/ip4/udp.cpp b/src/net/ip4/udp.cpp index bd2a197e40..76aa60b28e 100644 --- a/src/net/ip4/udp.cpp +++ b/src/net/ip4/udp.cpp @@ -23,6 +23,14 @@ namespace net { + UDP::UDP(Stack& inet) + : stack_(inet) + { + network_layer_out_ = [] (net::Packet_ptr) {}; + inet.on_transmit_queue_available( + transmit_avail_delg::from(this)); + } + void UDP::bottom(net::Packet_ptr pckt) { debug(" Got data"); @@ -50,9 +58,9 @@ namespace net { if (it == ports_.end()) { // create new socket auto res = ports_.emplace( - std::piecewise_construct, - std::forward_as_tuple(port), - std::forward_as_tuple(stack_, port)); + std::piecewise_construct, + std::forward_as_tuple(port), + std::forward_as_tuple(stack_, port)); it = res.first; } return it->second; @@ -65,7 +73,8 @@ namespace net { debug("UDP finding free ephemeral port\n"); while (ports_.find(++current_port_) != ports_.end()) - if (current_port_ == 0) current_port_ = 1025; // prevent automatic ports under 1024 + // prevent automatic ports under 1024 + if (current_port_ == 0) current_port_ = 1024; debug("UDP binding to %i port\n", current_port_); return bind(current_port_); @@ -84,19 +93,8 @@ namespace net { network_layer_out_(pckt); } - size_t UDP::process_sendq(size_t num) + void UDP::process_sendq(size_t num) { - // for gathering phase - if (num == 0) - { - size_t total = 0; - for (auto& buf : sendq) - total += buf.packets_needed(); - - return total; - } - - // for processing phase while (!sendq.empty() && num != 0) { WriteBuffer& buffer = sendq.front(); @@ -107,8 +105,6 @@ namespace net { if (buffer.done()) sendq.pop_front(); } - - return num; } size_t UDP::WriteBuffer::packets_needed() const From 6aff13ad024151a89f144498257040df476983f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Fri, 8 Apr 2016 17:59:39 +0200 Subject: [PATCH 110/311] tcp: work on rfc5681 (congestion control) --- api/net/tcp.hpp | 80 ++++++++++++++++++++++++++----- src/net/tcp.cpp | 4 +- src/net/tcp_connection.cpp | 69 ++++++++++++++++++-------- src/net/tcp_connection_states.cpp | 36 ++++++++++++-- 4 files changed, 150 insertions(+), 39 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index 3701ee2e0c..4256fb37c1 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -274,7 +274,7 @@ namespace net { PacketIP4::init(); set_protocol(IP4::IP4_TCP); - set_win_size(TCP::default_window_size); + set_win(TCP::default_window_size); set_offset(5); // set TCP payload location (!?) @@ -317,7 +317,7 @@ namespace net { return *this; } - inline TCP::Packet& set_win_size(uint16_t size) { + inline TCP::Packet& set_win(uint16_t size) { header().window_size = htons(size); return *this; } @@ -777,6 +777,8 @@ namespace net { TCP::Seq WL2; // segment acknowledgment number used for last window update uint16_t MSS; // Maximum segment size for outgoing segments. + + uint32_t cwnd; // Congestion window [RFC 5681] } SND; // << TCP::Seq ISS; // initial send sequence number @@ -785,16 +787,29 @@ namespace net { TCP::Seq NXT; // receive next uint16_t WND; // receive window uint16_t UP; // receive urgent pointer + + uint16_t rwnd; // receivers advertised window [RFC 5681] } RCV; // << TCP::Seq IRS; // initial receive sequence number + uint32_t ssthresh; // slow start threshold [RFC 5681] + TCB() { - SND = { 0, 0, TCP::default_window_size, 0, 0, 0, TCP::default_mss }; + SND = { 0, 0, TCP::default_window_size, 0, 0, 0, TCP::default_mss, 0 }; ISS = 0; - RCV = { 0, TCP::default_window_size, 0 }; + RCV = { 0, TCP::default_window_size, 0, 0 }; IRS = 0; + ssthresh = TCP::default_window_size; }; + bool slow_start() const { + return SND.cwnd <= ssthresh; + } + + bool congestion_avoidance() const { + return !slow_start(); + } + std::string to_string() const; }__attribute__((packed)); // < struct TCP::Connection::TCB @@ -1079,7 +1094,12 @@ namespace net { /* State if connection is in TCP write queue or not. */ - bool is_queued_; + bool queued_; + + struct { + TCP::Seq ACK = 0; + size_t count = 0; + } dup_acks_; /* Bytes queued for transmission. @@ -1215,14 +1235,14 @@ namespace net { Returns if the TCP has the Connection in write queue */ inline bool is_queued() const { - return is_queued_; + return queued_; } /* Mark wether the Connection is in TCP write queue or not. */ - inline void is_queued(bool queued) { - is_queued_ = queued; + inline void set_queued(bool queued) { + queued_ = queued; } /* @@ -1259,6 +1279,38 @@ namespace net { return (int32_t) x; } + /// Congestion Control [RFC 5681] /// + + inline uint16_t SMSS() const { + return host_.MSS(); + } + + inline uint16_t RMSS() const { + return control_block.SND.MSS; + } + + inline int32_t flight_size() const { + return control_block.SND.NXT - control_block.SND.UNA; + } + + inline void init_cwnd() { + control_block.SND.cwnd = 10*SMSS(); + } + + inline void reduce_slow_start_threshold() { + control_block.ssthresh = std::max( (flight_size() / 2), (2 * SMSS()) ); + printf("TCP::Connection::reduce_slow_start_threshold> Slow start threshold reduced: %u\n", + control_block.ssthresh); + } + + inline void segment_loss_detected() { + reduce_slow_start_threshold(); + } + /* + + */ + size_t duplicate_ack(TCP::Seq ack); + /* Generate a new ISS. */ @@ -1271,19 +1323,21 @@ namespace net { */ void set_state(State& state); - - /// BUFFER HANDLING /// - /* Transmit the send buffer. */ void transmit(); /* - Transmit the packet. + Transmit the packet and hooks up retransmission. */ void transmit(TCP::Packet_ptr); + /* + Retransmit the packet. + */ + void retransmit(TCP::Packet_ptr); + /* Creates a new outgoing packet with the current TCB values and options. */ @@ -1303,7 +1357,7 @@ namespace net { // TODO: Calculate RTO, currently hardcoded to 1 second (1000ms). */ - void add_retransmission(TCP::Packet_ptr); + void queue_retransmission(TCP::Packet_ptr, size_t rt_attempt = 1); /* Measure the elapsed time between sending a data octet with a diff --git a/src/net/tcp.cpp b/src/net/tcp.cpp index 7b9c48f375..609fac7e37 100644 --- a/src/net/tcp.cpp +++ b/src/net/tcp.cpp @@ -197,7 +197,7 @@ void TCP::process_write_queue(size_t packets) { } else { // mark the connection as not queued. - conn->is_queued(false); + conn->set_queued(false); debug2(" %s Removed from queue. Size is %u\n", conn->to_string().c_str(), write_queue.size()); } @@ -214,7 +214,7 @@ size_t TCP::send(Connection_ptr conn, Connection::WriteBuffer& buffer) { if(written < buffer.remaining and !conn->is_queued()) { write_queue.push(conn); - conn->is_queued(true); + conn->set_queued(true); debug2(" %s wrote %u bytes (%u remaining) and is Re-queued.\n", conn->to_string().c_str(), written, buffer.remaining-written); } diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index 75bfeb9bc2..8153285553 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -37,7 +37,7 @@ Connection::Connection(TCP& host, Port local_port, Socket remote) : control_block(), read_request(), write_queue(), - is_queued_(false), + queued_(false), time_wait_started(0) { @@ -282,7 +282,7 @@ TCP::Packet_ptr Connection::create_outgoing_packet() { // Set Destination (remote) packet->set_destination(remote_); - packet->set_win_size(control_block.SND.WND); + packet->set_win(control_block.SND.WND); // Set SEQ and ACK - I think this is OK.. packet->set_seq(control_block.SND.NXT).set_ack(control_block.RCV.NXT); @@ -295,8 +295,53 @@ void Connection::transmit(TCP::Packet_ptr packet) { debug(" Transmitting: %s \n", packet->to_string().c_str()); host_.transmit(packet); // Don't think we would like to retransmit reset packets..? - //if(!packet->isset(RST)) - // add_retransmission(packet); + if(!packet->isset(RST)) + queue_retransmission(packet); +} + +void Connection::retransmit(TCP::Packet_ptr packet) { + debug(" Retransmitting: %s \n", packet->to_string().c_str()); + host_.transmit(packet); +} + +void Connection::queue_retransmission(TCP::Packet_ptr packet, size_t rt_attempt) { + const size_t ATTEMPT_LIMIT = 3; + auto self = shared_from_this(); + + if(rt_attempt <= ATTEMPT_LIMIT) { + hw::PIT::instance().onTimeout(RTO() * rt_attempt, + [packet, self, rt_attempt] + { + // Packet hasnt been ACKed. + if(packet->seq() > self->tcb().SND.UNA) { + debug(" Packet unacknowledge, retransmitting...\n"); + if(rt_attempt == 1) + self->segment_loss_detected(); + //packet->set_ack(self->tcb().RCV.NXT); + self->retransmit(packet); + self->queue_retransmission(packet, rt_attempt+1); + } else { + debug2(" Packet acknowledged %s \n", packet->to_string().c_str()); + // Signal user? + } + }); + } + else { + printf(" Give up already... Already tried %u times. Time to kill connection?\n", + ATTEMPT_LIMIT); + } + debug2(" Packet queued for retransmission [%u] \n", retransmit_try); +} + +size_t Connection::duplicate_ack(TCP::Seq ack) { + // if its another duplicate, increment count + if(dup_acks_.ACK == ack) + return ++dup_acks_.count; + + // if not, set the new ack and set count to 1 + dup_acks_.ACK = ack; + dup_acks_.count = 1; + return dup_acks_.count; } TCP::Seq Connection::generate_iss() { @@ -310,21 +355,7 @@ void Connection::set_state(State& state) { prev_state_->to_string().c_str(), state_->to_string().c_str()); } -void Connection::add_retransmission(TCP::Packet_ptr packet) { - debug2(" Packet added to retransmission. \n"); - auto self = shared_from_this(); - hw::PIT::instance().onTimeout(RTO(), [packet, self] { - // Packet hasnt been ACKed. - if(packet->seq() > self->tcb().SND.UNA) { - debug(" Packet unacknowledge, retransmitting...\n"); - packet->set_ack(self->tcb().RCV.NXT); - self->transmit(packet); - } else { - debug2(" Packet acknowledged %s \n", packet->to_string().c_str()); - // Signal user? - } - }); -} + /* Next compute a Smoothed Round Trip Time (SRTT) as: diff --git a/src/net/tcp_connection_states.cpp b/src/net/tcp_connection_states.cpp index 40b639f7fc..45af7304b7 100644 --- a/src/net/tcp_connection_states.cpp +++ b/src/net/tcp_connection_states.cpp @@ -211,7 +211,9 @@ bool Connection::State::check_ack(Connection& tcp, TCP::Packet_ptr in) { something not yet sent (SEG.ACK > SND.NXT) then send an ACK, drop the segment, and return. */ - if( tcb.SND.UNA < in->ack() and in->ack() <= tcb.SND.NXT ) { + //if( tcb.SND.UNA < in->ack() and in->ack() <= tcb.SND.NXT ) { + // Correction: [RFC 1122 p. 94] + if( tcb.SND.UNA <= in->ack() and in->ack() <= tcb.SND.NXT ) { tcb.SND.UNA = in->ack(); debug2(" Usable window slided (%i)\n", tcp.usable_window()); // tcp.signal_sent(); @@ -245,9 +247,23 @@ bool Connection::State::check_ack(Connection& tcp, TCP::Packet_ptr in) { return false; } /* If the ACK is a duplicate (SEG.ACK < SND.UNA), it can be ignored. */ - /*else if( in->ack() < tcb.SND.UNA ) { - // ignore. - }*/ + // Correction: [RFC 1122 p. 94] + else if( in->ack() <= tcb.SND.UNA ) { + printf(" Dup ACK.\n"); + // [RFC 5681] + /* + Note that a sender using SACK [RFC2018] MUST NOT send + new data unless the incoming duplicate acknowledgment contains + new SACK information. + */ + auto dup_count = tcp.duplicate_ack(in->ack()); + if(dup_count == 3) { + printf(" Duplicate ACK strike! (>= 3)\n"); + tcp.reduce_slow_start_threshold(); + } else if(dup_count > 3) { + tcb.SND.cwnd += tcp.SMSS(); + } + } return true; } // ACK not set. @@ -304,6 +320,8 @@ void Connection::State::process_segment(Connection& tcp, TCP::Packet_ptr in) { assert(received == length); } tcb.RCV.NXT += length; + // [RFC 5681] + tcb.SND.cwnd += std::min(length, tcp.SMSS()); debug2(" Advanced RCV.NXT: %u. SND.NXT = %u \n", tcb.RCV.NXT, snd_nxt); /* @@ -676,7 +694,9 @@ void Connection::CloseWait::close(Connection& tcp) { auto packet = tcp.outgoing_packet(); packet->set_seq(tcb.SND.NXT++).set_ack(tcb.RCV.NXT).set_flags(ACK | FIN); tcp.transmit(packet); - tcp.set_state(Connection::Closing::instance()); + //tcp.set_state(Connection::Closing::instance()); + // Correction: [RFC 1122 p. 93] + tcp.set_state(Connection::LastAck::instance()); } ///////////////////////////////////////////////////////////////////// @@ -860,6 +880,12 @@ State::Result Connection::SynSent::handle(Connection& tcp, TCP::Packet_ptr in) { // (our SYN has been ACKed) if(tcb.SND.UNA > tcb.ISS) { tcp.set_state(Connection::Established::instance()); + // Correction: [RFC 1122 p. 94] + tcb.SND.WND = in->win(); + tcb.SND.WL1 = in->seq(); + tcb.SND.WL2 = in->ack(); + // end of correction + TCP::Seq snd_nxt = tcb.SND.NXT; tcp.signal_connect(); // NOTE: User callback From f7363f1f4c135b12efd286df57ccdbff0da75217 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Fri, 8 Apr 2016 18:09:48 +0200 Subject: [PATCH 111/311] inet4: Fix transmit delegate typo --- api/net/inet4.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/net/inet4.inc b/api/net/inet4.inc index 7c6a3f0b63..1d723672cf 100644 --- a/api/net/inet4.inc +++ b/api/net/inet4.inc @@ -25,7 +25,7 @@ namespace net /** Upstream wiring */ // Packets available nic.on_transmit_queue_available( - transmit_avail_delg::from, transmit_queue_available>(*this)); + transmit_avail_delg::from, &Inet4::transmit_queue_available>(*this)); // Phys -> Eth (Later, this will be passed through router) nic.set_linklayer_out(eth_bottom); From 2ed7328b9646965f6e963048e707dc5bf77613be Mon Sep 17 00:00:00 2001 From: RicoAntonioFelix Date: Fri, 8 Apr 2016 15:41:24 -0400 Subject: [PATCH 112/311] Corrected typographical error --- CONTRIBUTE.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTE.md b/CONTRIBUTE.md index e0dc70cf62..801044d0e0 100644 --- a/CONTRIBUTE.md +++ b/CONTRIBUTE.md @@ -1,14 +1,14 @@ # Contributing to IncludeOS -Feel free to [clone, edit and send pull-request](https://help.github.com/articles/using-pull-requests). +Feel free to [clone, edit and send pull-request](https://help.github.com/articles/using-pull-requests). * Send any and all pull-requests to the dev-branch. It's ok if it comes from your master branch. -* Do exactly one thing pr. pull-request. This makes it possible to quickly see and understand what you've done. +* Do exactly one thing pr. pull-request. This makes it possible to quickly see and understand what you've done. * Please don't redo the folder-structure - if you have suggestions for this, just post an issue explaining the benefits of your suggested structure. * Everything you commit will be under the same license as this repo (Undecided so far) and HiOA will retain the right to publish your commits under a different license. ### Consider making a standalone module! -We're working on a github-based package manager, much like [npm](https://www.npmjs.com/). Most new funcitonality from us, such as HTTP and a REST-framework, will probably come out like separate packages - each with their own repository. This will help keep the IncludeOS core small, and easier to maintain. Clearly, we also want to gather everything in one place, and our upcoming package manager will be doing that. Meanwhile: If you do want make a module - just make it a separate github-repo, and let us know about it. We'll link to it from here, until the package manager is ready. +We're working on a github-based package manager, much like [npm](https://www.npmjs.com/). Most new functionality from us, such as HTTP and a REST-framework, will probably come out like separate packages - each with their own repository. This will help keep the IncludeOS core small, and easier to maintain. Clearly, we also want to gather everything in one place, and our upcoming package manager will be doing that. Meanwhile: If you do want make a module - just make it a separate github-repo, and let us know about it. We'll link to it from here, until the package manager is ready. ## Issue tracker Post any issues not already mentioned, in the [issue tracker](https://github.com/hioa-cs/IncludeOS/issues). You can also post questions, not answered in the [FAQ](https://github.com/hioa-cs/IncludeOS/wiki/FAQ). From 59f6dc0f10523feea4b50fed7666aa3c17ccdfd0 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Sat, 9 Apr 2016 00:03:10 +0200 Subject: [PATCH 113/311] net: Fix ordering issue with sendq --- api/net/inet4.hpp | 9 +++---- api/net/inet4.inc | 4 ++-- api/net/inet_common.hpp | 5 ++-- src/debug/test_service.cpp | 48 ++++++++++++++++++++------------------ test/UDP/service.cpp | 3 ++- 5 files changed, 36 insertions(+), 33 deletions(-) diff --git a/api/net/inet4.hpp b/api/net/inet4.hpp index bc671b5997..5d16dbed7a 100644 --- a/api/net/inet4.hpp +++ b/api/net/inet4.hpp @@ -133,9 +133,10 @@ namespace net { virtual void on_transmit_queue_available(transmit_avail_delg del) override { tqa.push_back(del); + printf("* adding transmit listener (sz=%u)\n", tqa.size() ); } - inline virtual size_t transmit_queue_available() override { + virtual size_t transmit_queue_available() override { return nic_.transmit_queue_available(); } @@ -144,7 +145,9 @@ namespace net { } private: - void transmit_queue_available(size_t); + inline void process_sendq(size_t); + // delegates registered to get signalled about free packets + std::vector tqa; IP4::addr ip4_addr_; IP4::addr netmask_; @@ -164,8 +167,6 @@ namespace net { std::shared_ptr dhcp_{}; BufferStore& bufstore_; - // delegates registered to get signalled about free packets - std::vector tqa; }; } diff --git a/api/net/inet4.inc b/api/net/inet4.inc index 1d723672cf..ab34caf92b 100644 --- a/api/net/inet4.inc +++ b/api/net/inet4.inc @@ -25,7 +25,7 @@ namespace net /** Upstream wiring */ // Packets available nic.on_transmit_queue_available( - transmit_avail_delg::from, &Inet4::transmit_queue_available>(*this)); + transmit_avail_delg::from, &Inet4::process_sendq>(*this)); // Phys -> Eth (Later, this will be passed through router) nic.set_linklayer_out(eth_bottom); @@ -86,7 +86,7 @@ namespace net } template - void Inet4::transmit_queue_available(size_t packets) + void Inet4::process_sendq(size_t packets) { //////////////////////////////////////////// // divide up fairly diff --git a/api/net/inet_common.hpp b/api/net/inet_common.hpp index ef8d0d5c48..c0ec7ec83b 100644 --- a/api/net/inet_common.hpp +++ b/api/net/inet_common.hpp @@ -36,9 +36,8 @@ namespace net { using downstream = delegate; using upstream = downstream; - // Delegate for signalling available space in device transmit queue - // 'count' is a multiple of packets - using transmit_avail_delg = delegate; + // Delegate for signalling available buffers in device transmit queue + using transmit_avail_delg = delegate; // Compute the internet checksum for the buffer / buffer part provided uint16_t checksum(void* data, size_t len) noexcept; diff --git a/src/debug/test_service.cpp b/src/debug/test_service.cpp index 614fcc6a76..24d3a2cc9e 100644 --- a/src/debug/test_service.cpp +++ b/src/debug/test_service.cpp @@ -18,7 +18,6 @@ #include #include #include -#include #include "ircd.hpp" using namespace std::chrono; @@ -26,9 +25,6 @@ using namespace std::chrono; // An IP-stack object std::unique_ptr > inet; -#include -std::unique_ptr term; - void Service::start() { // boilerplate @@ -41,11 +37,11 @@ void Service::start() {{ 8,8,8,8 }} ); // DNS /* - auto& tcp = inet->tcp(); - auto& server = tcp.bind(6667); // IRCd default port - server.onConnect( - [] (auto csock) - { + auto& tcp = inet->tcp(); + auto& server = tcp.bind(6667); // IRCd default port + server.onConnect( + [] (auto csock) + { printf("*** Received connection from %s\n", csock->remote().to_string().c_str()); @@ -74,21 +70,27 @@ void Service::start() /// inform others about disconnect //client.bcast(TK_QUIT, "Disconnected"); }); - });*/ + });*/ + + using namespace net; + const UDP::port_t port = 4242; + auto& sock = inet->udp().bind(port); - /// terminal /// - auto& serial = hw::Serial::port<1> (); - // create terminal with open TCP connection - term = std::make_unique (serial); - // add 'ifconfig' command - term->add( - "ifconfig", "Show information about interfaces", - [] (const std::vector&) -> int - { - term->write("%s\r\n", inet->tcp().status().c_str()); - return 0; - }); - /// terminal /// + sock.on_read( + [&sock] (UDP::addr_t addr, UDP::port_t port, + const char* data, size_t len) + { + std::string strdata(data, len); + CHECK(1, "Getting UDP data from %s:%d -> %s", + addr.str().c_str(), port, strdata.c_str()); + // send the same thing right back! + sock.sendto(addr, port, data, len, + [] { + // sent + + INFO("UDP test", "SUCCESS"); + }); + }); printf("*** TEST SERVICE STARTED *** \n"); } diff --git a/test/UDP/service.cpp b/test/UDP/service.cpp index 43922b8ed4..bfc5151f4e 100644 --- a/test/UDP/service.cpp +++ b/test/UDP/service.cpp @@ -41,6 +41,7 @@ void Service::start() const UDP::port_t port = 4242; auto& sock = inet.udp().bind(port); + /* sock.on_read( [&sock] (UDP::addr_t addr, UDP::port_t port, const char* data, size_t len) @@ -55,7 +56,7 @@ void Service::start() INFO("UDP test", "SUCCESS"); }); - }); + });*/ INFO("UDP test", "Listening on port %d\n", port); } From 18f595e2341f16f48e8723399efd06db17e3f993 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Sat, 9 Apr 2016 00:09:27 +0200 Subject: [PATCH 114/311] udp: Call on_written callback --- src/debug/test_service.cpp | 1 - src/net/ip4/udp.cpp | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/debug/test_service.cpp b/src/debug/test_service.cpp index 24d3a2cc9e..f5623836b8 100644 --- a/src/debug/test_service.cpp +++ b/src/debug/test_service.cpp @@ -87,7 +87,6 @@ void Service::start() sock.sendto(addr, port, data, len, [] { // sent - INFO("UDP test", "SUCCESS"); }); }); diff --git a/src/net/ip4/udp.cpp b/src/net/ip4/udp.cpp index 76aa60b28e..795cd9dfb2 100644 --- a/src/net/ip4/udp.cpp +++ b/src/net/ip4/udp.cpp @@ -103,7 +103,12 @@ namespace net { num--; if (buffer.done()) + { + // call on_written callback + buffer.callback(); + // remove buffer from queue sendq.pop_front(); + } } } From 6d2e508292e3044b9ee2773306052fc5dbe63787 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Sat, 9 Apr 2016 10:21:11 +0200 Subject: [PATCH 115/311] udp: Process sendq immediately when possible --- api/net/inet4.inc | 2 +- src/net/ip4/udp_socket.cpp | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/api/net/inet4.inc b/api/net/inet4.inc index ab34caf92b..9e4e10ce79 100644 --- a/api/net/inet4.inc +++ b/api/net/inet4.inc @@ -99,7 +99,7 @@ namespace net // hand out remaining for (size_t i = 0; i < tqa.size(); i++) { - div = buffers_available(); + div = transmit_queue_available(); if (!div) break; // give as much as possible tqa[i](div); diff --git a/src/net/ip4/udp_socket.cpp b/src/net/ip4/udp_socket.cpp index a0011a52c2..bfbd4b2f52 100644 --- a/src/net/ip4/udp_socket.cpp +++ b/src/net/ip4/udp_socket.cpp @@ -58,6 +58,9 @@ namespace net stack.udp().sendq.emplace_back( data, length, cb, stack.udp(), srcIP, this->l_port, destIP, port); + + size_t packets = stack.transmit_queue_available(); + if (packets) stack.udp().process_sendq(packets); } // internal_write() void UDPSocket::sendto( From 760db1e80b0e2d1f37214503059d37192968e333 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Sat, 9 Apr 2016 12:36:21 +0200 Subject: [PATCH 116/311] udp: Add flush(), remove internal_write() --- api/net/ip4/udp.hpp | 7 +++++-- api/net/ip4/udp_socket.hpp | 2 -- src/net/ip4/udp.cpp | 6 ++++++ src/net/ip4/udp_socket.cpp | 36 ++++++++++++++---------------------- 4 files changed, 25 insertions(+), 26 deletions(-) diff --git a/api/net/ip4/udp.hpp b/api/net/ip4/udp.hpp index 788c691233..6e148e21c4 100644 --- a/api/net/ip4/udp.hpp +++ b/api/net/ip4/udp.hpp @@ -122,10 +122,13 @@ namespace net { return stack_; } - // create packets from send queue + // send as much as possible from sendq + void flush(); + // create and transmit @num packets from sendq void process_sendq(size_t num); - private: + private: + downstream network_layer_out_; Stack& stack_; std::map ports_; diff --git a/api/net/ip4/udp_socket.hpp b/api/net/ip4/udp_socket.hpp index fcb03b20d4..834052553e 100644 --- a/api/net/ip4/udp_socket.hpp +++ b/api/net/ip4/udp_socket.hpp @@ -72,8 +72,6 @@ namespace net private: void packet_init(UDP::Packet_ptr, addr_t, addr_t, port_t, uint16_t); void internal_read(UDP::Packet_ptr); - void internal_write( - addr_t, addr_t, port_t, const uint8_t*, size_t, sendto_handler); Stack& stack; port_t l_port; diff --git a/src/net/ip4/udp.cpp b/src/net/ip4/udp.cpp index 795cd9dfb2..b2c6b5fe4a 100644 --- a/src/net/ip4/udp.cpp +++ b/src/net/ip4/udp.cpp @@ -93,6 +93,12 @@ namespace net { network_layer_out_(pckt); } + void UDP::flush() + { + size_t packets = stack_.transmit_queue_available(); + if (packets) process_sendq(packets); + } + void UDP::process_sendq(size_t num) { while (!sendq.empty() && num != 0) diff --git a/src/net/ip4/udp_socket.cpp b/src/net/ip4/udp_socket.cpp index bfbd4b2f52..b7ac45a768 100644 --- a/src/net/ip4/udp_socket.cpp +++ b/src/net/ip4/udp_socket.cpp @@ -43,26 +43,10 @@ namespace net void UDPSocket::internal_read(UDP::Packet_ptr udp) { - on_read_handler - (udp->src(), udp->src_port(), udp->data(), udp->data_length()); + on_read_handler( + udp->src(), udp->src_port(), udp->data(), udp->data_length()); } - void UDPSocket::internal_write( - addr_t srcIP, - addr_t destIP, - port_t port, - const uint8_t* data, - size_t length, - sendto_handler cb) - { - stack.udp().sendq.emplace_back( - data, length, cb, stack.udp(), - srcIP, this->l_port, destIP, port); - - size_t packets = stack.transmit_queue_available(); - if (packets) stack.udp().process_sendq(packets); - } // internal_write() - void UDPSocket::sendto( addr_t destIP, port_t port, @@ -70,8 +54,12 @@ namespace net size_t len, sendto_handler cb) { - internal_write(local_addr(), destIP, port, - (const uint8_t*) buffer, len, cb); + stack.udp().sendq.emplace_back( + (const uint8_t*) buffer, len, cb, stack.udp(), + local_addr(), this->l_port, destIP, port); + + // UDP packets are meant to be sent immediately, so try flushing + stack.udp().flush(); } void UDPSocket::bcast( addr_t srcIP, @@ -80,8 +68,12 @@ namespace net size_t len, sendto_handler cb) { - internal_write(srcIP, IP4::INADDR_BCAST, port, - (const uint8_t*) buffer, len, cb); + stack.udp().sendq.emplace_back( + (const uint8_t*) buffer, len, cb, stack.udp(), + srcIP, this->l_port, IP4::INADDR_BCAST, port); + + // UDP packets are meant to be sent immediately, so try flushing + stack.udp().flush(); } } From 2ebd131fb5d03ddc0ec12201665d12132cf65e63 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Sat, 9 Apr 2016 12:46:19 +0200 Subject: [PATCH 117/311] udp: Pass UDP instead of Inet to UDPSocket --- api/net/ip4/udp_socket.hpp | 8 +++----- src/net/ip4/udp.cpp | 2 +- src/net/ip4/udp_socket.cpp | 16 ++++++++-------- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/api/net/ip4/udp_socket.hpp b/api/net/ip4/udp_socket.hpp index 834052553e..c1ff815d48 100644 --- a/api/net/ip4/udp_socket.hpp +++ b/api/net/ip4/udp_socket.hpp @@ -30,13 +30,11 @@ namespace net typedef IP4::addr addr_t; typedef IP4::addr multicast_group_addr; - using Stack = Inet; - typedef delegate recvfrom_handler; typedef UDP::sendto_handler sendto_handler; // constructors - UDPSocket(Stack&, port_t port); + UDPSocket(UDP&, port_t port); UDPSocket(const UDPSocket&) = delete; // ^ DON'T USE THESE. We could create our own allocators just to prevent // you from creating sockets, but then everyone is wasting time. @@ -62,7 +60,7 @@ namespace net // stuff addr_t local_addr() const { - return stack.ip_addr(); + return udp.local_ip(); } port_t local_port() const { @@ -73,7 +71,7 @@ namespace net void packet_init(UDP::Packet_ptr, addr_t, addr_t, port_t, uint16_t); void internal_read(UDP::Packet_ptr); - Stack& stack; + UDP& udp; port_t l_port; recvfrom_handler on_read_handler = [] (addr_t, port_t, const char*, size_t) {}; diff --git a/src/net/ip4/udp.cpp b/src/net/ip4/udp.cpp index b2c6b5fe4a..ec288db2a2 100644 --- a/src/net/ip4/udp.cpp +++ b/src/net/ip4/udp.cpp @@ -60,7 +60,7 @@ namespace net { auto res = ports_.emplace( std::piecewise_construct, std::forward_as_tuple(port), - std::forward_as_tuple(stack_, port)); + std::forward_as_tuple(*this, port)); it = res.first; } return it->second; diff --git a/src/net/ip4/udp_socket.cpp b/src/net/ip4/udp_socket.cpp index b7ac45a768..f19e67ad92 100644 --- a/src/net/ip4/udp_socket.cpp +++ b/src/net/ip4/udp_socket.cpp @@ -20,8 +20,8 @@ namespace net { - UDPSocket::UDPSocket(UDPSocket::Stack& stk, port_t port) - : stack(stk), l_port(port) + UDPSocket::UDPSocket(UDP& udp_, port_t port) + : udp(udp_), l_port(port) {} void UDPSocket::packet_init( @@ -54,12 +54,12 @@ namespace net size_t len, sendto_handler cb) { - stack.udp().sendq.emplace_back( - (const uint8_t*) buffer, len, cb, stack.udp(), + udp.sendq.emplace_back( + (const uint8_t*) buffer, len, cb, this->udp, local_addr(), this->l_port, destIP, port); // UDP packets are meant to be sent immediately, so try flushing - stack.udp().flush(); + udp.flush(); } void UDPSocket::bcast( addr_t srcIP, @@ -68,12 +68,12 @@ namespace net size_t len, sendto_handler cb) { - stack.udp().sendq.emplace_back( - (const uint8_t*) buffer, len, cb, stack.udp(), + udp.sendq.emplace_back( + (const uint8_t*) buffer, len, cb, this->udp, srcIP, this->l_port, IP4::INADDR_BCAST, port); // UDP packets are meant to be sent immediately, so try flushing - stack.udp().flush(); + udp.flush(); } } From dd3cbaeb7f4d842e20d00630ca953e100cdafb9e Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Sat, 9 Apr 2016 12:48:16 +0200 Subject: [PATCH 118/311] test: Restore UDP test --- test/UDP/service.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/test/UDP/service.cpp b/test/UDP/service.cpp index bfc5151f4e..40eb05fc43 100644 --- a/test/UDP/service.cpp +++ b/test/UDP/service.cpp @@ -41,7 +41,6 @@ void Service::start() const UDP::port_t port = 4242; auto& sock = inet.udp().bind(port); - /* sock.on_read( [&sock] (UDP::addr_t addr, UDP::port_t port, const char* data, size_t len) @@ -52,11 +51,9 @@ void Service::start() // send the same thing right back! sock.sendto(addr, port, data, len, [] { - // sent - INFO("UDP test", "SUCCESS"); }); - });*/ + }); INFO("UDP test", "Listening on port %d\n", port); } From e960739eb7d6e31d306189d62c91331c55576d4d Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sat, 9 Apr 2016 20:41:59 +0200 Subject: [PATCH 119/311] Added GSL test --- test/GSL/Makefile | 22 ++++++ test/GSL/README.md | 7 ++ test/GSL/run.sh | 3 + test/GSL/service.cpp | 173 +++++++++++++++++++++++++++++++++++++++++++ test/GSL/test.sh | 5 ++ 5 files changed, 210 insertions(+) create mode 100644 test/GSL/Makefile create mode 100644 test/GSL/README.md create mode 100755 test/GSL/run.sh create mode 100644 test/GSL/service.cpp create mode 100755 test/GSL/test.sh diff --git a/test/GSL/Makefile b/test/GSL/Makefile new file mode 100644 index 0000000000..61014aa23f --- /dev/null +++ b/test/GSL/Makefile @@ -0,0 +1,22 @@ +################################################# +# IncludeOS SERVICE makefile # +################################################# + +# The name of your service +SERVICE = test_GSL +SERVICE_NAME = C++ Core Guideline Support Library Tests + +# Your service parts +FILES = service.cpp + +LOCAL_INCLUDES=-I$(PWD)/../../mod/GSL/include -I$(PWD)/../lest/include/lest + +# Your disk image +DISK= + +# IncludeOS location +ifndef INCLUDEOS_INSTALL +INCLUDEOS_INSTALL=$(HOME)/IncludeOS_install +endif + +include $(INCLUDEOS_INSTALL)/Makeseed diff --git a/test/GSL/README.md b/test/GSL/README.md new file mode 100644 index 0000000000..da05daa283 --- /dev/null +++ b/test/GSL/README.md @@ -0,0 +1,7 @@ +# Test basics of C++ Core Guidelines Support Library +This just tests a fraction of GSL functionality, but it's here to just verify that basic GSL support is in place and working in IncludeOS. + +Sucess: Outputs SUCCESS if all tests pass +Fail: Panic if any test fails + +NOTE: This test uses the `lest` unit test framework as well for some tests. The result of those tests will also be reported. diff --git a/test/GSL/run.sh b/test/GSL/run.sh new file mode 100755 index 0000000000..3b2132d2cb --- /dev/null +++ b/test/GSL/run.sh @@ -0,0 +1,3 @@ +#! /bin/bash +source ${INCLUDEOS_HOME-$HOME/IncludeOS_install}/etc/run.sh + diff --git a/test/GSL/service.cpp b/test/GSL/service.cpp new file mode 100644 index 0000000000..22fdf54a62 --- /dev/null +++ b/test/GSL/service.cpp @@ -0,0 +1,173 @@ +// This file is a part of the IncludeOS unikernel - www.includeos.org +// +// Copyright 2015 Oslo and Akershus University College of Applied Sciences +// and Alfred Bratterud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + A very superficial test to verify that basic STL is working + This is useful when we mess with / replace STL implementations + +**/ + + +#include +#include + +#define GSL_THROW_ON_CONTRACT_VIOLATION +#include +#include + + +int clock_gettime(clockid_t clk_id, struct timespec *tp){ +(void*)clk_id; +(void*)tp; +return 0; +}; + + +#define MYINFO(X,...) INFO("Test GSL",X,##__VA_ARGS__) + +static int divcount_ = 0; + +const lest::test test_basic_gsl[] = { + { + + SCENARIO ("Basic Expects / Ensures behave as expected") { + + GIVEN ("A simple division function, requiring positive integers") { + + class Math { + public: + static int div (int x, int y) { + Expects( y > 0 ); + + int prevcount_ = divcount_; + + auto result = x / y; + divcount_++; + + Ensures(result == x / y); + Ensures(divcount_ > 0); + Ensures(divcount_ == prevcount_ + 1); + + return result; + + } + }; + + WHEN ("y is zero") { + int y = 0; + + THEN ("Division by y throws") { + EXPECT_THROWS( Math::div(100, y) ); + } + + } + + WHEN ("y is positive") { + int y = 4; + + THEN ("Division by y doesn't throw") { + EXPECT_NO_THROW( Math::div(100, y) ); + } + + AND_THEN("Division gives the correct result"){ + EXPECT( Math::div(100,y) == 100 / y ); + } + } + + WHEN ("y is negative"){ + int y = -90; + + THEN ("Divsion by y throws") {} + EXPECT_THROWS( Math::div(100, y) ); + + AND_THEN("Division should have succeeded twice"){ + EXPECT(divcount_ == 2); + } + } + } + } + }, + + { + SCENARIO("We can use span to replace pointer-and-size interfaces") { + + GIVEN ("A (member) function with a span parameter") { + + class Mem { + public: + static unsigned int count(gsl::span chars){ + + int i = 0; + for ( auto c : chars ) { + printf("%c ", c); + i++; + } + + printf("\n"); + return i; + } + + + }; + + + WHEN ("We pass a raw pointer") { + char* name = (char*)"Bjarne Stroustrup"; + + THEN("if we lie to the about our size, span can't save us from overflow / underflow") { + EXPECT( Mem::count({name, 100}) != std::string(name).size()); + EXPECT( Mem::count({name, 10}) != std::string(name).size()); + } + + AND_THEN("If callee keeps track of the size, it will still work"){ + EXPECT( Mem::count({name, 17}) == std::string(name).size()); + } + } + + WHEN ("We use std::array") { + std::array my_array {'G','S','L',' ','l','o', 'o', 'k', 's', ' ', 'n', 'i', 'c', 'e'}; + THEN("we're perfectly safe"){ + EXPECT( Mem::count(my_array) == my_array.size() ); + } + } + + WHEN ("We use normal array") { + char str2 [] = {49, 50, 51, 52, 53}; + + THEN ("Span helps us avoid decay to pointer") { + EXPECT( Mem::count(str2) == sizeof(str2)); + } + } + } + } + } +}; + +void Service::start() +{ + + // Lest takes command line params + char* argv[2] = {(char*)"test", (char*)"-p"}; + + auto failed = lest::run(test_basic_gsl, 2, argv); + + assert(not failed); + + MYINFO("SUCCESS"); + + +} diff --git a/test/GSL/test.sh b/test/GSL/test.sh new file mode 100755 index 0000000000..90b11cea18 --- /dev/null +++ b/test/GSL/test.sh @@ -0,0 +1,5 @@ +#!/bin/bash +source ../test_base + +make +start test_GSL.img From 8d1d481179214e1b98aaffafe6f696363f5e4ffa Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sun, 10 Apr 2016 00:26:20 +0200 Subject: [PATCH 120/311] Updated GSL-test to verify bounds checking on span --- test/GSL/service.cpp | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/test/GSL/service.cpp b/test/GSL/service.cpp index 22fdf54a62..f65d12b1ee 100644 --- a/test/GSL/service.cpp +++ b/test/GSL/service.cpp @@ -124,7 +124,6 @@ const lest::test test_basic_gsl[] = { }; - WHEN ("We pass a raw pointer") { char* name = (char*)"Bjarne Stroustrup"; @@ -133,9 +132,10 @@ const lest::test test_basic_gsl[] = { EXPECT( Mem::count({name, 10}) != std::string(name).size()); } - AND_THEN("If callee keeps track of the size, it will still work"){ + AND_THEN("If caller keeps track of the size, it will still work"){ EXPECT( Mem::count({name, 17}) == std::string(name).size()); } + } WHEN ("We use std::array") { @@ -153,6 +153,35 @@ const lest::test test_basic_gsl[] = { } } } + + GIVEN ("A (Bad) span-interface that doesn't do any bounds checking") { + + class Bad { + public: + static unsigned char eighth(gsl::span chars){ + return chars[8]; + } + }; + + WHEN ("we pass in sufficient data") { + char* character = (char*) "Bjarne \"Yoda\" Stroustrup leas the Jedi council with wisdom"; + THEN("you can access the elements of the span using the index operator"){ + EXPECT(Bad::eighth({character, 20}) == 'Y'); + } + + } + + WHEN ("we pass in too little data") { + char* character = (char*) "Yoda"; + THEN("span saves us from complete embarrasment") { + EXPECT_THROWS(Bad::eighth({character, 4})); + } + + } + + } + + } } }; From 50c497447334b8a96c9cd68398f29c0e415c2c3f Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Sun, 10 Apr 2016 18:57:29 +0200 Subject: [PATCH 121/311] udp: Fixed udp sendq and wrote test for UDP spam --- src/debug/test_service.cpp | 23 ++++++++++++++++++++--- src/net/ip4/udp.cpp | 33 ++++++++++++++++++++++++--------- 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/src/debug/test_service.cpp b/src/debug/test_service.cpp index f5623836b8..389eb6ff2d 100644 --- a/src/debug/test_service.cpp +++ b/src/debug/test_service.cpp @@ -85,9 +85,26 @@ void Service::start() addr.str().c_str(), port, strdata.c_str()); // send the same thing right back! sock.sendto(addr, port, data, len, - [] { - // sent - INFO("UDP test", "SUCCESS"); + [&sock, addr, port] + { + // print this message once + printf("*** Starting spam (you should see this once)\n"); + + typedef std::function rnd_gen_t; + auto next = std::make_shared (); + + *next = + [next, &sock, addr, port] () + { + // spam this message at max speed + std::string text("Spamorino Cappucino\n"); + + sock.sendto(addr, port, text.data(), text.size(), + [next] { (*next)(); }); + }; + + // start spamming + (*next)(); }); }); diff --git a/src/net/ip4/udp.cpp b/src/net/ip4/udp.cpp index ec288db2a2..8b126eb57e 100644 --- a/src/net/ip4/udp.cpp +++ b/src/net/ip4/udp.cpp @@ -21,6 +21,9 @@ #include #include +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) + namespace net { UDP::UDP(Stack& inet) @@ -33,7 +36,6 @@ namespace net { void UDP::bottom(net::Packet_ptr pckt) { - debug(" Got data"); std::shared_ptr udp = std::static_pointer_cast (pckt); @@ -42,11 +44,12 @@ namespace net { auto it = ports_.find(udp->dst_port()); if (it != ports_.end()) - { - debug(" Someone's listening to this port. Forwarding...\n"); - it->second.internal_read(udp); - } - + { + debug(" Someone's listening to this port. Forwarding...\n"); + it->second.internal_read(udp); + return; + } + debug(" Nobody's listening to this port. Drop!\n"); } @@ -55,7 +58,7 @@ namespace net { debug(" Binding to port %i\n", port); /// ... !!! auto it = ports_.find(port); - if (it == ports_.end()) { + if (likely(it == ports_.end())) { // create new socket auto res = ports_.emplace( std::piecewise_construct, @@ -104,16 +107,28 @@ namespace net { while (!sendq.empty() && num != 0) { WriteBuffer& buffer = sendq.front(); + // ignore empty or finished writes + if (unlikely(buffer.done())) + { + printf("process_sendq: removing empty buffer\n"); + sendq.pop_front(); + continue; + } + // create and transmit packet from writebuffer buffer.write(); num--; if (buffer.done()) { - // call on_written callback - buffer.callback(); + auto copy = buffer.callback; // remove buffer from queue sendq.pop_front(); + // call on_written callback + copy(); + // refresh @num, just in case packets were sent in + // another stack frame + num = stack_.transmit_queue_available(); } } } From e2aedf3f72e9ff1da6e152a824a1cede116d06de Mon Sep 17 00:00:00 2001 From: RicoAntonioFelix Date: Sun, 10 Apr 2016 12:59:16 -0400 Subject: [PATCH 122/311] Refactored MemDisk... --- api/fs/memdisk.hpp | 38 ++++++++++++------------- src/fs/memdisk.cpp | 69 ++++++++++++++++++++++------------------------ 2 files changed, 51 insertions(+), 56 deletions(-) diff --git a/api/fs/memdisk.hpp b/api/fs/memdisk.hpp index cab44d12f2..d11b4557f3 100644 --- a/api/fs/memdisk.hpp +++ b/api/fs/memdisk.hpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -28,33 +28,31 @@ namespace fs { class MemDisk : public hw::IDiskDevice { public: static constexpr size_t SECTOR_SIZE = 512; - + MemDisk() noexcept; - + + virtual const char* name() const noexcept override + { return "MemDisk"; } + + virtual block_t size() const noexcept override; + /** Returns the optimal block size for this device. */ virtual block_t block_size() const noexcept override { return SECTOR_SIZE; } - - virtual const char* name() const noexcept override - { - return "MemDisk"; - } - - virtual void + + virtual void read(block_t blk, on_read_func reader) override; - - virtual void + + virtual void read(block_t start, block_t cnt, on_read_func reader) override; - + virtual buffer_t read_sync(block_t blk) override; - - virtual block_t size() const noexcept override; - + private: - void* image_start; - void* image_end; + const char* image_start_; + const char* image_end_; }; //< class MemDisk - + } //< namespace fs #endif //< FS_MEMDISK_HPP diff --git a/src/fs/memdisk.cpp b/src/fs/memdisk.cpp index 967f39208c..84fe6c3148 100644 --- a/src/fs/memdisk.cpp +++ b/src/fs/memdisk.cpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -32,54 +32,51 @@ extern "C" { namespace fs { MemDisk::MemDisk() noexcept - : image_start { &_DISK_START_ }, - image_end { &_DISK_END_ } -{} + : image_start_ { &_DISK_START_ }, + image_end_ { &_DISK_END_ } + {} - void MemDisk::read(block_t blk, on_read_func callback) { - auto* sector_loc = ((char*) image_start) + blk * block_size(); + void MemDisk::read(block_t blk, on_read_func reader) { + auto sector_loc = image_start_ + (blk * block_size()); // Disallow reading memory past disk image - if (unlikely(sector_loc >= image_end)) - { - callback(buffer_t()); return; - } - - auto* buffer = new uint8_t[block_size()]; + if (unlikely(sector_loc >= image_end_)) { + reader(buffer_t()); return; + } + + auto buffer = new uint8_t[block_size()]; assert( memcpy(buffer, sector_loc, block_size()) == buffer ); - - callback( buffer_t(buffer, std::default_delete()) ); + + reader( buffer_t(buffer, std::default_delete()) ); } - void MemDisk::read(block_t start, block_t count, on_read_func callback) { - auto* start_loc = ((char*) image_start) + start * block_size(); - auto* end_loc = start_loc + count * block_size(); + void MemDisk::read(block_t blk, block_t count, on_read_func reader) { + auto start_loc = image_start_ + (blk * block_size()); + auto end_loc = start_loc + (count * block_size()); // Disallow reading memory past disk image - if (unlikely(end_loc >= image_end)) - { - callback(buffer_t()); return; - } - - auto* buffer = new uint8_t[count * block_size()]; + if (unlikely(end_loc >= image_end_)) { + reader(buffer_t()); return; + } + + auto buffer = new uint8_t[count * block_size()]; assert( memcpy(buffer, start_loc, count * block_size()) == buffer ); - - callback( buffer_t(buffer, std::default_delete()) ); + + reader( buffer_t(buffer, std::default_delete()) ); } - MemDisk::buffer_t MemDisk::read_sync(block_t blk) - { - auto* loc = ((char*) image_start) + blk * block_size(); + MemDisk::buffer_t MemDisk::read_sync(block_t blk) { + auto sector_loc = image_start_ + (blk * block_size()); // Disallow reading memory past disk image - if (unlikely(loc >= image_end)) + if (unlikely(sector_loc >= image_end_)) return buffer_t(); - - auto* buffer = new uint8_t[block_size()]; - assert( memcpy(buffer, loc, block_size()) == buffer ); - + + auto buffer = new uint8_t[block_size()]; + assert( memcpy(buffer, sector_loc, block_size()) == buffer ); + return buffer_t(buffer, std::default_delete()); } MemDisk::block_t MemDisk::size() const noexcept { - return ((char*) image_end - (char*) image_start) / SECTOR_SIZE; + return (image_end_ - image_start_) / SECTOR_SIZE; } - + } //< namespace fs From a9e9c83d3b2fc828aa31a0de42965f9827573502 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Sun, 10 Apr 2016 19:01:39 +0200 Subject: [PATCH 123/311] udp: sendq - Prevent using more packets than given, socket - Prevent adding empty buffer to sendq --- src/net/ip4/udp.cpp | 12 +++--------- src/net/ip4/udp_socket.cpp | 33 +++++++++++++++++++++------------ 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/src/net/ip4/udp.cpp b/src/net/ip4/udp.cpp index 8b126eb57e..7aa8922dca 100644 --- a/src/net/ip4/udp.cpp +++ b/src/net/ip4/udp.cpp @@ -107,13 +107,6 @@ namespace net { while (!sendq.empty() && num != 0) { WriteBuffer& buffer = sendq.front(); - // ignore empty or finished writes - if (unlikely(buffer.done())) - { - printf("process_sendq: removing empty buffer\n"); - sendq.pop_front(); - continue; - } // create and transmit packet from writebuffer buffer.write(); @@ -126,9 +119,10 @@ namespace net { sendq.pop_front(); // call on_written callback copy(); - // refresh @num, just in case packets were sent in + // reduce @num, just in case packets were sent in // another stack frame - num = stack_.transmit_queue_available(); + size_t avail = stack_.transmit_queue_available(); + num = (num > avail) ? avail : num; } } } diff --git a/src/net/ip4/udp_socket.cpp b/src/net/ip4/udp_socket.cpp index f19e67ad92..193997a301 100644 --- a/src/net/ip4/udp_socket.cpp +++ b/src/net/ip4/udp_socket.cpp @@ -18,6 +18,9 @@ #include #include +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) + namespace net { UDPSocket::UDPSocket(UDP& udp_, port_t port) @@ -54,12 +57,15 @@ namespace net size_t len, sendto_handler cb) { - udp.sendq.emplace_back( - (const uint8_t*) buffer, len, cb, this->udp, - local_addr(), this->l_port, destIP, port); - - // UDP packets are meant to be sent immediately, so try flushing - udp.flush(); + if (likely(len)) + { + udp.sendq.emplace_back( + (const uint8_t*) buffer, len, cb, this->udp, + local_addr(), this->l_port, destIP, port); + + // UDP packets are meant to be sent immediately, so try flushing + udp.flush(); + } } void UDPSocket::bcast( addr_t srcIP, @@ -68,12 +74,15 @@ namespace net size_t len, sendto_handler cb) { - udp.sendq.emplace_back( - (const uint8_t*) buffer, len, cb, this->udp, - srcIP, this->l_port, IP4::INADDR_BCAST, port); - - // UDP packets are meant to be sent immediately, so try flushing - udp.flush(); + if (likely(len)) + { + udp.sendq.emplace_back( + (const uint8_t*) buffer, len, cb, this->udp, + srcIP, this->l_port, IP4::INADDR_BCAST, port); + + // UDP packets are meant to be sent immediately, so try flushing + udp.flush(); + } } } From b5188110aa9ed701461149e4a2ce424d9110fac8 Mon Sep 17 00:00:00 2001 From: RicoAntonioFelix Date: Sun, 10 Apr 2016 14:34:41 -0400 Subject: [PATCH 124/311] Corrected typographical error... --- test/GSL/service.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/GSL/service.cpp b/test/GSL/service.cpp index f65d12b1ee..e12122f254 100644 --- a/test/GSL/service.cpp +++ b/test/GSL/service.cpp @@ -164,7 +164,7 @@ const lest::test test_basic_gsl[] = { }; WHEN ("we pass in sufficient data") { - char* character = (char*) "Bjarne \"Yoda\" Stroustrup leas the Jedi council with wisdom"; + char* character = (char*) "Bjarne \"Yoda\" Stroustrup leads the Jedi council with wisdom"; THEN("you can access the elements of the span using the index operator"){ EXPECT(Bad::eighth({character, 20}) == 'Y'); } From ba0a57d284c6404ef4e11028d80c202daaac6d23 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Mon, 11 Apr 2016 13:49:57 +0200 Subject: [PATCH 125/311] udp: Cleanup --- api/net/inet4.hpp | 1 - src/debug/test_service.cpp | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/api/net/inet4.hpp b/api/net/inet4.hpp index 5d16dbed7a..ce3e259428 100644 --- a/api/net/inet4.hpp +++ b/api/net/inet4.hpp @@ -133,7 +133,6 @@ namespace net { virtual void on_transmit_queue_available(transmit_avail_delg del) override { tqa.push_back(del); - printf("* adding transmit listener (sz=%u)\n", tqa.size() ); } virtual size_t transmit_queue_available() override { diff --git a/src/debug/test_service.cpp b/src/debug/test_service.cpp index 389eb6ff2d..0a156756d7 100644 --- a/src/debug/test_service.cpp +++ b/src/debug/test_service.cpp @@ -31,10 +31,10 @@ void Service::start() hw::Nic& eth0 = hw::Dev::eth<0,VirtioNet>(); inet = std::make_unique >(eth0); inet->network_config( - {{ 10,0,0,42 }}, // IP - {{ 255,255,255,0 }}, // Netmask - {{ 10,0,0,1 }}, // Gateway - {{ 8,8,8,8 }} ); // DNS + {{ 10,0,0,42 }}, // IP + {{ 255,255,255,0 }}, // Netmask + {{ 10,0,0,1 }}, // Gateway + {{ 8,8,8,8 }} ); // DNS /* auto& tcp = inet->tcp(); From 015f1a5907ca5aee66efdf118412055767443199 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Mon, 11 Apr 2016 14:40:32 +0200 Subject: [PATCH 126/311] Virtionet bufsize now takes ethernet header into account --- api/virtio/virtionet.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/api/virtio/virtionet.hpp b/api/virtio/virtionet.hpp index 0abd435f80..794ff9f6e4 100644 --- a/api/virtio/virtionet.hpp +++ b/api/virtio/virtionet.hpp @@ -123,7 +123,9 @@ class VirtioNet : Virtio { return 1500; } constexpr uint16_t bufsize() const { - return MTU() + sizeof(virtio_net_hdr); } + return MTU() + + sizeof(net::Ethernet::header) + sizeof(net::Ethernet::trailer) + + sizeof(virtio_net_hdr); } /** Delegate linklayer output. Hooks into IP-stack bottom, w.UPSTREAM data. */ inline void set_linklayer_out(net::upstream link_out){ From e014d280d79cd99405fa87b87deadb8a2f0ea1de Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Mon, 11 Apr 2016 14:43:45 +0200 Subject: [PATCH 127/311] Lest now taks command line params as vector --- test/GSL/service.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/GSL/service.cpp b/test/GSL/service.cpp index f65d12b1ee..fb0eb349c1 100644 --- a/test/GSL/service.cpp +++ b/test/GSL/service.cpp @@ -189,10 +189,8 @@ const lest::test test_basic_gsl[] = { void Service::start() { - // Lest takes command line params - char* argv[2] = {(char*)"test", (char*)"-p"}; - - auto failed = lest::run(test_basic_gsl, 2, argv); + // Lest takes command line params as vector + auto failed = lest::run(test_basic_gsl, {"-p"}); assert(not failed); From 6f83b5a65e3ea9f189ee534810a8a7c9b5d76084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Mon, 11 Apr 2016 14:45:14 +0200 Subject: [PATCH 128/311] net: calculating MTU/segment size layer by layer --- api/net/inet.hpp | 2 +- api/net/inet4.hpp | 2 +- api/net/ip4/ip4.hpp | 52 +++++++++++++++++++++++++-------------------- api/net/tcp.hpp | 12 +++++------ 4 files changed, 37 insertions(+), 31 deletions(-) diff --git a/api/net/inet.hpp b/api/net/inet.hpp index 71834b517c..33b4823e25 100644 --- a/api/net/inet.hpp +++ b/api/net/inet.hpp @@ -47,7 +47,7 @@ namespace net { virtual std::shared_ptr dhclient() = 0; - virtual uint16_t MTU() const = 0; + virtual constexpr uint16_t MTU() const = 0; virtual Packet_ptr createPacket(size_t size) = 0; diff --git a/api/net/inet4.hpp b/api/net/inet4.hpp index 5d16dbed7a..6fe534ed45 100644 --- a/api/net/inet4.hpp +++ b/api/net/inet4.hpp @@ -148,7 +148,7 @@ namespace net { inline void process_sendq(size_t); // delegates registered to get signalled about free packets std::vector tqa; - + IP4::addr ip4_addr_; IP4::addr netmask_; IP4::addr router_; diff --git a/api/net/ip4/ip4.hpp b/api/net/ip4/ip4.hpp index 2a369e8716..0009be70f0 100644 --- a/api/net/ip4/ip4.hpp +++ b/api/net/ip4/ip4.hpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -35,15 +35,15 @@ namespace net { public: /** Initialize. Sets a dummy linklayer out. */ explicit IP4(Inet&) noexcept; - + /** Known transport layer protocols. */ enum proto { IP4_ICMP=1, IP4_UDP=17, IP4_TCP=6 }; - + /** IP4 address representation */ union __attribute__((packed)) addr { uint8_t part[4]; uint32_t whole; - + /** * NOTE: Constructors * Can't have them - removes the packed-attribute @@ -53,14 +53,14 @@ namespace net { whole = cpy.whole; return *this; } - + /** Standard comparison operators */ inline bool operator==(addr rhs) const noexcept { return whole == rhs.whole; } inline bool operator==(const uint32_t rhs) const noexcept { return whole == rhs; } - + inline bool operator<(const addr rhs) const noexcept { return whole < rhs.whole; } @@ -72,25 +72,25 @@ namespace net { inline bool operator>(const uint32_t rhs) const noexcept { return whole > rhs; } - + inline bool operator!=(const addr rhs) const noexcept { return whole != rhs.whole; } - + inline bool operator!=(const uint32_t rhs) const noexcept { return whole != rhs; } - + /** x.x.x.x string representation */ std::string str() const { char ip_addr[16]; sprintf(ip_addr, "%1i.%1i.%1i.%1i", part[0], part[1], part[2], part[3]); return ip_addr; - } + } }; //< union addr - + static const addr INADDR_ANY; static const addr INADDR_BCAST; - + /** IP4 header representation */ struct ip_header { uint8_t version_ihl; @@ -114,27 +114,33 @@ namespace net { uint8_t link_hdr[sizeof(typename LinkLayer::header)]; ip_header ip_hdr; }; - + + /* + Maximum Datagram Data Size + */ + inline constexpr uint16_t MDDS() const + { return stack_.MTU() - sizeof(ip_header); } + /** Upstream: Input from link layer */ void bottom(Packet_ptr); - + /** Upstream: Outputs to transport layer */ inline void set_icmp_handler(upstream s) { icmp_handler_ = s; } - + inline void set_udp_handler(upstream s) { udp_handler_ = s; } - + inline void set_tcp_handler(upstream s) { tcp_handler_ = s; } - + /** Downstream: Delegate linklayer out */ void set_linklayer_out(downstream s) { linklayer_out_ = s; }; /** * Downstream: Receive data from above and transmit - * + * * @note: The following *must be set* in the packet: * * * Destination IP @@ -146,7 +152,7 @@ namespace net { /** Compute the IP4 header checksum */ uint16_t checksum(ip_header*); - + /** * \brief * @@ -155,13 +161,13 @@ namespace net { const addr local_ip() const { return stack_.ip_addr(); } - + private: Inet& stack_; - + /** Downstream: Linklayer output delegate */ downstream linklayer_out_ {ignore_ip4_down}; - + /** Upstream delegates */ upstream icmp_handler_ {ignore_ip4_up}; upstream udp_handler_ {ignore_ip4_up}; diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index 4256fb37c1..4a20bbb4a4 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -1276,7 +1276,7 @@ namespace net { inline int32_t usable_window() const { auto x = (int64_t)control_block.SND.UNA + (int64_t)control_block.SND.WND - (int64_t)control_block.SND.NXT; - return (int32_t) x; + return std::min((int32_t) x, (int32_t)control_block.SND.cwnd); } /// Congestion Control [RFC 5681] /// @@ -1293,8 +1293,8 @@ namespace net { return control_block.SND.NXT - control_block.SND.UNA; } - inline void init_cwnd() { - control_block.SND.cwnd = 10*SMSS(); + inline void init_cwnd(uint32_t segments) { + control_block.SND.cwnd = segments*SMSS(); } inline void reduce_slow_start_threshold() { @@ -1483,14 +1483,14 @@ namespace net { @NOTE: Currently not supporting MTU bigger than 1482 bytes. */ - inline uint16_t MSS() const { + inline constexpr uint16_t MSS() const { /* VirtulaBox "issue": MTU > 1498 will break TCP. MTU > 1482 seems to cause fragmentation: https://www.virtualbox.org/ticket/13967 */ - const uint16_t VBOX_LIMIT = 1482; - return std::min(inet_.MTU(), VBOX_LIMIT) - sizeof(Full_header::ip4) - sizeof(TCP::Header); + //const uint16_t VBOX_LIMIT = 1482; + return inet_.ip_obj().MDDS() - sizeof(TCP::Header); } /* From 4792c7d4eb016697d41e2b4c996da8b80d19f109 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Mon, 11 Apr 2016 14:49:29 +0200 Subject: [PATCH 129/311] Added ethernet trailer type (for CRC, but mostly to get the right bufsize) --- api/net/ethernet.hpp | 62 +++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/api/net/ethernet.hpp b/api/net/ethernet.hpp index dcf7acdb40..8dc1e20c40 100644 --- a/api/net/ethernet.hpp +++ b/api/net/ethernet.hpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -33,14 +33,14 @@ namespace net { /** * Some big-endian ethernet types - * + * * From http://en.wikipedia.org/wiki/EtherType */ enum ethertype_le { _ETH_IP4 = 0x0800, - _ETH_ARP = 0x0806, + _ETH_ARP = 0x0806, _ETH_WOL = 0x0842, - _ETH_IP6 = 0x86DD, + _ETH_IP6 = 0x86DD, _ETH_FLOW = 0x8808, _ETH_JUMBO = 0x8870 }; @@ -59,18 +59,18 @@ namespace net { // MAC address union addr { uint8_t part[ETHER_ADDR_LEN]; - + struct { uint16_t minor; uint32_t major; } __attribute__((packed)); - + addr& operator=(const addr cpy) noexcept { minor = cpy.minor; major = cpy.major; return *this; } - + // hex string representation std::string str() const { char eth_addr[17]; @@ -79,64 +79,66 @@ namespace net { part[3], part[4], part[5]); return eth_addr; } - + /** Check for equality */ bool operator==(const addr mac) const noexcept { return strncmp( - reinterpret_cast(part), - reinterpret_cast(mac.part), + reinterpret_cast(part), + reinterpret_cast(mac.part), ETHER_ADDR_LEN) == 0; } - + static const addr MULTICAST_FRAME; static const addr BROADCAST_FRAME; - + static const addr IPv6mcast_01; static const addr IPv6mcast_02; - + } __attribute__((packed)); //< union addr - + /** Constructor */ explicit Ethernet(addr mac) noexcept; - + struct header { addr dest; addr src; unsigned short type; - + } __attribute__((packed)) ; - + + using trailer = uint32_t; + /** Bottom upstream input, "Bottom up". Handle raw ethernet buffer. */ void bottom(Packet_ptr); - + /** Delegate upstream ARP handler. */ void set_arp_handler(upstream del) { arp_handler_ = del; } - + upstream get_arp_handler() { return arp_handler_; } - + /** Delegate upstream IPv4 handler. */ void set_ip4_handler(upstream del) { ip4_handler_ = del; } - + /** Delegate upstream IPv4 handler. */ upstream get_ip4_handler() { return ip4_handler_; } - + /** Delegate upstream IPv6 handler. */ void set_ip6_handler(upstream del) - { ip6_handler_ = del; }; - + { ip6_handler_ = del; }; + /** Delegate downstream */ void set_physical_out(downstream del) { physical_out_ = del; } - + /** @return Mac address of the underlying device */ const addr mac() const noexcept { return mac_; } - + /** Transmit data, with preallocated space for eth.header */ void transmit(Packet_ptr); @@ -148,18 +150,18 @@ namespace net { upstream ip4_handler_ = [](Packet_ptr){}; upstream ip6_handler_ = [](Packet_ptr){}; upstream arp_handler_ = [](Packet_ptr){}; - + /** Downstream OUTPUT connection */ downstream physical_out_ = [](Packet_ptr){}; /* - + +--|IP4|---|ARP|---|IP6|---+ | | | Ethernet | | | +---------|Phys|-----------+ - + */ }; //< class Ethernet } // namespace net From d9f03aa24f3aaa964ef7c485febce6f20bf57a14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Mon, 11 Apr 2016 16:47:52 +0200 Subject: [PATCH 130/311] net: calculation of MTU and buffer size corrected --- api/net/packet.hpp | 4 +--- api/net/tcp.hpp | 16 ++++++---------- src/virtio/virtionet.cpp | 6 +++--- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/api/net/packet.hpp b/api/net/packet.hpp index 0d13519af2..c8244655a4 100644 --- a/api/net/packet.hpp +++ b/api/net/packet.hpp @@ -29,8 +29,6 @@ namespace net { class Packet : public std::enable_shared_from_this { public: - static constexpr size_t MTU {1500}; - using release_del = BufferStore::release_del; /** @@ -120,7 +118,7 @@ namespace net { protected: BufferStore::buffer_t payload_ {nullptr}; BufferStore::buffer_t buf_ {nullptr}; - size_t capacity_ {MTU}; // NOTE: Actual value is provided by BufferStore + size_t capacity_ {0}; // NOTE: Actual value is provided by BufferStore size_t size_ {0}; IP4::addr next_hop4_ {}; private: diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index 4a20bbb4a4..3cae9eb458 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -1386,7 +1386,7 @@ namespace net { (Limit the size for outgoing packets) */ inline uint16_t MSDS() const { - return std::min(host_.MSS(), control_block.SND.MSS); + return std::min(host_.MSS(), control_block.SND.MSS) + sizeof(TCP::Header); } /* @@ -1480,17 +1480,9 @@ namespace net { /* Maximum Segment Size [RFC 793] [RFC 879] [RFC 6691] - - @NOTE: Currently not supporting MTU bigger than 1482 bytes. */ inline constexpr uint16_t MSS() const { - /* - VirtulaBox "issue": - MTU > 1498 will break TCP. - MTU > 1482 seems to cause fragmentation: https://www.virtualbox.org/ticket/13967 - */ - //const uint16_t VBOX_LIMIT = 1482; - return inet_.ip_obj().MDDS() - sizeof(TCP::Header); + return network().MDDS() - sizeof(TCP::Header); } /* @@ -1564,6 +1556,10 @@ namespace net { process_write_queue(inet_.transmit_queue_available()); } + inline IP4& network() const { + return inet_.ip_obj(); + } + }; // < class TCP diff --git a/src/virtio/virtionet.cpp b/src/virtio/virtionet.cpp index daf305396b..3a03c23b97 100644 --- a/src/virtio/virtionet.cpp +++ b/src/virtio/virtionet.cpp @@ -119,7 +119,7 @@ VirtioNet::VirtioNet(hw::PCI_Device& d) // Step 3 - Fill receive queue with buffers // DEBUG: Disable INFO("VirtioNet", "Adding %i receive buffers of size %i", - rx_q.size() / 2, Packet::MTU+sizeof(virtio_net_hdr)); + rx_q.size() / 2, bufsize()); for (int i = 0; i < rx_q.size() / 2; i++) add_receive_buffer(); @@ -177,7 +177,7 @@ int VirtioNet::add_receive_buffer(){ //sg[0].data = (void*)&empty_header; sg[0].size = sizeof(virtio_net_hdr); sg[1].data = buf + sizeof(virtio_net_hdr); - sg[1].size = Packet::MTU; + sg[1].size = bufsize()-sizeof(virtio_net_hdr); rx_q.enqueue(sg, 0, 2,buf); return 0; @@ -241,7 +241,7 @@ void VirtioNet::service_queues(){ auto pckt_ptr = std::make_shared (data+sizeof(virtio_net_hdr), // Offset buffer (bufstore knows the offseto) - MTU(), // Capacity + bufsize()-sizeof(virtio_net_hdr), // Capacity len - sizeof(virtio_net_hdr), release_buffer); // Size _link_out(pckt_ptr); From 02bf9140cfcb122e5d259b5d4bc35cf756ebe732 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Mon, 11 Apr 2016 19:50:51 +0200 Subject: [PATCH 131/311] Updated transmit test to use new UDP interface --- test/transmit/service.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/test/transmit/service.cpp b/test/transmit/service.cpp index c9cad0a578..ab7eb9d1b7 100644 --- a/test/transmit/service.cpp +++ b/test/transmit/service.cpp @@ -45,10 +45,10 @@ void Service::start() // UDP UDP::port_t port = 4242; - auto& sock = inet->udp().bind(port); + auto& conn = inet->udp().bind(port); - sock.onRead([&] (UDP::Socket& conn, UDP::addr_t addr, UDP::port_t port, - const char* data, int len) -> int { + conn.on_read([&] (UDP::addr_t addr, UDP::port_t port, + const char* data, int len) { string received = std::string(data,len-1); INFO("Test 2","Starting UDP-test (got UDP data from %s: %i: '%s')", addr.str().c_str(), port, received.c_str()); @@ -78,8 +78,6 @@ void Service::start() INFO("Transmision tests","SUCCESS"); }); - return 0; - }); eth0.on_transmit_queue_available([](size_t s){ From 0d9dc6b3cd890ffaee9c962665fe386116933e3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Tue, 12 Apr 2016 09:50:23 +0200 Subject: [PATCH 132/311] tcp: removed default parameter on write to avoid ambigous function call --- api/net/tcp.hpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index 3cae9eb458..76bad7f6e2 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -874,34 +874,34 @@ namespace net { Copies the data from the buffer into an internal buffer. Callback is called when a a write is either done or aborted. Immediately tries to write the data to the connection. If not possible, queues the write for processing when possible (FIFO). */ - inline void write(const void* buf, size_t n, WriteCallback callback, bool PUSH = true) { + inline void write(const void* buf, size_t n, WriteCallback callback, bool PUSH) { auto buffer = buffer_t(new uint8_t[n], std::default_delete()); memcpy(buffer.get(), buf, n); write(buffer, n, callback, PUSH); } + inline void write(const void* buf, size_t n, WriteCallback callback) + { write(buf, n, callback, true); } + + inline void write(const void* buf, size_t n, bool PUSH) + { write(buf, n, [](auto){}, PUSH); } + + inline void write(const void* buf, size_t n) + { write(buf, n, [](auto){}, true); } + /* Works as write(const void*, size_t, WriteCallback, bool), but with the exception of avoiding copying the data to an internal buffer. */ - inline void write(buffer_t buffer, size_t n, WriteCallback callback, bool PUSH = true) { - write({buffer, n, PUSH}, callback); - } + inline void write(buffer_t buffer, size_t n, WriteCallback callback, bool PUSH = true) + { write({buffer, n, PUSH}, callback); } - /* - Works the same as it's counterpart, without subscribing to a WriteCallback. - */ - inline void write(const void* buf, size_t n, bool PUSH = true) { - write(buf, n, [](auto){}, PUSH); - } + inline void write(buffer_t buffer, size_t n, bool PUSH = true) + { write({buffer, n, PUSH}, [](auto){}); } /* - Works the same as it's counterpart, without subscribing to a WriteCallback. + Write a WriteBuffer asynchronous to a remote and calls the WriteCallback when done (or aborted). */ - inline void write(buffer_t buffer, size_t n, bool PUSH = true) { - write({buffer, n, PUSH}, [](auto){}); - } - void write(WriteBuffer request, WriteCallback callback); From eeaf2b92aec528f6505b7aa6238f4639483571f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Tue, 12 Apr 2016 09:55:24 +0200 Subject: [PATCH 133/311] tcp: more congestion control + silence debug output --- api/net/tcp.hpp | 2 +- src/net/tcp_connection.cpp | 9 +++++---- src/net/tcp_connection_states.cpp | 27 ++++++++++++++------------- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index 76bad7f6e2..fd214c3e19 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -1299,7 +1299,7 @@ namespace net { inline void reduce_slow_start_threshold() { control_block.ssthresh = std::max( (flight_size() / 2), (2 * SMSS()) ); - printf("TCP::Connection::reduce_slow_start_threshold> Slow start threshold reduced: %u\n", + debug2("TCP::Connection::reduce_slow_start_threshold> Slow start threshold reduced: %u\n", control_block.ssthresh); } diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index 8153285553..b8020b10bd 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -40,7 +40,7 @@ Connection::Connection(TCP& host, Port local_port, Socket remote) : queued_(false), time_wait_started(0) { - + init_cwnd(3); } /* @@ -161,7 +161,7 @@ size_t Connection::send(const char* buffer, size_t remaining, size_t& packet_cou bytes_written += written; remaining -= written; - debug2(" Packet Limit: %u - Written: %u" + debug2(" Packet Limit: %u - Written: %u" " - Remaining: %u - Packet count: %u, Window: %u\n", packet_limit, written, remaining, packet_count, usable_window()); @@ -174,6 +174,7 @@ size_t Connection::send(const char* buffer, size_t remaining, size_t& packet_cou // TODO: Replace with chaining transmit(packet); } + debug(" Sent %u bytes of data\n", bytes_written); return bytes_written; } @@ -295,8 +296,8 @@ void Connection::transmit(TCP::Packet_ptr packet) { debug(" Transmitting: %s \n", packet->to_string().c_str()); host_.transmit(packet); // Don't think we would like to retransmit reset packets..? - if(!packet->isset(RST)) - queue_retransmission(packet); + //if(!packet->isset(RST)) + // queue_retransmission(packet); } void Connection::retransmit(TCP::Packet_ptr packet) { diff --git a/src/net/tcp_connection_states.cpp b/src/net/tcp_connection_states.cpp index 45af7304b7..074b0af77e 100644 --- a/src/net/tcp_connection_states.cpp +++ b/src/net/tcp_connection_states.cpp @@ -211,11 +211,10 @@ bool Connection::State::check_ack(Connection& tcp, TCP::Packet_ptr in) { something not yet sent (SEG.ACK > SND.NXT) then send an ACK, drop the segment, and return. */ - //if( tcb.SND.UNA < in->ack() and in->ack() <= tcb.SND.NXT ) { // Correction: [RFC 1122 p. 94] - if( tcb.SND.UNA <= in->ack() and in->ack() <= tcb.SND.NXT ) { + if( tcb.SND.UNA < in->ack() and in->ack() <= tcb.SND.NXT ) { tcb.SND.UNA = in->ack(); - debug2(" Usable window slided (%i)\n", tcp.usable_window()); + debug2(" Usable window slided (%i) %u\n", tcp.usable_window(), tcb.SND.cwnd); // tcp.signal_sent(); // return that buffer has been SENT - currently no support to receipt sent buffer. @@ -229,6 +228,7 @@ bool Connection::State::check_ack(Connection& tcp, TCP::Packet_ptr in) { tcb.SND.WND = in->win(); tcb.SND.WL1 = in->seq(); tcb.SND.WL2 = in->ack(); + debug2(" Send window updated: %u \n", tcb.SND.WND); } /* Note that SND.WND is an offset from SND.UNA, that SND.WL1 @@ -238,18 +238,10 @@ bool Connection::State::check_ack(Connection& tcp, TCP::Packet_ptr in) { prevents using old segments to update the window. */ } - /* If the ACK acks something not yet sent (SEG.ACK > SND.NXT) then send an ACK, drop the segment, and return. */ - else if( in->ack() > tcb.SND.NXT ) { - auto packet = tcp.outgoing_packet(); - packet->set_flag(ACK); - tcp.transmit(packet); - tcp.drop(in, "ACK > SND.NXT"); - return false; - } /* If the ACK is a duplicate (SEG.ACK < SND.UNA), it can be ignored. */ // Correction: [RFC 1122 p. 94] else if( in->ack() <= tcb.SND.UNA ) { - printf(" Dup ACK.\n"); + debug2(" Dup ACK.\n"); // [RFC 5681] /* Note that a sender using SACK [RFC2018] MUST NOT send @@ -258,12 +250,20 @@ bool Connection::State::check_ack(Connection& tcp, TCP::Packet_ptr in) { */ auto dup_count = tcp.duplicate_ack(in->ack()); if(dup_count == 3) { - printf(" Duplicate ACK strike! (>= 3)\n"); + debug(" Duplicate ACK strike! (>= 3)\n"); tcp.reduce_slow_start_threshold(); } else if(dup_count > 3) { tcb.SND.cwnd += tcp.SMSS(); } } + /* If the ACK acks something not yet sent (SEG.ACK > SND.NXT) then send an ACK, drop the segment, and return. */ + else if( in->ack() > tcb.SND.NXT ) { + auto packet = tcp.outgoing_packet(); + packet->set_flag(ACK); + tcp.transmit(packet); + tcp.drop(in, "ACK > SND.NXT"); + return false; + } return true; } // ACK not set. @@ -1240,6 +1240,7 @@ State::Result Connection::LastAck::handle(Connection& tcp, TCP::Packet_ptr in) { if(! check_seq(tcp, in) ) { return OK; } + return CLOSED; // 2. check RST if( in->isset(RST) ) { From 0f682371dd97495d90a6c90474afa1e7aa557a70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Tue, 12 Apr 2016 09:56:08 +0200 Subject: [PATCH 134/311] example: repaired demo example --- examples/demo_service/service.cpp | 117 ++++++++++++++++-------------- 1 file changed, 64 insertions(+), 53 deletions(-) diff --git a/examples/demo_service/service.cpp b/examples/demo_service/service.cpp index 402c24b307..dd7fa0cd98 100644 --- a/examples/demo_service/service.cpp +++ b/examples/demo_service/service.cpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -26,23 +26,57 @@ std::unique_ptr > inet; using namespace std::chrono; +std::string HTML_RESPONSE() { + int color = rand(); + std::stringstream stream; + + /* HTML Fonts */ + std::string ubuntu_medium = "font-family: \'Ubuntu\', sans-serif; font-weight: 500; "; + std::string ubuntu_normal = "font-family: \'Ubuntu\', sans-serif; font-weight: 400; "; + std::string ubuntu_light = "font-family: \'Ubuntu\', sans-serif; font-weight: 300; "; + + /* HTML */ + stream << "" + << "" + << "" + << "

> 8) << "\">" + << "IncludeOS

" + << "

Now speaks TCP!

" + // .... generate more dynamic content + << "

...and can improvise http. With limitations of course, but it's been easier than expected so far

" + << "

© 2015, Oslo and Akershus University College of Applied Sciences
" + << "\n"; + + std::string html = stream.str(); + + std::string header="HTTP/1.1 200 OK \n " \ + "Date: Mon, 01 Jan 1970 00:00:01 GMT \n" \ + "Server: IncludeOS prototype 4.0 \n" \ + "Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT \n" \ + "Content-Type: text/html; charset=UTF-8 \n" \ + "Content-Length: "+std::to_string(html.size())+"\n" \ + "Accept-Ranges: bytes\n" \ + "Connection: close\n\n"; + return header + html; +} + void Service::start() { // Assign a driver (VirtioNet) to a network interface (eth0) // @note: We could determine the appropirate driver dynamically, but then we'd // have to include all the drivers into the image, which we want to avoid. hw::Nic& eth0 = hw::Dev::eth<0,VirtioNet>(); - + // Bring up a network stack, attached to the nic // @note : No parameters after 'nic' means we'll use DHCP for IP config. inet = std::make_unique >(eth0); - + // Static IP configuration, until we (possibly) get DHCP // @note : Mostly to get a robust demo service that it works with and without DHCP inet->network_config( {{ 10,0,0,42 }}, // IP {{ 255,255,255,0 }}, // Netmask {{ 10,0,0,1 }}, // Gateway {{ 8,8,8,8 }} ); // DNS - + srand(OS::cycles_since_boot()); // Set up a TCP server on port 80 @@ -51,56 +85,33 @@ void Service::start() { hw::PIT::instance().onRepeatedTimeout(30s, []{ printf(" TCP STATUS:\n%s \n", inet->tcp().status().c_str()); }); - + // Add a TCP connection handler - here a hardcoded HTTP-service server.onAccept([](auto conn) -> bool { - printf(" @onAccept - Connection attempt from: %s \n", - conn->to_string().c_str()); - return true; // allow all connections - - }).onConnect([](auto) { - printf(" @onConnect - Connection successfully established.\n"); - - }).onReceive([](auto conn, bool push) { - std::string data = conn->read(1024); - printf(" @onData - PUSH: %d, Data read: \n%s\n", push, data.c_str()); - int color = rand(); - std::stringstream stream; - - /* HTML Fonts */ - std::string ubuntu_medium = "font-family: \'Ubuntu\', sans-serif; font-weight: 500; "; - std::string ubuntu_normal = "font-family: \'Ubuntu\', sans-serif; font-weight: 400; "; - std::string ubuntu_light = "font-family: \'Ubuntu\', sans-serif; font-weight: 300; "; - - /* HTML */ - stream << "" - << "" - << "" - << "

> 8) << "\">" - << "IncludeOS

" - << "

Now speaks TCP!

" - // .... generate more dynamic content - << "

...and can improvise http. With limitations of course, but it's been easier than expected so far

" - << "

© 2015, Oslo and Akershus University College of Applied Sciences
" - << "\n"; - - /* HTTP-header */ - std::string html = stream.str(); - std::string header="HTTP/1.1 200 OK \n " \ - "Date: Mon, 01 Jan 1970 00:00:01 GMT \n" \ - "Server: IncludeOS prototype 4.0 \n" \ - "Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT \n" \ - "Content-Type: text/html; charset=UTF-8 \n" \ - "Content-Length: "+std::to_string(html.size())+"\n" \ - "Accept-Ranges: bytes\n" \ - "Connection: close\n\n"; - - std::string output{header + html}; - conn->write(output.data(), output.size()); - - }).onDisconnect([](auto, auto reason) { - printf(" @onDisconnect - Reason: %s \n", reason.to_string().c_str()); - }); + printf(" @onAccept - Connection attempt from: %s \n", + conn->to_string().c_str()); + return true; // allow all connections + + }).onConnect([](auto conn) { + printf(" @onConnect - Connection successfully established.\n"); + // read async with a buffer size of 1024 bytes + // define what to do when data is read + conn->read(1024, [conn](net::TCP::buffer_t buf, size_t n) { + // create string from buffer + std::string data { (char*)buf.get(), n }; + printf(" @read:\n%s\n", data.c_str()); + + // create response + std::string response = HTML_RESPONSE(); + // write the data from the string with the strings size + conn->write(response.data(), response.size(), [](size_t n) { + printf(" @write: %u bytes written\n", n); + }); + }); + + }).onDisconnect([](auto, auto reason) { + printf(" @onDisconnect - Reason: %s \n", reason.to_string().c_str()); + }); printf("*** TEST SERVICE STARTED *** \n"); } From 0a6d4f1feab9aae3db3fc82f17226ef2c64272f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Tue, 12 Apr 2016 10:25:47 +0200 Subject: [PATCH 135/311] examples: repaired tcp demo --- examples/tcp/service.cpp | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/examples/tcp/service.cpp b/examples/tcp/service.cpp index 42a0ccfbdc..534438dc07 100644 --- a/examples/tcp/service.cpp +++ b/examples/tcp/service.cpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -18,11 +18,11 @@ /* An example to show incoming and outgoing TCP Connections. In this example, IncludeOS is listening on port 80. - + Data received on port 80 will be redirected to a outgoing connection to a (in this case) python server (server.py) - - Data received from the python server connection + + Data received from the python server connection will be redirected back to the client. To try it out, use netcat to connect to this IncludeOS instance. @@ -42,29 +42,25 @@ std::unique_ptr > inet; net::TCP::Socket python_server{ {{10,0,2,2}} , 1337}; // Called when data is received on client (incoming connection) -void handle_client_on_receive(Connection_ptr client, Connection_ptr python) { - // Read the request from our client - std::string request = client->read(1024); +void handle_client_on_read(Connection_ptr python, std::string request) { printf("Received [Client]: %s\n", request.c_str()); // Write the request to our python server - python->write(request); + python->write(request.data(), request.size()); } // Called when data is received on python (outgoing connection) -void handle_python_on_receive(Connection_ptr python, Connection_ptr client) { - // Read the response from our python server - std::string response = python->read(1024); +void handle_python_on_read(Connection_ptr client, std::string response) { // Write response to our client - client->write(response); + client->write(response.data(), response.size()); } void Service::start() { // Assign a driver (VirtioNet) to a network interface (eth0) hw::Nic& eth0 = hw::Dev::eth<0,VirtioNet>(); - + // Bring up a network stack, attached to the nic inet = std::make_unique >(eth0); - + // Static IP configuration, until we (possibly) get DHCP inet->network_config( {{ 10,0,0,42 }}, // IP {{ 255,255,255,0 }}, // Netmask @@ -87,14 +83,16 @@ void Service::start() { printf("Connected [Python]: %s\n", python->to_string().c_str()); // Setup handlers for when data is received on client and python connection - // When client has data to be read - client->onReceive([python](Connection_ptr client, bool) { - handle_client_on_receive(client, python); + // When client reads data + client->read(1024, [python](auto buf, size_t n) { + std::string data{ (char*)buf.get(), n }; + handle_client_on_read(python, data); }); - // When python server has data to be read - python->onReceive([client](Connection_ptr python, bool) { - handle_python_on_receive(python, client); + // When python server reads data + python->read(1024, [client](auto buf, size_t n) { + std::string data{ (char*)buf.get(), n }; + handle_python_on_read(client, data); }); // When client is disconnecting From 2e3f050abf33ce5fef02bfa9fdd6cb3e4c782b85 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 12 Apr 2016 11:50:03 +0200 Subject: [PATCH 136/311] Improved timer tests + test timer deletion --- test/timers/Makefile | 4 +- test/timers/service.cpp | 138 +++++++++++++++++++++++++++------------- test/timers/test.sh | 5 ++ 3 files changed, 101 insertions(+), 46 deletions(-) create mode 100755 test/timers/test.sh diff --git a/test/timers/Makefile b/test/timers/Makefile index 0df8981c38..64f2ad2da1 100644 --- a/test/timers/Makefile +++ b/test/timers/Makefile @@ -3,8 +3,8 @@ ################################################# # The name of your service -SERVICE = "Test_timers" -SERVICE_NAME = "Timers\ Test\ Service" +SERVICE = test_timers +SERVICE_NAME = Timers Test Service # Your service parts FILES = service.cpp diff --git a/test/timers/service.cpp b/test/timers/service.cpp index a469b018e6..203c2a83b6 100644 --- a/test/timers/service.cpp +++ b/test/timers/service.cpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -19,54 +19,104 @@ #include #include #include +#include using namespace std::chrono; +int one_shots = 0; +int repeat1 = 0; +int repeat2 = 0; + +auto& timer = hw::PIT::instance(); + void Service::start() { - - std::vector integers={1,2,3}; - - printf("TESTING Timers \n"); - auto& time = hw::PIT::instance(); - - - int x = 42; - - // Write something in a while - time.onTimeout(7s, [x](){ printf("7 seconds passed...%i \n",x); }); - - // Write a dot in a second - time.onTimeout(1s, [](){ printf("One second passed...\n"); }); - - // Write something in half a second - time.onTimeout(500ms, [](){ printf("Half a second passed...\n"); }); - - - time.onTimeout(3s, [](){ printf("Three second passed...\n"); }); - - + + + INFO("Test Timers","Testing one-shot timers"); + + + int t1 = 0; + int t10 = 0; + int t2 = 0; + + // 30 sec. - Test End + timer.onTimeout(30s, [] { + printf("One-shots fired: %i \n", one_shots); + CHECKSERT(one_shots == 5, "5 one-shot-timers fired"); + CHECKSERT(repeat1 == 25 and repeat2 == 10, "1s. timer fired 25 times, 2s. timer fired 10 times"); + CHECKSERT(timer.active_timers() == 1, "This is the last active timer"); + INFO("Test Timers","SUCCESS"); + }); + + // 5 sec. + timer.onTimeout(5s, [] { + CHECKSERT(one_shots == 3, + "After 5 sec, 3 other one-shot-timers have fired"); + one_shots++; + }); + + // 0.5 sec. + timer.onTimeout(500ms, [] { + CHECKSERT(one_shots == 0, "After 0.5 sec, no other one-shot-timers have fired"); + one_shots++; + }); + + // 1 sec. + timer.onTimeout(1s, [] { + CHECKSERT(one_shots == 1, "After 1 sec, 1 other one-shot-timers has fired"); + one_shots++; + }); + + // You can also use the std::function interface (which is great) - std::function in_a_second = [integers](){ - std::cout << "Hey - this is a std::function - it knows about integers:" << std::endl; + std::vector integers={1,2,3}; + + std::function in_a_second = [integers](){ for (auto i : integers) - std::cout << i << std::endl; + CHECKSERT(i == integers[i - 1], "%i == integers[%i - 1]", i, integers[i - 1]); + one_shots++; }; - - time.onTimeout(1s, in_a_second); - - time.onRepeatedTimeout(1s, []{ printf("1sec. PULSE \n"); }); - time.onRepeatedTimeout(2s, []{ printf("2sec. PULSE, "); }, - - // A continue-condition. The timer stops when false is returned - []{ - static int i = 0; i++; - printf("%i / 10 times \n", i); - if (i >= 10) { - printf("2sec. pulse DONE!"); - return false; - } - return true; }); - - + + timer.onTimeout(1s, in_a_second); + + auto timer1s = timer.onRepeatedTimeout(1s, []{ + repeat1++; + printf("1s. PULSE #%i \n", repeat1); + }); + + timer.onRepeatedTimeout(2s, []{ + repeat2++; + printf("2s. PULSE #%i \n", repeat2); + }, + + // A continue-condition. The timer stops when false is returned + []{ + CHECKSERT(repeat1 == (repeat2 * 2), "2s timer fired %i, 1s fired %i x 2 == %i times", repeat2, repeat2, repeat1); + if (repeat2 >= 10) { + CHECK(true, "2sec. pulse DONE!"); + return false; + } + return true; + }); + + + // 25 sec. - end last repeating timer + timer.onTimeout(25s + 10ms, [ timer1s ] { + one_shots++; + CHECKSERT(repeat1 == 25 and repeat2 == 10, + "After 25 sec, 1s timer x 30 == %i times, 2s timer x 15 == %i times", + repeat1, repeat2); + + timer.stop_timer(timer1s); + CHECKSERT(timer.active_timers() == 2, "There are now 2 timers left"); + + timer.onTimeout(1s, []{ + CHECKSERT(1, "Timers are still functioning"); + }); + + }); + + + } diff --git a/test/timers/test.sh b/test/timers/test.sh new file mode 100755 index 0000000000..a878e3f600 --- /dev/null +++ b/test/timers/test.sh @@ -0,0 +1,5 @@ +#!/bin/bash +source ../test_base + +make +start test_timers.img From 27c51290ecc73eba4d370a3d323c43849871deca Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 12 Apr 2016 11:54:58 +0200 Subject: [PATCH 137/311] Added functionality to stop timers --- api/hw/pit.hpp | 195 ++++++++++++++++++++++++++----------------------- src/hw/pit.cpp | 66 ++++++++++------- 2 files changed, 141 insertions(+), 120 deletions(-) diff --git a/api/hw/pit.hpp b/api/hw/pit.hpp index f4f4d8f439..aa7761467b 100644 --- a/api/hw/pit.hpp +++ b/api/hw/pit.hpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -25,163 +25,174 @@ namespace hw { /** Programmable Interval Timer class. A singleton. - + @TODO - ...It has timer-functionality, which should probably be super-classed, + ...It has timer-functionality, which should probably be super-classed, so that i.e. the HPET could be used with the same interface. */ - class PIT{ + class PIT{ public: - - typedef delegate timeout_handler; - typedef std::function repeat_condition; - - /** Create a one-shot timer. + + using timeout_handler = delegate; + using repeat_condition = std::function; + + /** A timer is a handler and an expiration time (interval). + @todo The timer also keeps a pre-computed rdtsc-value, which is currently unused.*/ + class Timer { + public: + enum Type { ONE_SHOT, REPEAT, REPEAT_WHILE} type_; + + Timer() = delete; + Timer(Type, timeout_handler, std::chrono::milliseconds, repeat_condition = forever); + Timer(const Timer&) = default; + Timer(Timer&&) = default; + Timer& operator=(Timer&) = default; + Timer& operator=(Timer&&) = default; + virtual ~Timer() = default; + + inline Type type(){ return type_; } + inline std::chrono::milliseconds interval(){ return interval_; } + inline uint64_t start() { return timestamp_start_; } + inline uint64_t end() { return timestamp_end_; } + inline void setStart(uint64_t s) { timestamp_start_ = s; } + inline void setEnd(uint64_t e) { timestamp_end_ = e; } + inline timeout_handler handler(){ return handler_; } + inline const repeat_condition cond() { return cond_; } + inline uint32_t id(){ return id_; } + + private: + static uint32_t timers_count_; + uint32_t id_ = 0; + timeout_handler handler_; + uint64_t timestamp_start_; + uint64_t timestamp_end_; + std::chrono::milliseconds interval_; + + /* This Could be a reference in the default case of "forever", but then the + case of a normal lambda being passed in, the user would have to be in charge + of storage. */ + const repeat_condition cond_; + }; + + + + using Timer_iterator = std::multimap::iterator; + + /** Create a one-shot timer. @param ms: Expiration time. Compatible with all std::chrono durations. @param handler: A delegate or function to be called on timeout. */ - void onTimeout(std::chrono::milliseconds ms, timeout_handler handler); + Timer_iterator onTimeout(std::chrono::milliseconds ms, timeout_handler handler); - /** Create a repeating timer. + /** Create a repeating timer. @param ms: Expiration time. Compatible with all std::chrono durations. - @param handler: A delegate or function to be called every ms interval. + @param handler: A delegate or function to be called every ms interval. @param cond: The timer ends when cond() returns false. Default to true. */ - void onRepeatedTimeout(std::chrono::milliseconds ms, - timeout_handler handler, - repeat_condition cond = forever); - + Timer_iterator onRepeatedTimeout(std::chrono::milliseconds ms, + timeout_handler handler, + repeat_condition cond = forever); + + /** Stop a timer. + @param it: A valid iterator to timer */ + void stop_timer(Timer_iterator it); + + inline size_t active_timers() { return timers_.size(); } + /** No copy or move. The OS owns one instance forever. */ PIT(PIT&) = delete; PIT(PIT&&) = delete; - + /** Get the (single) instance. */ - static PIT& instance() { + static PIT& instance() { static PIT instance_; return instance_; }; - + /** Initialize the hardware. */ - static void init(); - + static void init(); + /** The constant frequency of the PIT-hardware, before frequency dividers */ static constexpr MHz frequency() { return frequency_; } - + static inline MHz current_frequency(){ return frequency() / current_freq_divider_; } - - /** Estimate cpu frequency based on the fixed PIT frequency and rdtsc. - @Note This is an asynchronous function. Once finished the result can be + + /** Estimate cpu frequency based on the fixed PIT frequency and rdtsc. + @Note This is an asynchronous function. Once finished the result can be fetched by CPUFrequency() (below) */ static void estimateCPUFrequency(); - + /** Get the last estimated CPU frequency. May trigger frequency sampling */ static MHz CPUFrequency(); - - private: + + + private: // Default repeat-condition static std::function forever; - - enum Mode { ONE_SHOT = 0, - HW_ONESHOT = 1 << 1, - RATE_GEN = 2 << 1, - SQ_WAVE = 3 << 1, - SW_STROBE = 4 << 1, - HW_STROBE = 5 << 1, + + enum Mode { ONE_SHOT = 0, + HW_ONESHOT = 1 << 1, + RATE_GEN = 2 << 1, + SQ_WAVE = 3 << 1, + SW_STROBE = 4 << 1, + HW_STROBE = 5 << 1, NONE = 256}; - + // The PIT-chip runs at this fixed frequency (in MHz) , according to OSDev.org */ static constexpr MHz frequency_ = MHz(14.31818 / 12); /** Disable regular timer interrupts- which are turned on at boot-time. */ static void disable_regular_interrupts(); - + /** The default (soft)handler for timer interrupts */ void irq_handler(); - + // Private constructor / destructor. It's a singleton. - PIT(); + PIT(); ~PIT(); // State-keeping static Mode temp_mode_; - static uint16_t temp_freq_divider_; + static uint16_t temp_freq_divider_; static uint8_t status_byte_; static uint16_t current_freq_divider_; static Mode current_mode_; static uint64_t IRQ_counter_; - + // The closest we can get to a millisecond interval, with the PIT-frequency static constexpr uint16_t millisec_interval = KHz(frequency_).count(); - + // Count the "milliseconds" static uint64_t millisec_counter; // Access mode bits are bits 4- and 5 in the Mode register enum AccessMode { LATCH_COUNT = 0x0, LO_ONLY=0x10, HI_ONLY=0x20, LO_HI=0x30 }; - + /** Physically set the PIT-mode */ static void set_mode(Mode); - + /** Physiclally set the PIT frequency divider */ static void set_freq_divider(uint16_t); - + /** Set mode to one-shot, and frequency-divider to t */ - static void oneshot(uint16_t t); - + static void oneshot(uint16_t t); + /** Read back the PIT status from hardware */ static uint8_t read_back(uint8_t channel); - - /** A timer is a handler and an expiration time (interval). - @todo The timer also keeps a pre-computed rdtsc-value, which is currently unused.*/ - class Timer { - public: - enum Type { ONE_SHOT, REPEAT, REPEAT_WHILE} type_; - - Timer() = delete; - Timer(Type, timeout_handler, std::chrono::milliseconds, repeat_condition = forever); - Timer(const Timer&) = default; - Timer(Timer&&) = default; - Timer& operator=(Timer&) = default; - Timer& operator=(Timer&&) = default; - virtual ~Timer() = default; - - inline Type type(){ return type_; } - inline std::chrono::milliseconds interval(){ return interval_; } - inline uint64_t start() { return timestamp_start_; } - inline uint64_t end() { return timestamp_end_; } - inline void setStart(uint64_t s) { timestamp_start_ = s; } - inline void setEnd(uint64_t e) { timestamp_end_ = e; } - inline timeout_handler handler(){ return handler_; } - inline const repeat_condition cond() { return cond_; } - inline uint32_t id(){ return id_; } - - private: - static uint32_t timers_count_; - uint32_t id_ = 0; - timeout_handler handler_; - uint64_t timestamp_start_; - uint64_t timestamp_end_; - std::chrono::milliseconds interval_; - - /* This Could be a reference in the default case of "forever", but then the - case of a normal lambda being passed in, the user would have to be in charge - of storage. */ - const repeat_condition cond_; - }; - - /** A map of timers. - @note {Performance: We take advantage of the fact that std::map have sorted keys. + + /** A map of timers. + @note {Performance: We take advantage of the fact that std::map have sorted keys. * Timers soonest to expire are in the front, so we only iterate over those * Deletion of finished timers in amortized constant time, via iterators * Timer insertion is log(n) } - @note This is why we want to instantiate PIT, and why it's a singleton: + @note This is why we want to instantiate PIT, and why it's a singleton: If you don't use PIT-timers, you won't pay for them. */ std::multimap timers_; /** Queue the timer. This will update timestamps in the timer */ - void start_timer(Timer t, std::chrono::milliseconds); - + Timer_iterator start_timer(Timer t, std::chrono::milliseconds); + }; } //< namespace hw diff --git a/src/hw/pit.cpp b/src/hw/pit.cpp index 11ffc8e9e6..73264c5e49 100644 --- a/src/hw/pit.cpp +++ b/src/hw/pit.cpp @@ -16,7 +16,7 @@ // limitations under the License. //#define DEBUG -// #define DEBUG2 +//#define DEBUG2 #include #include #include @@ -111,7 +111,7 @@ namespace hw { } - void PIT::start_timer(Timer t, std::chrono::milliseconds in_msecs){ + PIT::Timer_iterator PIT::start_timer(Timer t, std::chrono::milliseconds in_msecs){ if (in_msecs < 1ms) panic("Can't wait less than 1 ms. "); if (current_mode_ != RATE_GEN) @@ -121,11 +121,11 @@ namespace hw { set_freq_divider(millisec_interval); auto cycles_pr_millisec = KHz(CPUFrequency()); - debug(" CPU KHz: %f Cycles to wait: %f \n",cycles_pr_millisec.count(), cycles_pr_millisec.count() * in_msecs); + //debug(" CPU KHz: %f Cycles to wait: %f \n",cycles_pr_millisec.count(), cycles_pr_millisec.count() * in_msecs); auto ticks = in_msecs / KHz(current_frequency()).count(); - debug(" PIT KHz: %f * %i = %f ms. \n", - KHz(current_frequency()).count(), (uint32_t)ticks.count(), ((uint32_t)ticks.count() * KHz(current_frequency()).count())); + //debug(" PIT KHz: %f * %i = %f ms. \n", + //KHz(current_frequency()).count(), (uint32_t)ticks.count(), ((uint32_t)ticks.count() * KHz(current_frequency()).count())); t.setStart(OS::cycles_since_boot()); t.setEnd(t.start() + uint64_t(cycles_pr_millisec.count() * in_msecs.count())); @@ -134,32 +134,37 @@ namespace hw { auto key = millisec_counter + ticks.count(); // We could emplace, but the timer exists allready, and might be a reused one - timers_.insert(std::make_pair(key, t)); + auto it = timers_.insert(std::make_pair(key, t)); debug(" Key: %i id: %i, t.cond()(): %s There are %i timers. \n", (uint32_t)key, t.id(), t.cond()() ? "true" : "false", timers_.size()); + return it; } - void PIT::onRepeatedTimeout(std::chrono::milliseconds ms, timeout_handler handler, repeat_condition cond){ + PIT::Timer_iterator PIT::onRepeatedTimeout(std::chrono::milliseconds ms, timeout_handler handler, repeat_condition cond){ debug(" setting a %i ms. repeating timer \n", (uint32_t)ms.count()); Timer t(Timer::REPEAT_WHILE, handler, ms, cond); - start_timer(t, ms); + return start_timer(t, ms); }; - void PIT::onTimeout(std::chrono::milliseconds msec, timeout_handler handler){ + PIT::Timer_iterator PIT::onTimeout(std::chrono::milliseconds msec, timeout_handler handler){ Timer t(Timer::ONE_SHOT, handler, msec); debug(" setting a %i ms. one-shot timer. Id: %i \n", (uint32_t)msec.count(), t.id()); - start_timer(t, msec); + return start_timer(t, msec); }; + void PIT::stop_timer(PIT::Timer_iterator it) { + timers_.erase(it); + } + uint8_t PIT::read_back(uint8_t){ const uint8_t READ_BACK_CMD = 0xc2; @@ -188,6 +193,9 @@ namespace hw { OS::rsprint("."); #endif + std::vector garbage {}; + std::vector restart {}; + // Iterate over expired timers (we break on the first non-expired) for (auto it = timers_.begin(); it != timers_.end(); it++) { @@ -204,44 +212,46 @@ namespace hw { // Re-queue repeating timers if (it->second.type() == Timer::REPEAT) { debug2 (" REPEAT: Requeuing the timer \n"); - start_timer(it->second, it->second.interval()); + restart.push_back(it); }else if (it->second.type() == Timer::REPEAT_WHILE and it->second.cond()()) { debug2 (" REPEAT_WHILE: Requeuing the timer COND \n"); - start_timer(it->second, it->second.interval()); + restart.push_back(it); } debug2 ("Timer done. Erasing. \n"); - // Escape iterator death - auto remove = it; - it++; - - // Erase the timer - timers_.erase(remove); + // Queue this timer for deletion (Escape iterator death by not deleting it now) + garbage.push_back(it); - // If this was the last timer, we can turn off the clock - if (timers_.empty()){ - // Disable the PIT - oneshot(1); - - debug2 ("Timers done. PIT disabled for now. \n"); - // Escape iterator death - break; - } + } + if (not garbage.empty()) { debug2 ("Timers left: %i \n", timers_.size()); #ifdef DEBUG2 for (auto t : timers_) - debug2("Key: %i , id: %i, Type: %i", (uint32_t)t.first, t.second.id(), t.second.type()); + debug2("Key: %i , id: %i, Type: %i \n", (uint32_t)t.first, t.second.id(), t.second.type()); #endif debug2("\n---------------------------\n\n"); } + for (auto t : restart) { + start_timer(t->second, t->second.interval()); + } + + for (auto t : garbage) { + debug2("ERASE: Key: %i , id: %i, Type: %i \n", (uint32_t)t->first, t->second.id(), t->second.type()); + timers_.erase(t); + } + + if (timers_.empty()) + oneshot(1); + } + void PIT::init(){ debug(" Initializing @ frequency: %16.16f MHz. Assigning myself to all timer interrupts.\n ", frequency()); PIT::disable_regular_interrupts(); From 29e4dae42048300c73b49644339b4ae3dca109e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Tue, 12 Apr 2016 15:31:00 +0200 Subject: [PATCH 138/311] tcp: avoid ambiguous member call + work on rfc6298 (retransmission) --- api/net/tcp.hpp | 100 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 94 insertions(+), 6 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index fd214c3e19..a9af1eb2b0 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -883,27 +883,37 @@ namespace net { inline void write(const void* buf, size_t n, WriteCallback callback) { write(buf, n, callback, true); } - inline void write(const void* buf, size_t n, bool PUSH) - { write(buf, n, [](auto){}, PUSH); } + // results in ambiguous call to member function + //inline void write(const void* buf, size_t n, bool PUSH) + //{ write(buf, n, WriteCallback::from(this), PUSH); } inline void write(const void* buf, size_t n) - { write(buf, n, [](auto){}, true); } + { write(buf, n, WriteCallback::from(this), true); } /* Works as write(const void*, size_t, WriteCallback, bool), but with the exception of avoiding copying the data to an internal buffer. */ - inline void write(buffer_t buffer, size_t n, WriteCallback callback, bool PUSH = true) + inline void write(buffer_t buffer, size_t n, WriteCallback callback, bool PUSH) { write({buffer, n, PUSH}, callback); } - inline void write(buffer_t buffer, size_t n, bool PUSH = true) - { write({buffer, n, PUSH}, [](auto){}); } + inline void write(buffer_t buffer, size_t n, WriteCallback callback) + { write({buffer, n, true}, callback); } + + // results in ambiguous call to member function + //inline void write(buffer_t buffer, size_t n, bool PUSH) + //{ write({buffer, n, PUSH}, WriteCallback::from(this)); } + + inline void write(buffer_t buffer, size_t n) + { write({buffer, n, true}, WriteCallback::from(this)); } /* Write a WriteBuffer asynchronous to a remote and calls the WriteCallback when done (or aborted). */ void write(WriteBuffer request, WriteCallback callback); + inline void default_on_write(size_t) {}; + /* Open connection. @@ -1112,6 +1122,84 @@ namespace net { uint64_t time_wait_started; + // [RFC 6298] + struct RoundTripCalc { + using timestamp_t = double; + using duration_t = double; + + // clock granularity + static constexpr duration_t CLOCK_G = hw::PIT::frequency().count(); + + static constexpr double K = 4.0; + + static constexpr double alpha = 1.0/8; + static constexpr double beta = 1.0/4; + + TCP::Seq SEQ; // current sequence number measured + timestamp_t t; // tick when measure is started + + duration_t SRTT; // smoothed round-trip time + duration_t RTTVAR; // round-trip time variation + duration_t RTO; // retransmission timeout + + bool active = false; + + void start(Seq seq) { + SEQ = seq; + t = OS::uptime(); + active = true; + } + + void stop() { + active = false; + // round trip time (RTT) + sub_rtt_measurement(OS::uptime() - t); + } + + /* + When the first RTT measurement R is made, the host MUST set + + SRTT <- R + RTTVAR <- R/2 + RTO <- SRTT + max (G, K*RTTVAR) + + where K = 4. + */ + void first_rtt_measurement(duration_t R) { + SRTT = R; + RTTVAR = R/2; + update_rto(); + } + + /* + When a subsequent RTT measurement R' is made, a host MUST set + + RTTVAR <- (1 - beta) * RTTVAR + beta * |SRTT - R'| + SRTT <- (1 - alpha) * SRTT + alpha * R' + + The value of SRTT used in the update to RTTVAR is its value + before updating SRTT itself using the second assignment. That + is, updating RTTVAR and SRTT MUST be computed in the above + order. + + The above SHOULD be computed using alpha=1/8 and beta=1/4 (as + suggested in [JK88]). + + After the computation, a host MUST update + RTO <- SRTT + max (G, K*RTTVAR) + */ + void sub_rtt_measurement(duration_t R) { + RTTVAR = (1 - beta) * RTTVAR + beta * std::abs(SRTT-R); + SRTT = (1 - alpha) * SRTT + alpha * R; + } + + void update_rto() { + RTO = std::max(SRTT + std::max(CLOCK_G, K * RTTVAR), 1.0); + } + + } round_trip; + + /// CALLBACK HANDLING /// /* When a Connection is initiated. */ From 89eef3c101f2ff968c56bd6344c108c39ca2c913 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Tue, 12 Apr 2016 15:50:42 +0200 Subject: [PATCH 139/311] pit: on_timeout takes double (seconds) --- api/hw/pit.hpp | 3 +++ test/timers/service.cpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/api/hw/pit.hpp b/api/hw/pit.hpp index aa7761467b..127da36b70 100644 --- a/api/hw/pit.hpp +++ b/api/hw/pit.hpp @@ -83,6 +83,9 @@ namespace hw { @param handler: A delegate or function to be called on timeout. */ Timer_iterator onTimeout(std::chrono::milliseconds ms, timeout_handler handler); + Timer_iterator on_timeout(double sec, timeout_handler handler) + { return onTimeout(std::chrono::milliseconds((unsigned)(sec * 1000)), handler); } + /** Create a repeating timer. @param ms: Expiration time. Compatible with all std::chrono durations. @param handler: A delegate or function to be called every ms interval. diff --git a/test/timers/service.cpp b/test/timers/service.cpp index 203c2a83b6..93be400a82 100644 --- a/test/timers/service.cpp +++ b/test/timers/service.cpp @@ -63,7 +63,7 @@ void Service::start() }); // 1 sec. - timer.onTimeout(1s, [] { + timer.on_timeout(1, [] { CHECKSERT(one_shots == 1, "After 1 sec, 1 other one-shot-timers has fired"); one_shots++; }); From 9dcfe301f1324cb0f9087bce491d9d736ec2e514 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Tue, 12 Apr 2016 16:26:03 +0200 Subject: [PATCH 140/311] virtio: Work on new vring interface --- api/virtio/block.hpp | 23 ++--- api/virtio/virtio.hpp | 20 +++-- src/debug/run_test.sh | 2 +- src/debug/test_disk.cpp | 166 ++++++++++++------------------------ src/virtio/block.cpp | 63 +++++++------- src/virtio/virtio_queue.cpp | 122 +++++++++++++++++--------- 6 files changed, 195 insertions(+), 201 deletions(-) diff --git a/api/virtio/block.hpp b/api/virtio/block.hpp index db8167b0d1..048a3ce460 100644 --- a/api/virtio/block.hpp +++ b/api/virtio/block.hpp @@ -86,23 +86,24 @@ class VirtioBlk : public Virtio, public hw::IDiskDevice uint32_t type; uint32_t ioprio; uint64_t sector; - /// SCSI /// - //char* cmd = nullptr; - } __attribute__((packed)); - struct blk_data_t + }; + struct blk_resp_t { - uint8_t sector[512]; - uint32_t stuff1; - on_read_func* handler; - uint32_t stuff2; uint8_t status; - } __attribute__((packed)); + }; + + struct blk_io_t + { + uint8_t sector[512]; + on_read_func handler; + }; struct request_t { scsi_header_t hdr; - blk_data_t data; - } __attribute__((packed)); + blk_io_t io; + blk_resp_t resp; + }; /** Get virtio PCI config. @see Virtio::get_config.*/ void get_config(); diff --git a/api/virtio/virtio.hpp b/api/virtio/virtio.hpp index c5affa27b4..1d601b630f 100644 --- a/api/virtio/virtio.hpp +++ b/api/virtio/virtio.hpp @@ -213,9 +213,6 @@ class Virtio */ int enqueue(scatterlist sg[], uint32_t out, uint32_t in, void*); - void enqueue(void* out, uint32_t out_len, void* in, uint32_t in_len); - void* dequeue(uint32_t& len); - /** Dequeue a received packet. From SanOS */ uint8_t* dequeue(uint32_t* len); @@ -228,16 +225,22 @@ class Virtio void release(uint32_t head); /** Get number of free tokens in Queue */ - inline uint16_t num_free(){ return _num_free; } + uint16_t num_free() const noexcept + { return _num_free; } /** Get number of new incoming buffers */ - inline uint16_t new_incoming() + uint16_t new_incoming() const noexcept { return _queue.used->idx - _last_used_idx; } /** Get number of used buffers */ - inline uint16_t num_avail() + uint16_t num_avail() const noexcept { return _queue.avail->idx - _queue.used->idx; } + // gonzoified enqueue & dequeue + void enqueue(void* out, uint32_t out_len, void* in, uint32_t in_len); + void enqueue(void* data, uint32_t len, bool out, bool last); + void* dequeue(uint32_t& len); + // access the current index virtq_desc& current() { @@ -254,7 +257,10 @@ class Virtio _free_head = _queue.desc[_free_head].next; } - inline uint16_t size(){ return _size; } + uint16_t size() const noexcept + { + return _size; + } }; diff --git a/src/debug/run_test.sh b/src/debug/run_test.sh index 953a9ddfff..854aa62061 100755 --- a/src/debug/run_test.sh +++ b/src/debug/run_test.sh @@ -14,7 +14,7 @@ echo "Building system $SERVICE..." # Get the Qemu-command (in-source, so we can use it elsewhere) . ../etc/qemu_cmd.sh export SERIAL="" #"-monitor none -virtioconsole stdio" -QEMU_OPTS+=" -drive file=./smalldisk,if=ide,media=disk $SERIAL" +QEMU_OPTS+=" -drive file=./smalldisk,if=virtio,media=disk $SERIAL" # Qemu with gdb debugging: if [ "$DEBUG" -ne 0 ] diff --git a/src/debug/test_disk.cpp b/src/debug/test_disk.cpp index 0ece49b679..a8d969d824 100644 --- a/src/debug/test_disk.cpp +++ b/src/debug/test_disk.cpp @@ -11,7 +11,7 @@ void list_partitions(decltype(disk)); void Service::start() { // instantiate memdisk with FAT filesystem - auto& device = hw::Dev::disk<0, hw::IDE>(hw::IDE::SLAVE); + auto& device = hw::Dev::disk<1, VirtioBlk>(); disk = std::make_shared (device); assert(disk); @@ -22,107 +22,53 @@ void Service::start() list_partitions(disk); // mount first valid partition (auto-detect and mount) - disk->mount( // or specify partition explicitly in parameter - [] (fs::error_t err) - { - if (err) - { - printf("Could not mount filesystem\n"); - return; - } - // get a reference to the mounted filesystem - auto& fs = disk->fs(); + disk->mount( + [] (fs::error_t err) + { + if (err) + { + printf("Could not mount filesystem\n"); + return; + } - // check contents of disk - auto dirents = fs::new_shared_vector(); - err = fs.ls("/", dirents); - if (err) - printf("Could not list '/' directory\n"); - else - for (auto& e : *dirents) - { - printf("%s: %s\t of size %llu bytes (CL: %llu)\n", - e.type_string().c_str(), e.name().c_str(), e.size, e.block); - } - - auto ent = fs.stat("/test.txt"); - // validate the stat call - if (ent.is_valid()) - { - // read specific area of file - auto buf = fs.read(ent, 1032, 65); - std::string contents((const char*) buf.buffer.get(), buf.len); - printf("[%s contents (%llu bytes)]:\n%s\n[end]\n\n", - ent.name().c_str(), buf.len, contents.c_str()); - - } - else - { - printf("Invalid entity for /test.txt\n"); - } - return; - - disk->fs().ls("/", - [] (fs::error_t err, auto ents) - { - if (err) - { - printf("Could not list '/' directory\n"); - return; - } - - for (auto& e : *ents) - { - printf("%s: %s\t of size %llu bytes (CL: %llu)\n", - e.type_string().c_str(), e.name().c_str(), e.size, e.block); - - if (e.is_file()) - { - printf("*** Attempting to read: %s\n", e.name().c_str()); - disk->fs().read(e, 0, e.size, - [e] (fs::error_t err, fs::buffer_t buffer, size_t len) - { - if (err) - { - printf("Failed to read file %s!\n", - e.name().c_str()); - return; - } - - std::string contents((const char*) buffer.get(), len); - printf("[%s contents]:\n%s\nEOF\n\n", - e.name().c_str(), contents.c_str()); - }); - } - } - }); - - disk->fs().stat("/test.txt", - [] (fs::error_t err, const auto& e) - { - if (err) - { - printf("Could not stat %s\n", e.name().c_str()); - return; - } - - printf("stat: /test.txt is a %s on cluster %llu\n", - e.type_string().c_str(), e.block); - }); - disk->fs().stat("/Sample Pictures/Koala.jpg", - [] (fs::error_t err, const auto& e) - { - if (err) - { - printf("Could not stat %s\n", e.name().c_str()); - return; - } + // async ls + disk->fs().ls("/", + [] (fs::error_t err, auto ents) + { + if (err) + { + printf("Could not list '/' directory\n"); + return; + } - printf("stat: %s is a %s on cluster %llu\n", - e.name().c_str(), e.type_string().c_str(), e.block); - }); + // go through directory entries + for (auto& e : *ents) + { + printf("%s: %s\t of size %llu bytes (CL: %llu)\n", + e.type_string().c_str(), e.name().c_str(), e.size, e.block); + + if (e.is_file()) + { + printf("*** Attempting to read: %s\n", e.name().c_str()); + disk->fs().read(e, 0, e.size, + [e] (fs::error_t err, fs::buffer_t buffer, size_t len) + { + if (err) + { + printf("Failed to read file %s!\n", + e.name().c_str()); + return; + } + + std::string contents((const char*) buffer.get(), len); + printf("[%s contents]:\n%s\nEOF\n\n", + e.name().c_str(), contents.c_str()); + }); + } + } + }); - }); // disk->auto_detect() + }); // disk->auto_detect() printf("*** TEST SERVICE STARTED *** \n"); } @@ -130,16 +76,16 @@ void Service::start() void list_partitions(decltype(disk) disk) { disk->partitions( - [] (fs::error_t err, auto& parts) - { - if (err) - { - printf("Failed to retrieve volumes on disk\n"); - return; - } + [] (fs::error_t err, auto& parts) + { + if (err) + { + printf("Failed to retrieve volumes on disk\n"); + return; + } - for (auto& part : parts) - printf("[Partition] '%s' at LBA %u\n", - part.name().c_str(), part.lba()); - }); + for (auto& part : parts) + printf("[Partition] '%s' at LBA %u\n", + part.name().c_str(), part.lba()); + }); } diff --git a/src/virtio/block.cpp b/src/virtio/block.cpp index d05bcad32a..503b1b67a6 100644 --- a/src/virtio/block.cpp +++ b/src/virtio/block.cpp @@ -105,10 +105,10 @@ void VirtioBlk::irq_handler() // Step 2. A) - one of the queues have changed if (isr & 1) - { - // This now means service RX & TX interchangeably - service_RX(); - } + { + // This now means service RX & TX interchangeably + service_RX(); + } // Step 2. B) if (isr & 2) @@ -125,37 +125,35 @@ void VirtioBlk::irq_handler() void VirtioBlk::service_RX() { + printf("VirtioBlk interrupt handler\n"); req.disable_interrupts(); uint32_t received = 0; uint32_t len; request_t* hdr; - blk_data_t* vbr; - //printf("service_RX() reading from VirtioBlk device\n"); while ((hdr = (request_t*) req.dequeue(len)) != nullptr) - { - printf("service_RX() received %u bytes for sector %llu\n", - len, hdr->hdr.sector); - vbr = &hdr->data; + { + printf("service_RX() received %u bytes for sector %llu\n", + len, hdr->hdr.sector); + // + blk_resp_t* resp = &hdr->resp; + printf("blk response: %u\n", resp->status); - printf("service_RX() received %u bytes data response\n", len); - printf("Received handler: %p\n", vbr->handler); + uint8_t* copy = new uint8_t[SECTOR_SIZE]; + memcpy(copy, hdr->io.sector, SECTOR_SIZE); + auto buf = buffer_t(copy, std::default_delete()); - uint8_t* copy = new uint8_t[SECTOR_SIZE]; - memcpy(copy, vbr->sector, SECTOR_SIZE); - auto buf = buffer_t(copy, std::default_delete()); + printf("STATUS: [%u]\nCalling handler: %p\n", + resp->status, &hdr->io.handler); + hdr->io.handler(buf); - printf("Calling handler: %p\n", vbr->handler); - (*vbr->handler)(buf); - delete vbr->handler; - - received++; - } + received++; + } if (received == 0) - { - //printf("service_RX() error processing requests\n"); - } + { + //printf("service_RX() error processing requests\n"); + } req.enable_interrupts(); } @@ -163,17 +161,20 @@ void VirtioBlk::service_RX() void VirtioBlk::read (block_t blk, on_read_func func) { // Virtio Std. § 5.1.6.3 - auto* vbr = new request_t(); + auto* vbr = new request_t; vbr->hdr.type = VIRTIO_BLK_T_IN; vbr->hdr.ioprio = 0; vbr->hdr.sector = blk; - vbr->data.handler = new on_read_func(func); - vbr->data.status = VIRTIO_BLK_S_OK; - - printf("Enqueue handler: %p\n", vbr->data.handler); - - req.enqueue(&vbr->hdr, sizeof(scsi_header_t), &vbr->data, sizeof(blk_data_t)); + vbr->io.handler = func; + vbr->resp.status = VIRTIO_BLK_S_IOERR; + + printf("Enqueue handler: %p, total: %u\n", + &vbr->io.handler, sizeof(request_t)); + // + req.enqueue(&vbr->hdr, sizeof(scsi_header_t), 1, false); // out + req.enqueue(&vbr->io, sizeof(blk_io_t), 0, false); // in + req.enqueue(&vbr->resp, sizeof(blk_resp_t), 0, true); // in, last req.kick(); } diff --git a/src/virtio/virtio_queue.cpp b/src/virtio/virtio_queue.cpp index 3bd9750356..0df57e6774 100644 --- a/src/virtio/virtio_queue.cpp +++ b/src/virtio/virtio_queue.cpp @@ -157,24 +157,26 @@ int Virtio::Queue::enqueue(scatterlist sg[], uint32_t out, uint32_t in, void* UN return _num_free; } void Virtio::Queue::enqueue( - void* out, - uint32_t out_len, - void* in, - uint32_t in_len) + void* out, + uint32_t out_len, + void* in, + uint32_t in_len) { int total = (out) ? 1 : 0; total += (in) ? 1 : 0; - + + printf("enqueue total: %d\n", total); + if (_num_free < total) - { - // Queue is full (we think) - printf("Buffer full (%i avail," \ - " used.idx: %i, avail.idx: %i )\n", - _pci_index, num_avail(), - _queue.used->idx,_queue.avail->idx - ); - panic("Buffer full"); - } + { + // Queue is full (we think) + printf("Buffer full (%i avail," \ + " used.idx: %i, avail.idx: %i )\n", + _pci_index, num_avail(), + _queue.used->idx,_queue.avail->idx + ); + panic("Buffer full"); + } // Remove buffers from the free list _num_free -= total; @@ -185,31 +187,31 @@ void Virtio::Queue::enqueue( // (implicitly) Mark all outbound tokens as device-readable if (out) - { - current().flags = VIRTQ_DESC_F_NEXT; - current().addr = (intptr_t) out; - current().len = out_len; - - debug(" Enqueueing outbound: index %u len %li, next %i\n", - _pci_index, head, current().len, current().next); - - last = ¤t(); - // go to next - go_next(); - } + { + current().flags = VIRTQ_DESC_F_NEXT; + current().addr = (intptr_t) out; + current().len = out_len; + + printf(" Enqueueing outbound: index %u len %u (actual: %u), next %d\n", + _pci_index, head, current().len, out_len, current().next); + + last = ¤t(); + // go to next + go_next(); + } // Mark all inbound tokens as device-writable if (in) - { - debug(" Enqueuing inbound \n"); - current().flags = VIRTQ_DESC_F_NEXT | VIRTQ_DESC_F_WRITE; - current().addr = (intptr_t) in; - current().len = in_len; - - last = ¤t(); - // go to next - go_next(); - } + { + printf(" Enqueuing inbound \n"); + current().flags = VIRTQ_DESC_F_NEXT | VIRTQ_DESC_F_WRITE; + current().addr = (intptr_t) in; + current().len = in_len; + + last = ¤t(); + // go to next + go_next(); + } // No continue on last buffer last->flags &= ~VIRTQ_DESC_F_NEXT; @@ -219,19 +221,57 @@ void Virtio::Queue::enqueue( _queue.avail->ring[avail] = head; debug(" avail: %u\n", _pci_index, avail); } +void Virtio::Queue::enqueue(void* data, uint32_t len, bool out, bool last) +{ + if (_num_free < 1) + { + // Queue is full (we think) + printf("Buffer full (%i avail," \ + " used.idx: %i, avail.idx: %i )\n", + _pci_index, num_avail(), + _queue.used->idx,_queue.avail->idx + ); + panic("Buffer full"); + } + + // Remove buffers from the free list + _num_free -= 1; + // remember current head for later + uint16_t head = _free_head; + // No continue on last buffer + uint16_t flags = last ? 0 : VIRTQ_DESC_F_NEXT; + // WRITE for inbound + current().flags = flags | (out ? 0 : VIRTQ_DESC_F_WRITE); + current().addr = (intptr_t) data; + current().len = len; + + if (out) + printf(" Enqueueing outbound: %p index %u len %u (actual: %u), next %d\n", + _pci_index, data, head, current().len, len, current().next); + else + printf(" Enqueueing inbound: %p index %u len %u (actual: %u), next %d\n", + _pci_index, data, head, current().len, len, current().next); + + // go to next in ring + go_next(); + + // SanOS: Put entry in available array, but do not update avail->idx until sync + uint16_t avail = (_queue.avail->idx + _num_added++) % _size; + _queue.avail->ring[avail] = head; +} void* Virtio::Queue::dequeue(uint32_t& len) { // Return NULL if there are no more completed buffers in the queue if (_last_used_idx == _queue.used->idx) - { - debug(" Can't dequeue - no used buffers \n",_pci_index); - return nullptr; - } + { + debug(" Can't dequeue - no used buffers \n",_pci_index); + return nullptr; + } // Get next completed buffer auto& e = _queue.used->ring[_last_used_idx % _size]; - debug2(" Releasing token %li. Len: %li\n",_pci_index, e.id, e.len); + printf(" Releasing token %u. Len: %u\n",_pci_index, e.id, e.len); void* data = (void*) _queue.desc[e.id].addr; len = e.len; From 7f29d6aca3c705054892ad79c53d7066dffeac4a Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 12 Apr 2016 20:06:13 +0200 Subject: [PATCH 141/311] Removed debug folder from example --- examples/tcp/debug/service.gdb | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 examples/tcp/debug/service.gdb diff --git a/examples/tcp/debug/service.gdb b/examples/tcp/debug/service.gdb deleted file mode 100644 index f5acb4ff3c..0000000000 --- a/examples/tcp/debug/service.gdb +++ /dev/null @@ -1,5 +0,0 @@ -file service -break _start -break OS::start -set non-stop off -target remote localhost:1234 \ No newline at end of file From 136d5720aa15e5498c213e8fda0ec97b8caf86f1 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 12 Apr 2016 21:27:05 +0200 Subject: [PATCH 142/311] Moved memory page stuff from common macros to OS --- api/common | 22 +++------------------- api/kernel/os.hpp | 47 ++++++++++++++++++++++++++++++----------------- 2 files changed, 33 insertions(+), 36 deletions(-) diff --git a/api/common b/api/common index ebf7cee857..6c363dd72a 100644 --- a/api/common +++ b/api/common @@ -7,9 +7,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -38,24 +38,13 @@ #error "This project needs to be compiled with an ix86-elf compiler" #endif -#ifndef __includeOS__ -#define __includeOS__ -#endif - -/* Unused parameters (necessary for syscall warnings) */ +/* Unused parameters */ #ifdef __GNUC__ # define UNUSED(x) UNUSED_ ## x __attribute__((__unused__)) #else # define UNUSED(x) UNUSED_ ## x #endif -/* Hardware @todo Make this more C++'ish and proper. */ -#define MAX_NICS 4 -#define MAX_DISKS 4 -#define MAX_SERIALS 4 - -/* LIMITS */ -//#define SBRK_MAX 0x10000 /* BOCHS Break point */ #define BREAK __asm__ volatile("xchg %bx,%bx"); @@ -65,9 +54,4 @@ #include "warn" #include "info" -// From sanos, pdir.h -#define PAGESHIFT 12 -#define BTOP(x) ((unsigned long)(x) >> PAGESHIFT) -#define PAGESIZE 4096 - #endif diff --git a/api/kernel/os.hpp b/api/kernel/os.hpp index 58f4e3fdf0..8f9a99c8ca 100644 --- a/api/kernel/os.hpp +++ b/api/kernel/os.hpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -35,23 +35,23 @@ namespace hw{ class Serial; } * @note For device access, see Dev */ class OS { -public: +public: using rsprint_func = delegate; - + /* Get the version of the os */ static inline std::string version() { return std::string(OS_VERSION); } - + /** Clock cycles since boot. */ static inline uint64_t cycles_since_boot() { uint64_t ret; __asm__ volatile ("rdtsc":"=A"(ret)); return ret; } - + /** Uptime in seconds. */ static double uptime(); - + /** * Write a cstring to serial port. @todo Should be moved to Dev::serial(n). * @@ -59,9 +59,9 @@ class OS { */ static size_t rsprint(const char* ptr); static size_t rsprint(const char* ptr, const size_t len); - + /** - * Write a character to serial port. + * Write a character to serial port. * * @param c: The character to print to serial port */ @@ -82,31 +82,44 @@ class OS { * we'll stay asleep. */ static void halt(); - + /** * Set handler for serial output. */ static void set_rsprint(rsprint_func func) { rsprint_handler_ = func; } - -private: + + /** Memory page helpers */ + static inline constexpr uint32_t page_size() { + return 4096; + } + static inline constexpr uint32_t page_nr_from_addr(uint32_t x){ + return x >> page_shift_; + } + static inline constexpr uint32_t base_from_page_nr(uint32_t x){ + return x << page_shift_; + } + +private: + static const int page_shift_ = 12; + /** Indicate if the OS is running. */ static bool power_; - + /** The main event loop. Check interrupts, timers etc., and do callbacks. */ static void event_loop(); - + static MHz cpu_mhz_; - + static rsprint_func rsprint_handler_; static hw::Serial& com1; - + // Prohibit copy and move operations OS(OS&) = delete; OS(OS&&) = delete; - + // Prohibit construction OS() = delete; }; //< OS From 910207710de188fa11c72b19743d374331b41da8 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 12 Apr 2016 21:41:53 +0200 Subject: [PATCH 143/311] Editorconfig NUKE v3 --- api/net/inet4.inc | 100 +++++++------- api/net/ip4/udp.hpp | 58 ++++---- api/net/ip4/udp_socket.hpp | 32 ++--- api/net/ip6/tcp6.hpp | 5 +- api/net/tcp.hpp | 14 +- examples/demo_service/service.cpp | 46 +++---- examples/tcp/service.cpp | 8 +- src/debug/test_disk.cpp | 120 ++++++++-------- src/debug/test_service.cpp | 104 +++++++------- src/fs/memdisk.cpp | 4 +- src/net/dhcp/dh4client.cpp | 220 +++++++++++++++--------------- src/net/dns/client.cpp | 28 ++-- src/net/ip4/udp.cpp | 114 ++++++++-------- src/net/ip4/udp_socket.cpp | 80 +++++------ src/net/ip6/ndp.cpp | 5 +- src/net/tcp.cpp | 4 +- src/net/tcp_connection.cpp | 41 +++--- src/net/tcp_connection_states.cpp | 6 +- src/virtio/block.cpp | 104 +++++++------- src/virtio/console.cpp | 64 ++++----- src/virtio/virtio.cpp | 122 ++++++++--------- src/virtio/virtio_queue.cpp | 114 ++++++++-------- test/GSL/service.cpp | 6 +- test/UDP/service.cpp | 30 ++-- test/fat/fat16.cpp | 50 +++---- test/fat/fat32.cpp | 122 ++++++++--------- test/serial/service.cpp | 20 ++- test/transmit/service.cpp | 44 +++--- 28 files changed, 828 insertions(+), 837 deletions(-) diff --git a/api/net/inet4.inc b/api/net/inet4.inc index 9e4e10ce79..5b9e7e0a81 100644 --- a/api/net/inet4.inc +++ b/api/net/inet4.inc @@ -4,78 +4,78 @@ namespace net { - template + template Inet4::Inet4(hw::Nic& nic, IP4::addr ip, IP4::addr netmask) - : ip4_addr_(ip), netmask_(netmask), router_(IP4::INADDR_ANY), - nic_(nic), eth_(nic.mac()), arp_(*this), ip4_(*this), - icmp_(*this), udp_(*this), tcp_(*this), dns(*this), + : ip4_addr_(ip), netmask_(netmask), router_(IP4::INADDR_ANY), + nic_(nic), eth_(nic.mac()), arp_(*this), ip4_(*this), + icmp_(*this), udp_(*this), tcp_(*this), dns(*this), bufstore_(nic.bufstore()) { - debug(" Constructor. TCP @ %p has %i open ports. \n", &tcp_, tcp_.openPorts()); + debug(" Constructor. TCP @ %p has %i open ports. \n", &tcp_, tcp_.openPorts()); INFO("Inet4","Bringing up the IP stack"); - - /** Upstream delegates */ + + /** Upstream delegates */ auto eth_bottom(upstream::from(eth_)); auto arp_bottom(upstream::from(arp_)); auto ip4_bottom(upstream::from(ip4_)); auto icmp4_bottom(upstream::from(icmp_)); auto udp4_bottom(upstream::from(udp_)); auto tcp_bottom(upstream::from(tcp_)); - + /** Upstream wiring */ // Packets available nic.on_transmit_queue_available( - transmit_avail_delg::from, &Inet4::process_sendq>(*this)); - + transmit_avail_delg::from, &Inet4::process_sendq>(*this)); + // Phys -> Eth (Later, this will be passed through router) nic.set_linklayer_out(eth_bottom); - + // Eth -> Arp eth_.set_arp_handler(arp_bottom); - + // Eth -> IP4 eth_.set_ip4_handler(ip4_bottom); - + // IP4 -> ICMP ip4_.set_icmp_handler(icmp4_bottom); - + // IP4 -> UDP ip4_.set_udp_handler(udp4_bottom); - + // IP4 -> TCP ip4_.set_tcp_handler(tcp_bottom); - + /** Downstream delegates */ auto phys_top(downstream ::from,&hw::Nic::transmit>(nic)); auto eth_top(downstream - ::from(eth_)); + ::from(eth_)); auto arp_top(downstream ::from(arp_)); auto ip4_top(downstream ::from(ip4_)); - + /** Downstream wiring. */ - + // ICMP -> IP4 icmp_.set_network_out(ip4_top); - + // UDP4 -> IP4 udp_.set_network_out(ip4_top); - + // TCP -> IP4 tcp_.set_network_out(ip4_top); - // IP4 -> Arp + // IP4 -> Arp ip4_.set_linklayer_out(arp_top); - + // Arp -> Eth arp_.set_linklayer_out(eth_top); - + // Eth -> Phys eth_.set_physical_out(phys_top); } - + template Inet4::Inet4(hw::Nic& nic) : Inet4(nic, IP4::INADDR_ANY, IP4::INADDR_ANY) @@ -84,50 +84,50 @@ namespace net dhcp_ = std::make_shared(*this); dhcp_->negotiate(); } - + template void Inet4::process_sendq(size_t packets) { //////////////////////////////////////////// // divide up fairly size_t div = packets / tqa.size(); - + // give each protocol a chance to take for (size_t i = 0; i < tqa.size(); i++) tqa[i](div); - + // hand out remaining for (size_t i = 0; i < tqa.size(); i++) - { - div = transmit_queue_available(); - if (!div) break; - // give as much as possible - tqa[i](div); - } + { + div = transmit_queue_available(); + if (!div) break; + // give as much as possible + tqa[i](div); + } //////////////////////////////////////////// - + /* - size_t list[tqa.size()]; - for (size_t i = 0; i < tqa.size(); i++) + size_t list[tqa.size()]; + for (size_t i = 0; i < tqa.size(); i++) list[i] = tqa[i](0); - - size_t give[tqa.size()] = {0}; - int cp = 0; // current protocol - - // distribute packets one at a time for each protocol - while (packets--) - { + + size_t give[tqa.size()] = {0}; + int cp = 0; // current protocol + + // distribute packets one at a time for each protocol + while (packets--) + { if (list[cp]) { - // give one packet - give[cp]++; list[cp]--; + // give one packet + give[cp]++; list[cp]--; } cp = (cp + 1) % tqa.size(); - } - // hand out several packets per protocol - for (size_t i = 0; i < tqa.size(); i++) + } + // hand out several packets per protocol + for (size_t i = 0; i < tqa.size(); i++) if (give[i]) tqa[i](give[i]); */ } - + } diff --git a/api/net/ip4/udp.hpp b/api/net/ip4/udp.hpp index 6e148e21c4..4356d219b2 100644 --- a/api/net/ip4/udp.hpp +++ b/api/net/ip4/udp.hpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -28,35 +28,35 @@ namespace net { class PacketUDP; class UDPSocket; - + /** Basic UDP support. @todo Implement UDP sockets. */ class UDP { public: using addr_t = IP4::addr; using port_t = uint16_t; - + using Packet_ptr = std::shared_ptr; using Stack = Inet; - + typedef delegate sendto_handler; - + // write buffer for sendq struct WriteBuffer { WriteBuffer( - const uint8_t* data, size_t length, sendto_handler cb, - UDP& udp, addr_t LA, port_t LP, addr_t DA, port_t DP); - + const uint8_t* data, size_t length, sendto_handler cb, + UDP& udp, addr_t LA, port_t LP, addr_t DA, port_t DP); + int remaining() const { return len - offset; } bool done() const { return offset == len; } - + size_t packets_needed() const; void write(); - + // buffer, total length and current write offset std::shared_ptr buf; size_t len; @@ -65,7 +65,7 @@ namespace net { sendto_handler callback; // the UDP stack UDP& udp; - + // port and addr this was being sent from addr_t l_addr; port_t l_port; @@ -73,7 +73,7 @@ namespace net { port_t d_port; addr_t d_addr; }; - + /** UDP header */ struct udp_header { port_t sport; @@ -81,64 +81,64 @@ namespace net { uint16_t length; uint16_t checksum; }; - + /** Full UDP Header with all sub-headers */ struct full_header { IP4::full_header full_hdr; udp_header udp_hdr; }__attribute__((packed)); - + //////////////////////////////////////////// - + addr_t local_ip() const { return stack_.ip_addr(); } - + /** Input from network layer */ void bottom(net::Packet_ptr); /** Delegate output to network layer */ void set_network_out(downstream del) { network_layer_out_ = del; } - - /** Send UDP datagram from source ip/port to destination ip/port. - + + /** Send UDP datagram from source ip/port to destination ip/port. + @param sip Local IP-address @param sport Local port @param dip Remote IP-address @param dport Remote port */ void transmit(UDP::Packet_ptr udp); - + //! @param port local port UDPSocket& bind(port_t port); - + //! returns a new UDP socket bound to a random port UDPSocket& bind(); - + //! construct this UDP module with @inet UDP(Stack& inet); - + Stack& stack() { return stack_; } - + // send as much as possible from sendq void flush(); // create and transmit @num packets from sendq void process_sendq(size_t num); - + private: - + downstream network_layer_out_; Stack& stack_; std::map ports_; port_t current_port_ {1024}; - + // the async send queue std::deque sendq; friend class net::UDPSocket; }; //< class UDP - + } //< namespace net #include "packet_udp.hpp" diff --git a/api/net/ip4/udp_socket.hpp b/api/net/ip4/udp_socket.hpp index c1ff815d48..ea5ea219ff 100644 --- a/api/net/ip4/udp_socket.hpp +++ b/api/net/ip4/udp_socket.hpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -29,10 +29,10 @@ namespace net typedef UDP::port_t port_t; typedef IP4::addr addr_t; typedef IP4::addr multicast_group_addr; - + typedef delegate recvfrom_handler; typedef UDP::sendto_handler sendto_handler; - + // constructors UDPSocket(UDP&, port_t port); UDPSocket(const UDPSocket&) = delete; @@ -40,23 +40,23 @@ namespace net // you from creating sockets, but then everyone is wasting time. // These are public to allow us to use emplace(...). // Use Stack.udp().bind(port) to get a valid Socket reference. - + // functions void on_read(recvfrom_handler callback) { on_read_handler = callback; } - void sendto(addr_t destIP, port_t port, - const void* buffer, size_t length, + void sendto(addr_t destIP, port_t port, + const void* buffer, size_t length, sendto_handler cb = [] {}); - void bcast(addr_t srcIP, port_t port, + void bcast(addr_t srcIP, port_t port, const void* buffer, size_t length, sendto_handler cb = [] {}); void close(); - + void join(multicast_group_addr); void leave(multicast_group_addr); - + // stuff addr_t local_addr() const { @@ -66,19 +66,19 @@ namespace net { return l_port; } - + private: void packet_init(UDP::Packet_ptr, addr_t, addr_t, port_t, uint16_t); void internal_read(UDP::Packet_ptr); - + UDP& udp; port_t l_port; - recvfrom_handler on_read_handler = - [] (addr_t, port_t, const char*, size_t) {}; - + recvfrom_handler on_read_handler = + [] (addr_t, port_t, const char*, size_t) {}; + bool reuse_addr; bool loopback; // true means multicast data is looped back to sender - + friend class UDP; friend class std::allocator; }; diff --git a/api/net/ip6/tcp6.hpp b/api/net/ip6/tcp6.hpp index 013ea32c32..96cd732076 100644 --- a/api/net/ip6/tcp6.hpp +++ b/api/net/ip6/tcp6.hpp @@ -6,12 +6,11 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. - diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index a9af1eb2b0..2f3f7b45c0 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -1159,9 +1159,9 @@ namespace net { /* When the first RTT measurement R is made, the host MUST set - SRTT <- R - RTTVAR <- R/2 - RTO <- SRTT + max (G, K*RTTVAR) + SRTT <- R + RTTVAR <- R/2 + RTO <- SRTT + max (G, K*RTTVAR) where K = 4. */ @@ -1174,8 +1174,8 @@ namespace net { /* When a subsequent RTT measurement R' is made, a host MUST set - RTTVAR <- (1 - beta) * RTTVAR + beta * |SRTT - R'| - SRTT <- (1 - alpha) * SRTT + alpha * R' + RTTVAR <- (1 - beta) * RTTVAR + beta * |SRTT - R'| + SRTT <- (1 - alpha) * SRTT + alpha * R' The value of SRTT used in the update to RTTVAR is its value before updating SRTT itself using the second assignment. That @@ -1388,7 +1388,7 @@ namespace net { inline void reduce_slow_start_threshold() { control_block.ssthresh = std::max( (flight_size() / 2), (2 * SMSS()) ); debug2("TCP::Connection::reduce_slow_start_threshold> Slow start threshold reduced: %u\n", - control_block.ssthresh); + control_block.ssthresh); } inline void segment_loss_detected() { @@ -1396,7 +1396,7 @@ namespace net { } /* - */ + */ size_t duplicate_ack(TCP::Seq ack); /* diff --git a/examples/demo_service/service.cpp b/examples/demo_service/service.cpp index dd7fa0cd98..b16cdbbb6d 100644 --- a/examples/demo_service/service.cpp +++ b/examples/demo_service/service.cpp @@ -88,30 +88,30 @@ void Service::start() { // Add a TCP connection handler - here a hardcoded HTTP-service server.onAccept([](auto conn) -> bool { - printf(" @onAccept - Connection attempt from: %s \n", - conn->to_string().c_str()); - return true; // allow all connections - - }).onConnect([](auto conn) { - printf(" @onConnect - Connection successfully established.\n"); - // read async with a buffer size of 1024 bytes - // define what to do when data is read - conn->read(1024, [conn](net::TCP::buffer_t buf, size_t n) { - // create string from buffer - std::string data { (char*)buf.get(), n }; - printf(" @read:\n%s\n", data.c_str()); - - // create response - std::string response = HTML_RESPONSE(); - // write the data from the string with the strings size - conn->write(response.data(), response.size(), [](size_t n) { - printf(" @write: %u bytes written\n", n); + printf(" @onAccept - Connection attempt from: %s \n", + conn->to_string().c_str()); + return true; // allow all connections + + }).onConnect([](auto conn) { + printf(" @onConnect - Connection successfully established.\n"); + // read async with a buffer size of 1024 bytes + // define what to do when data is read + conn->read(1024, [conn](net::TCP::buffer_t buf, size_t n) { + // create string from buffer + std::string data { (char*)buf.get(), n }; + printf(" @read:\n%s\n", data.c_str()); + + // create response + std::string response = HTML_RESPONSE(); + // write the data from the string with the strings size + conn->write(response.data(), response.size(), [](size_t n) { + printf(" @write: %u bytes written\n", n); + }); + }); + + }).onDisconnect([](auto, auto reason) { + printf(" @onDisconnect - Reason: %s \n", reason.to_string().c_str()); }); - }); - - }).onDisconnect([](auto, auto reason) { - printf(" @onDisconnect - Reason: %s \n", reason.to_string().c_str()); - }); printf("*** TEST SERVICE STARTED *** \n"); } diff --git a/examples/tcp/service.cpp b/examples/tcp/service.cpp index 534438dc07..bbed1ce741 100644 --- a/examples/tcp/service.cpp +++ b/examples/tcp/service.cpp @@ -85,14 +85,14 @@ void Service::start() { // Setup handlers for when data is received on client and python connection // When client reads data client->read(1024, [python](auto buf, size_t n) { - std::string data{ (char*)buf.get(), n }; - handle_client_on_read(python, data); + std::string data{ (char*)buf.get(), n }; + handle_client_on_read(python, data); }); // When python server reads data python->read(1024, [client](auto buf, size_t n) { - std::string data{ (char*)buf.get(), n }; - handle_python_on_read(client, data); + std::string data{ (char*)buf.get(), n }; + handle_python_on_read(client, data); }); // When client is disconnecting diff --git a/src/debug/test_disk.cpp b/src/debug/test_disk.cpp index a8d969d824..7ab5d4726e 100644 --- a/src/debug/test_disk.cpp +++ b/src/debug/test_disk.cpp @@ -14,78 +14,78 @@ void Service::start() auto& device = hw::Dev::disk<1, VirtioBlk>(); disk = std::make_shared (device); assert(disk); - + // if the disk is empty, we can't mount a filesystem anyways if (disk->empty()) panic("Oops! The disk is empty!\n"); - + // list extended partitions list_partitions(disk); - + // mount first valid partition (auto-detect and mount) disk->mount( - [] (fs::error_t err) - { - if (err) - { - printf("Could not mount filesystem\n"); - return; - } - - // async ls - disk->fs().ls("/", - [] (fs::error_t err, auto ents) - { - if (err) - { - printf("Could not list '/' directory\n"); - return; - } - - // go through directory entries - for (auto& e : *ents) - { - printf("%s: %s\t of size %llu bytes (CL: %llu)\n", - e.type_string().c_str(), e.name().c_str(), e.size, e.block); + [] (fs::error_t err) + { + if (err) + { + printf("Could not mount filesystem\n"); + return; + } + + // async ls + disk->fs().ls("/", + [] (fs::error_t err, auto ents) + { + if (err) + { + printf("Could not list '/' directory\n"); + return; + } - if (e.is_file()) - { - printf("*** Attempting to read: %s\n", e.name().c_str()); - disk->fs().read(e, 0, e.size, - [e] (fs::error_t err, fs::buffer_t buffer, size_t len) - { - if (err) - { - printf("Failed to read file %s!\n", - e.name().c_str()); - return; - } + // go through directory entries + for (auto& e : *ents) + { + printf("%s: %s\t of size %llu bytes (CL: %llu)\n", + e.type_string().c_str(), e.name().c_str(), e.size, e.block); + + if (e.is_file()) + { + printf("*** Attempting to read: %s\n", e.name().c_str()); + disk->fs().read(e, 0, e.size, + [e] (fs::error_t err, fs::buffer_t buffer, size_t len) + { + if (err) + { + printf("Failed to read file %s!\n", + e.name().c_str()); + return; + } + + std::string contents((const char*) buffer.get(), len); + printf("[%s contents]:\n%s\nEOF\n\n", + e.name().c_str(), contents.c_str()); + }); + } + } + }); + + }); // disk->auto_detect() - std::string contents((const char*) buffer.get(), len); - printf("[%s contents]:\n%s\nEOF\n\n", - e.name().c_str(), contents.c_str()); - }); - } - } - }); - - }); // disk->auto_detect() - printf("*** TEST SERVICE STARTED *** \n"); } void list_partitions(decltype(disk) disk) { disk->partitions( - [] (fs::error_t err, auto& parts) - { - if (err) - { - printf("Failed to retrieve volumes on disk\n"); - return; - } - - for (auto& part : parts) - printf("[Partition] '%s' at LBA %u\n", - part.name().c_str(), part.lba()); - }); + [] (fs::error_t err, auto& parts) + { + if (err) + { + printf("Failed to retrieve volumes on disk\n"); + return; + } + + for (auto& part : parts) + printf("[Partition] '%s' at LBA %u\n", + part.name().c_str(), part.lba()); + }); } diff --git a/src/debug/test_service.cpp b/src/debug/test_service.cpp index 0a156756d7..49fc5b85cb 100644 --- a/src/debug/test_service.cpp +++ b/src/debug/test_service.cpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -31,37 +31,37 @@ void Service::start() hw::Nic& eth0 = hw::Dev::eth<0,VirtioNet>(); inet = std::make_unique >(eth0); inet->network_config( - {{ 10,0,0,42 }}, // IP - {{ 255,255,255,0 }}, // Netmask - {{ 10,0,0,1 }}, // Gateway - {{ 8,8,8,8 }} ); // DNS - + {{ 10,0,0,42 }}, // IP + {{ 255,255,255,0 }}, // Netmask + {{ 10,0,0,1 }}, // Gateway + {{ 8,8,8,8 }} ); // DNS + /* - auto& tcp = inet->tcp(); - auto& server = tcp.bind(6667); // IRCd default port - server.onConnect( - [] (auto csock) - { + auto& tcp = inet->tcp(); + auto& server = tcp.bind(6667); // IRCd default port + server.onConnect( + [] (auto csock) + { printf("*** Received connection from %s\n", csock->remote().to_string().c_str()); - + /// create client /// size_t index = clients.size(); clients.emplace_back(index, csock); - + auto& client = clients[index]; - + // set up callbacks csock->onReceive( [&client] (auto conn, bool) { char buffer[1024]; size_t bytes = conn->read(buffer, sizeof(buffer)); - + client.read(buffer, bytes); - + }); - + .onDisconnect( [&client] (auto conn, std::string) { @@ -70,43 +70,43 @@ void Service::start() /// inform others about disconnect //client.bcast(TK_QUIT, "Disconnected"); }); - });*/ - + });*/ + using namespace net; const UDP::port_t port = 4242; auto& sock = inet->udp().bind(port); - + sock.on_read( - [&sock] (UDP::addr_t addr, UDP::port_t port, - const char* data, size_t len) - { - std::string strdata(data, len); - CHECK(1, "Getting UDP data from %s:%d -> %s", - addr.str().c_str(), port, strdata.c_str()); - // send the same thing right back! - sock.sendto(addr, port, data, len, - [&sock, addr, port] - { - // print this message once - printf("*** Starting spam (you should see this once)\n"); - - typedef std::function rnd_gen_t; - auto next = std::make_shared (); - - *next = - [next, &sock, addr, port] () - { - // spam this message at max speed - std::string text("Spamorino Cappucino\n"); - - sock.sendto(addr, port, text.data(), text.size(), - [next] { (*next)(); }); - }; - - // start spamming - (*next)(); - }); - }); - + [&sock] (UDP::addr_t addr, UDP::port_t port, + const char* data, size_t len) + { + std::string strdata(data, len); + CHECK(1, "Getting UDP data from %s:%d -> %s", + addr.str().c_str(), port, strdata.c_str()); + // send the same thing right back! + sock.sendto(addr, port, data, len, + [&sock, addr, port] + { + // print this message once + printf("*** Starting spam (you should see this once)\n"); + + typedef std::function rnd_gen_t; + auto next = std::make_shared (); + + *next = + [next, &sock, addr, port] () + { + // spam this message at max speed + std::string text("Spamorino Cappucino\n"); + + sock.sendto(addr, port, text.data(), text.size(), + [next] { (*next)(); }); + }; + + // start spamming + (*next)(); + }); + }); + printf("*** TEST SERVICE STARTED *** \n"); } diff --git a/src/fs/memdisk.cpp b/src/fs/memdisk.cpp index 84fe6c3148..2d5619f06e 100644 --- a/src/fs/memdisk.cpp +++ b/src/fs/memdisk.cpp @@ -40,7 +40,7 @@ namespace fs { auto sector_loc = image_start_ + (blk * block_size()); // Disallow reading memory past disk image if (unlikely(sector_loc >= image_end_)) { - reader(buffer_t()); return; + reader(buffer_t()); return; } auto buffer = new uint8_t[block_size()]; @@ -54,7 +54,7 @@ namespace fs { auto end_loc = start_loc + (count * block_size()); // Disallow reading memory past disk image if (unlikely(end_loc >= image_end_)) { - reader(buffer_t()); return; + reader(buffer_t()); return; } auto buffer = new uint8_t[count * block_size()]; diff --git a/src/net/dhcp/dh4client.cpp b/src/net/dhcp/dh4client.cpp index 948f21ee7b..8d23d662d1 100644 --- a/src/net/dhcp/dh4client.cpp +++ b/src/net/dhcp/dh4client.cpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -27,20 +27,20 @@ // BOOTP (rfc951) message types #define BOOTREQUEST 1 #define BOOTREPLY 2 - + // Possible values for flags field #define BOOTP_UNICAST 0x0000 #define BOOTP_BROADCAST 0x8000 - + // Possible values for hardware type (htype) field #define HTYPE_ETHER 1 // Ethernet 10Mbps #define HTYPE_IEEE802 6 // IEEE 802.2 Token Ring #define HTYPE_FDDI 8 // FDDI - + /* Magic cookie validating dhcp options field (and bootp vendor extensions field). */ #define DHCP_OPTIONS_COOKIE "\143\202\123\143" - + // DHCP Option codes #define DHO_PAD 0 #define DHO_SUBNET_MASK 1 @@ -154,17 +154,17 @@ namespace net { return (dhcp_option_t*) option; } - + void DHClient::negotiate() { // create a random session ID this->xid = OS::cycles_since_boot() & 0xFFFFFFFF; MYINFO("Negotiating IP-address (xid=%u)", xid); - + // create DHCP discover packet const size_t packetlen = sizeof(dhcp_packet_t); char packet[packetlen]; - + dhcp_packet_t* dhcp = (dhcp_packet_t*) packet; dhcp->op = BOOTREQUEST; dhcp->htype = HTYPE_ETHER; @@ -177,20 +177,20 @@ namespace net dhcp->yiaddr = IP4::INADDR_ANY; dhcp->siaddr = IP4::INADDR_ANY; dhcp->giaddr = IP4::INADDR_ANY; - + Ethernet::addr link_addr = stack.link_addr(); - + // copy our hardware address to chaddr field memset(dhcp->chaddr, 0, dhcp_packet_t::CHADDR_LEN); memcpy(dhcp->chaddr, &link_addr, ETH_ALEN); // zero server, file and options memset(dhcp->sname, 0, dhcp_packet_t::SNAME_LEN + dhcp_packet_t::FILE_LEN); - + dhcp->magic[0] = 99; dhcp->magic[1] = 130; dhcp->magic[2] = 83; dhcp->magic[3] = 99; - + dhcp_option_t* opt = conv_option(dhcp->options + 0); // DHCP discover opt->code = DHO_DHCP_MESSAGE_TYPE; @@ -213,124 +213,124 @@ namespace net opt = conv_option(dhcp->options + 17); opt->code = DHO_END; opt->length = 0; - + //////////////////////////////////////////////////////// auto& socket = stack.udp().bind(DHCP_SOURCE_PORT); /// broadcast our DHCP plea as 0.0.0.0:67 socket.bcast(IP4::INADDR_ANY, DHCP_DEST_PORT, packet, packetlen); - + socket.on_read( - [this, &socket] (IP4::addr, UDP::port_t port, - const char* data, size_t len) - { - if (port == DHCP_DEST_PORT) - { - // we have got a DHCP Offer - debug("Received possible DHCP OFFER from %s:%d\n", - addr.str().c_str(), DHCP_DEST_PORT); - this->offer(socket, data, len); - } - }); + [this, &socket] (IP4::addr, UDP::port_t port, + const char* data, size_t len) + { + if (port == DHCP_DEST_PORT) + { + // we have got a DHCP Offer + debug("Received possible DHCP OFFER from %s:%d\n", + addr.str().c_str(), DHCP_DEST_PORT); + this->offer(socket, data, len); + } + }); } - + const dhcp_option_t* get_option(const uint8_t* options, uint8_t code) { const dhcp_option_t* opt = (const dhcp_option_t*) options; while (opt->code != code && opt->code != DHO_END) - { - // go to next option - opt = (const dhcp_option_t*) (((const uint8_t*) opt) + 2 + opt->length); - } + { + // go to next option + opt = (const dhcp_option_t*) (((const uint8_t*) opt) + 2 + opt->length); + } return opt; } - + void DHClient::offer(UDPSocket& sock, const char* data, size_t) { const dhcp_packet_t* dhcp = (const dhcp_packet_t*) data; - + uint32_t xid = htonl(dhcp->xid); // silently ignore transactions not our own if (xid != this->xid) return; - + // check if the BOOTP message is a DHCP OFFER const dhcp_option_t* opt; opt = get_option(dhcp->options, DHO_DHCP_MESSAGE_TYPE); - + if (opt->code == DHO_DHCP_MESSAGE_TYPE) - { - // verify that the type is indeed DHCPOFFER - debug("Found DHCP message type %d (DHCP Offer = %d)\n", - opt->val[0], DHCPOFFER); - - // ignore when not a DHCP Offer - if (opt->val[0] != DHCPOFFER) return; - } + { + // verify that the type is indeed DHCPOFFER + debug("Found DHCP message type %d (DHCP Offer = %d)\n", + opt->val[0], DHCPOFFER); + + // ignore when not a DHCP Offer + if (opt->val[0] != DHCPOFFER) return; + } // ignore message when DHCP message type is missing else return; - + // the offered IP address: this->ipaddr = dhcp->yiaddr; MYINFO("IP ADDRESS: \t%s", this->ipaddr.str().c_str()); - + opt = get_option(dhcp->options, DHO_SUBNET_MASK); if (opt->code == DHO_SUBNET_MASK) - { - memcpy(&this->netmask, opt->val, sizeof(IP4::addr)); - MYINFO("SUBNET MASK: \t%s", - this->netmask.str().c_str()); - } - + { + memcpy(&this->netmask, opt->val, sizeof(IP4::addr)); + MYINFO("SUBNET MASK: \t%s", + this->netmask.str().c_str()); + } + opt = get_option(dhcp->options, DHO_DHCP_LEASE_TIME); if (opt->code == DHO_DHCP_LEASE_TIME) - { - memcpy(&this->lease_time, opt->val, sizeof(this->lease_time)); - MYINFO("LEASE TIME: \t%u mins", this->lease_time / 60); - } - + { + memcpy(&this->lease_time, opt->val, sizeof(this->lease_time)); + MYINFO("LEASE TIME: \t%u mins", this->lease_time / 60); + } + // now validate the offer, checking for minimum information opt = get_option(dhcp->options, DHO_ROUTERS); if (opt->code == DHO_ROUTERS) - { - memcpy(&this->router, opt->val, sizeof(IP4::addr)); - MYINFO("GATEWAY: \t%s", - this->router.str().c_str()); - } - // assume that the server we received the request from is the gateway - else - { - opt = get_option(dhcp->options, DHO_DHCP_SERVER_IDENTIFIER); - if (opt->code == DHO_DHCP_SERVER_IDENTIFIER) { memcpy(&this->router, opt->val, sizeof(IP4::addr)); MYINFO("GATEWAY: \t%s", this->router.str().c_str()); } - // silently ignore when both ROUTER and SERVER_ID is missing - else return; - } - + // assume that the server we received the request from is the gateway + else + { + opt = get_option(dhcp->options, DHO_DHCP_SERVER_IDENTIFIER); + if (opt->code == DHO_DHCP_SERVER_IDENTIFIER) + { + memcpy(&this->router, opt->val, sizeof(IP4::addr)); + MYINFO("GATEWAY: \t%s", + this->router.str().c_str()); + } + // silently ignore when both ROUTER and SERVER_ID is missing + else return; + } + opt = get_option(dhcp->options, DHO_DOMAIN_NAME_SERVERS); if (opt->code == DHO_DOMAIN_NAME_SERVERS) - { - memcpy(&this->dns_server, opt->val, sizeof(IP4::addr)); - } + { + memcpy(&this->dns_server, opt->val, sizeof(IP4::addr)); + } else - { // just try using ROUTER as DNS server - this->dns_server = this->router; - } + { // just try using ROUTER as DNS server + this->dns_server = this->router; + } MYINFO("DNS SERVER: \t%s", this->dns_server.str().c_str()); - + // we can accept the offer now by requesting the IP! this->request(sock); } - + void DHClient::request(UDPSocket& sock) { // form a response const size_t packetlen = sizeof(dhcp_packet_t); char packet[packetlen]; - + dhcp_packet_t* resp = (dhcp_packet_t*) packet; resp->op = BOOTREQUEST; resp->htype = HTYPE_ETHER; @@ -339,14 +339,14 @@ namespace net resp->xid = htonl(this->xid); resp->secs = 0; resp->flags = htons(BOOTP_UNICAST); - + resp->ciaddr = IP4::INADDR_ANY; resp->yiaddr = IP4::INADDR_ANY; resp->siaddr = IP4::INADDR_ANY; resp->giaddr = IP4::INADDR_ANY; - + Ethernet::addr link_addr = stack.link_addr(); - + // copy our hardware address to chaddr field memset(resp->chaddr, 0, dhcp_packet_t::CHADDR_LEN); memcpy(resp->chaddr, &link_addr, ETH_ALEN); @@ -357,7 +357,7 @@ namespace net resp->magic[1] = 130; resp->magic[2] = 83; resp->magic[3] = 99; - + dhcp_option_t* opt = conv_option(resp->options + 0); // DHCP Request opt->code = DHO_DHCP_MESSAGE_TYPE; @@ -390,52 +390,52 @@ namespace net opt = conv_option(resp->options + 29); opt->code = DHO_END; opt->length = 0; - + // set our onRead function to point to a hopeful DHCP ACK! sock.on_read( - [this] (IP4::addr, UDP::port_t port, - const char* data, size_t len) - { - if (port == DHCP_DEST_PORT) - { - // we have hopefully got a DHCP Ack - debug("\tReceived DHCP ACK from %s:%d\n", - addr.str().c_str(), DHCP_DEST_PORT); - this->acknowledge(data, len); - } - }); - + [this] (IP4::addr, UDP::port_t port, + const char* data, size_t len) + { + if (port == DHCP_DEST_PORT) + { + // we have hopefully got a DHCP Ack + debug("\tReceived DHCP ACK from %s:%d\n", + addr.str().c_str(), DHCP_DEST_PORT); + this->acknowledge(data, len); + } + }); + // send our DHCP Request sock.bcast(IP4::INADDR_ANY, DHCP_DEST_PORT, packet, packetlen); } - + void DHClient::acknowledge(const char* data, size_t) { const dhcp_packet_t* dhcp = (const dhcp_packet_t*) data; - + uint32_t xid = htonl(dhcp->xid); // silently ignore transactions not our own if (xid != this->xid) return; - + // check if the BOOTP message is a DHCP OFFER const dhcp_option_t* opt; opt = get_option(dhcp->options, DHO_DHCP_MESSAGE_TYPE); - + if (opt->code == DHO_DHCP_MESSAGE_TYPE) - { - // verify that the type is indeed DHCPOFFER - debug("\tFound DHCP message type %d (DHCP Ack = %d)\n", - opt->val[0], DHCPACK); - - // ignore when not a DHCP Offer - if (opt->val[0] != DHCPACK) return; - } + { + // verify that the type is indeed DHCPOFFER + debug("\tFound DHCP message type %d (DHCP Ack = %d)\n", + opt->val[0], DHCPACK); + + // ignore when not a DHCP Offer + if (opt->val[0] != DHCPACK) return; + } // ignore message when DHCP message type is missing else return; - + // configure our network stack MYINFO("Server acknowledged our request!"); - stack.network_config(this->ipaddr, this->netmask, + stack.network_config(this->ipaddr, this->netmask, this->router, this->dns_server); // run some post-DHCP event to release the hounds this->config_handler(stack); diff --git a/src/net/dns/client.cpp b/src/net/dns/client.cpp index 902caa3106..f90ba0b480 100644 --- a/src/net/dns/client.cpp +++ b/src/net/dns/client.cpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -25,27 +25,27 @@ namespace net void DNSClient::resolve(IP4::addr dns_server, const std::string& hostname, Stack::resolve_func func) { auto& sock = stack.udp().bind(); - + // create DNS request DNS::Request request; auto* data = new char[256]; size_t len = request.create(data, hostname); - + // send request to DNS server sock.sendto(dns_server, DNS::DNS_SERVICE_PORT, data, len); delete[] data; - + // wait for response // FIXME: WE DO NOT CHECK TRANSACTION IDS HERE (yet), GOD HELP US ALL sock.on_read( - [this, hostname, request, func] - (IP4::addr, UDP::port_t, const char* data, size_t) mutable - { - // original request ID = this->id; - request.parseResponse(data); - - // fire onResolve event - func(this->stack, hostname, request.getFirstIP4()); - }); + [this, hostname, request, func] + (IP4::addr, UDP::port_t, const char* data, size_t) mutable + { + // original request ID = this->id; + request.parseResponse(data); + + // fire onResolve event + func(this->stack, hostname, request.getFirstIP4()); + }); } } diff --git a/src/net/ip4/udp.cpp b/src/net/ip4/udp.cpp index 7aa8922dca..cfea2c4868 100644 --- a/src/net/ip4/udp.cpp +++ b/src/net/ip4/udp.cpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -31,25 +31,25 @@ namespace net { { network_layer_out_ = [] (net::Packet_ptr) {}; inet.on_transmit_queue_available( - transmit_avail_delg::from(this)); + transmit_avail_delg::from(this)); } - + void UDP::bottom(net::Packet_ptr pckt) { - std::shared_ptr udp = + std::shared_ptr udp = std::static_pointer_cast (pckt); - + debug("\t Source port: %i, Dest. Port: %i Length: %i\n", udp->src_port(), udp->dst_port(), udp->length()); - + auto it = ports_.find(udp->dst_port()); if (it != ports_.end()) - { - debug(" Someone's listening to this port. Forwarding...\n"); - it->second.internal_read(udp); - return; - } - + { + debug(" Someone's listening to this port. Forwarding...\n"); + it->second.internal_read(udp); + return; + } + debug(" Nobody's listening to this port. Drop!\n"); } @@ -61,24 +61,24 @@ namespace net { if (likely(it == ports_.end())) { // create new socket auto res = ports_.emplace( - std::piecewise_construct, - std::forward_as_tuple(port), - std::forward_as_tuple(*this, port)); + std::piecewise_construct, + std::forward_as_tuple(port), + std::forward_as_tuple(*this, port)); it = res.first; } return it->second; } - UDPSocket& UDP::bind() { + UDPSocket& UDP::bind() { if (ports_.size() >= 0xfc00) - panic("UPD Socket: All ports taken!"); + panic("UPD Socket: All ports taken!"); - debug("UDP finding free ephemeral port\n"); + debug("UDP finding free ephemeral port\n"); while (ports_.find(++current_port_) != ports_.end()) // prevent automatic ports under 1024 if (current_port_ == 0) current_port_ = 1024; - + debug("UDP binding to %i port\n", current_port_); return bind(current_port_); } @@ -88,45 +88,45 @@ namespace net { udp->length(), udp->ip4_segment_size(), udp->src().str().c_str(), udp->dst().str().c_str(), udp->dst_port()); - + assert(udp->length() >= sizeof(udp_header)); assert(udp->protocol() == IP4::IP4_UDP); - + auto pckt = Packet::packet(udp); network_layer_out_(pckt); } - + void UDP::flush() { size_t packets = stack_.transmit_queue_available(); if (packets) process_sendq(packets); } - + void UDP::process_sendq(size_t num) { while (!sendq.empty() && num != 0) - { - WriteBuffer& buffer = sendq.front(); - - // create and transmit packet from writebuffer - buffer.write(); - num--; - - if (buffer.done()) { - auto copy = buffer.callback; - // remove buffer from queue - sendq.pop_front(); - // call on_written callback - copy(); - // reduce @num, just in case packets were sent in - // another stack frame - size_t avail = stack_.transmit_queue_available(); - num = (num > avail) ? avail : num; + WriteBuffer& buffer = sendq.front(); + + // create and transmit packet from writebuffer + buffer.write(); + num--; + + if (buffer.done()) + { + auto copy = buffer.callback; + // remove buffer from queue + sendq.pop_front(); + // call on_written callback + copy(); + // reduce @num, just in case packets were sent in + // another stack frame + size_t avail = stack_.transmit_queue_available(); + num = (num > avail) ? avail : num; + } } - } } - + size_t UDP::WriteBuffer::packets_needed() const { int r = remaining(); @@ -137,50 +137,50 @@ namespace net { return P; } UDP::WriteBuffer::WriteBuffer( - const uint8_t* data, size_t length, sendto_handler cb, - UDP& stack, addr_t LA, port_t LP, addr_t DA, port_t DP) - : len(length), offset(0), callback(cb), udp(stack), - l_addr(LA), l_port(LP), d_port(DP), d_addr(DA) + const uint8_t* data, size_t length, sendto_handler cb, + UDP& stack, addr_t LA, port_t LP, addr_t DA, port_t DP) + : len(length), offset(0), callback(cb), udp(stack), + l_addr(LA), l_port(LP), d_port(DP), d_addr(DA) { // create a copy of the data, auto* copy = new uint8_t[len]; memcpy(copy, data, length); // make it shared - this->buf = + this->buf = std::shared_ptr (copy, std::default_delete()); } - + void UDP::WriteBuffer::write() { const size_t MTU = udp.stack().MTU(); - + // the maximum we can write per packet: const size_t WRITE_MAX = MTU - PacketUDP::HEADERS_SIZE; // the bytes remaining to be written size_t total = remaining(); total = (total > WRITE_MAX) ? WRITE_MAX : total; - + // create some packet p (and convert it to PacketUDP) auto p = udp.stack().createPacket(MTU); // fill buffer (at payload position) - memcpy(p->buffer() + PacketUDP::HEADERS_SIZE, + memcpy(p->buffer() + PacketUDP::HEADERS_SIZE, buf.get() + this->offset, total); - + // initialize packet with several infos auto p2 = std::static_pointer_cast(p); - + p2->init(); p2->header().sport = htons(l_port); p2->header().dport = htons(d_port); p2->set_src(l_addr); p2->set_dst(d_addr); p2->set_length(total); - + // ship the packet udp.transmit(p2); - + // next position in buffer this->offset += total; } - + } //< namespace net diff --git a/src/net/ip4/udp_socket.cpp b/src/net/ip4/udp_socket.cpp index 193997a301..3622ed85c2 100644 --- a/src/net/ip4/udp_socket.cpp +++ b/src/net/ip4/udp_socket.cpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -24,15 +24,15 @@ namespace net { UDPSocket::UDPSocket(UDP& udp_, port_t port) - : udp(udp_), l_port(port) + : udp(udp_), l_port(port) {} - + void UDPSocket::packet_init( - UDP::Packet_ptr p, - addr_t srcIP, - addr_t destIP, - port_t port, - uint16_t length) + UDP::Packet_ptr p, + addr_t srcIP, + addr_t destIP, + port_t port, + uint16_t length) { p->init(); p->header().sport = htons(this->l_port); @@ -40,49 +40,49 @@ namespace net p->set_src(srcIP); p->set_dst(destIP); p->set_length(length); - + assert(p->data_length() == length); } - + void UDPSocket::internal_read(UDP::Packet_ptr udp) { on_read_handler( - udp->src(), udp->src_port(), udp->data(), udp->data_length()); + udp->src(), udp->src_port(), udp->data(), udp->data_length()); } - + void UDPSocket::sendto( - addr_t destIP, - port_t port, - const void* buffer, - size_t len, - sendto_handler cb) + addr_t destIP, + port_t port, + const void* buffer, + size_t len, + sendto_handler cb) { if (likely(len)) - { - udp.sendq.emplace_back( - (const uint8_t*) buffer, len, cb, this->udp, - local_addr(), this->l_port, destIP, port); - - // UDP packets are meant to be sent immediately, so try flushing - udp.flush(); - } + { + udp.sendq.emplace_back( + (const uint8_t*) buffer, len, cb, this->udp, + local_addr(), this->l_port, destIP, port); + + // UDP packets are meant to be sent immediately, so try flushing + udp.flush(); + } } void UDPSocket::bcast( - addr_t srcIP, - port_t port, - const void* buffer, - size_t len, - sendto_handler cb) + addr_t srcIP, + port_t port, + const void* buffer, + size_t len, + sendto_handler cb) { if (likely(len)) - { - udp.sendq.emplace_back( - (const uint8_t*) buffer, len, cb, this->udp, - srcIP, this->l_port, IP4::INADDR_BCAST, port); - - // UDP packets are meant to be sent immediately, so try flushing - udp.flush(); - } + { + udp.sendq.emplace_back( + (const uint8_t*) buffer, len, cb, this->udp, + srcIP, this->l_port, IP4::INADDR_BCAST, port); + + // UDP packets are meant to be sent immediately, so try flushing + udp.flush(); + } } - + } diff --git a/src/net/ip6/ndp.cpp b/src/net/ip6/ndp.cpp index 3faa99847d..7dde0dcbfc 100644 --- a/src/net/ip6/ndp.cpp +++ b/src/net/ip6/ndp.cpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,4 +16,3 @@ // limitations under the License. #include - diff --git a/src/net/tcp.cpp b/src/net/tcp.cpp index 609fac7e37..5c5a4932fc 100644 --- a/src/net/tcp.cpp +++ b/src/net/tcp.cpp @@ -199,7 +199,7 @@ void TCP::process_write_queue(size_t packets) { // mark the connection as not queued. conn->set_queued(false); debug2(" %s Removed from queue. Size is %u\n", - conn->to_string().c_str(), write_queue.size()); + conn->to_string().c_str(), write_queue.size()); } } } @@ -216,7 +216,7 @@ size_t TCP::send(Connection_ptr conn, Connection::WriteBuffer& buffer) { write_queue.push(conn); conn->set_queued(true); debug2(" %s wrote %u bytes (%u remaining) and is Re-queued.\n", - conn->to_string().c_str(), written, buffer.remaining-written); + conn->to_string().c_str(), written, buffer.remaining-written); } return written; diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index b8020b10bd..a6a8272a6b 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -117,7 +117,7 @@ void Connection::write(WriteBuffer buffer, WriteCallback callback) { bool Connection::offer(size_t& packets) { assert(packets); debug(" %s got offered [%u] packets. Usable window is %i.\n", - to_string().c_str(), packets, usable_window()); + to_string().c_str(), packets, usable_window()); while(has_doable_job() and packets) { auto& buf = write_queue.front().first; @@ -126,7 +126,7 @@ bool Connection::offer(size_t& packets) { // advance the buffer buf.advance(written); debug2(" Wrote %u bytes (%u remaining) with [%u] packets left and a usable window of %i.\n", - written, buf.remaining, packets, usable_window()); + written, buf.remaining, packets, usable_window()); // if finished if(!buf.remaining) { // callback and remove object @@ -137,7 +137,7 @@ bool Connection::offer(size_t& packets) { } assert(packets >= 0); debug(" Finished working offer with [%u] packets left and a queue of (%u) with a usable window of %i\n", - packets, write_queue.size(), usable_window()); + packets, write_queue.size(), usable_window()); return !has_doable_job(); } @@ -162,7 +162,7 @@ size_t Connection::send(const char* buffer, size_t remaining, size_t& packet_cou remaining -= written; debug2(" Packet Limit: %u - Written: %u" - " - Remaining: %u - Packet count: %u, Window: %u\n", + " - Remaining: %u - Packet count: %u, Window: %u\n", packet_limit, written, remaining, packet_count, usable_window()); // If last packet, add PUSH. @@ -311,25 +311,25 @@ void Connection::queue_retransmission(TCP::Packet_ptr packet, size_t rt_attempt) if(rt_attempt <= ATTEMPT_LIMIT) { hw::PIT::instance().onTimeout(RTO() * rt_attempt, - [packet, self, rt_attempt] - { - // Packet hasnt been ACKed. - if(packet->seq() > self->tcb().SND.UNA) { - debug(" Packet unacknowledge, retransmitting...\n"); - if(rt_attempt == 1) - self->segment_loss_detected(); - //packet->set_ack(self->tcb().RCV.NXT); - self->retransmit(packet); - self->queue_retransmission(packet, rt_attempt+1); - } else { - debug2(" Packet acknowledged %s \n", packet->to_string().c_str()); - // Signal user? - } - }); + [packet, self, rt_attempt] + { + // Packet hasnt been ACKed. + if(packet->seq() > self->tcb().SND.UNA) { + debug(" Packet unacknowledge, retransmitting...\n"); + if(rt_attempt == 1) + self->segment_loss_detected(); + //packet->set_ack(self->tcb().RCV.NXT); + self->retransmit(packet); + self->queue_retransmission(packet, rt_attempt+1); + } else { + debug2(" Packet acknowledged %s \n", packet->to_string().c_str()); + // Signal user? + } + }); } else { printf(" Give up already... Already tried %u times. Time to kill connection?\n", - ATTEMPT_LIMIT); + ATTEMPT_LIMIT); } debug2(" Packet queued for retransmission [%u] \n", retransmit_try); } @@ -471,4 +471,3 @@ void Connection::add_option(TCP::Option::Kind kind, TCP::Packet_ptr packet) { break; } } - diff --git a/src/net/tcp_connection_states.cpp b/src/net/tcp_connection_states.cpp index 074b0af77e..c65bb494f6 100644 --- a/src/net/tcp_connection_states.cpp +++ b/src/net/tcp_connection_states.cpp @@ -130,8 +130,8 @@ bool Connection::State::check_seq(Connection& tcp, TCP::Packet_ptr in) { } std::stringstream ss; ss << "Unacceptable SEQ: " - << "[Packet: SEQ: " << in->seq() << " LEN: " << in->data_length() << "] " - << "[TCB: RCV.NXT: " << tcb.RCV.NXT << " RCV.WND: " << tcb.RCV.WND << "]"; + << "[Packet: SEQ: " << in->seq() << " LEN: " << in->data_length() << "] " + << "[TCB: RCV.NXT: " << tcb.RCV.NXT << " RCV.WND: " << tcb.RCV.WND << "]"; tcp.drop(in, ss.str()); return false; @@ -354,7 +354,7 @@ void Connection::State::process_segment(Connection& tcp, TCP::Packet_ptr in) { // If no outgoing data right now - reply with ACK. else { debug2(" ACK. Window: %i, Queue: %u, is_queued: %s\n", - tcp.usable_window(), tcp.write_queue.size(), tcp.is_queued() ? "true" : "false"); + tcp.usable_window(), tcp.write_queue.size(), tcp.is_queued() ? "true" : "false"); auto packet = tcp.outgoing_packet(); packet->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); tcp.transmit(packet); diff --git a/src/virtio/block.cpp b/src/virtio/block.cpp index 503b1b67a6..fa3f5fbdf7 100644 --- a/src/virtio/block.cpp +++ b/src/virtio/block.cpp @@ -30,15 +30,15 @@ VirtioBlk::VirtioBlk(hw::PCI_Device& d) : Virtio(d), - req(queue_size(0), 0, iobase()), + req(queue_size(0), 0, iobase()), request_counter(0) { INFO("VirtioBlk", "Driver initializing"); - + uint32_t needed_features = FEAT(VIRTIO_BLK_F_BLK_SIZE); negotiate_features(needed_features); - + CHECK(features() & FEAT(VIRTIO_BLK_F_BARRIER), "Barrier is enabled"); CHECK(features() & FEAT(VIRTIO_BLK_F_SIZE_MAX), @@ -55,37 +55,37 @@ VirtioBlk::VirtioBlk(hw::PCI_Device& d) "SCSI is enabled :("); CHECK(features() & FEAT(VIRTIO_BLK_F_FLUSH), "Flush enabled"); - - + + CHECK ((features() & needed_features) == needed_features, "Negotiated needed features"); - + // Step 1 - Initialize REQ queue auto success = assign_queue(0, (uint32_t) req.queue_desc()); CHECK(success, "Request queue assigned (0x%x) to device", (uint32_t) req.queue_desc()); - + // Step 3 - Fill receive queue with buffers // DEBUG: Disable INFO("VirtioBlk", "Queue size: %i\tRequest size: %u\n", req.size(), sizeof(request_t)); - + // Get device configuration get_config(); - - // Signal setup complete. + + // Signal setup complete. setup_complete((features() & needed_features) == needed_features); CHECK((features() & needed_features) == needed_features, "Signalled driver OK"); - + // Hook up IRQ handler (inherited from Virtio) auto del(delegate::from(this)); IRQ_manager::subscribe(irq(),del); - IRQ_manager::enable_irq(irq()); - + IRQ_manager::enable_irq(irq()); + // Done INFO("VirtioBlk", "Block device with %llu sectors capacity", config.capacity); - //CHECK(config.status == VIRTIO_BLK_S_OK, "Link up\n"); + //CHECK(config.status == VIRTIO_BLK_S_OK, "Link up\n"); req.kick(); } @@ -98,25 +98,25 @@ void VirtioBlk::irq_handler() { debug2(" IRQ handler\n"); - //Virtio Std. § 4.1.5.5, steps 1-3 - + //Virtio Std. § 4.1.5.5, steps 1-3 + // Step 1. read ISR unsigned char isr = hw::inp(iobase() + VIRTIO_PCI_ISR); - + // Step 2. A) - one of the queues have changed if (isr & 1) - { - // This now means service RX & TX interchangeably - service_RX(); - } - + { + // This now means service RX & TX interchangeably + service_RX(); + } + // Step 2. B) if (isr & 2) { debug("\t Configuration change:\n"); - - // Getting the MAC + status - //debug("\t Old status: 0x%x\n", config.status); + + // Getting the MAC + status + //debug("\t Old status: 0x%x\n", config.status); get_config(); //debug("\t New status: 0x%x \n", config.status); } @@ -127,34 +127,34 @@ void VirtioBlk::service_RX() { printf("VirtioBlk interrupt handler\n"); req.disable_interrupts(); - + uint32_t received = 0; uint32_t len; request_t* hdr; - + while ((hdr = (request_t*) req.dequeue(len)) != nullptr) - { - printf("service_RX() received %u bytes for sector %llu\n", - len, hdr->hdr.sector); - // - blk_resp_t* resp = &hdr->resp; - printf("blk response: %u\n", resp->status); - - uint8_t* copy = new uint8_t[SECTOR_SIZE]; - memcpy(copy, hdr->io.sector, SECTOR_SIZE); - auto buf = buffer_t(copy, std::default_delete()); - - printf("STATUS: [%u]\nCalling handler: %p\n", - resp->status, &hdr->io.handler); - hdr->io.handler(buf); - - received++; - } + { + printf("service_RX() received %u bytes for sector %llu\n", + len, hdr->hdr.sector); + // + blk_resp_t* resp = &hdr->resp; + printf("blk response: %u\n", resp->status); + + uint8_t* copy = new uint8_t[SECTOR_SIZE]; + memcpy(copy, hdr->io.sector, SECTOR_SIZE); + auto buf = buffer_t(copy, std::default_delete()); + + printf("STATUS: [%u]\nCalling handler: %p\n", + resp->status, &hdr->io.handler); + hdr->io.handler(buf); + + received++; + } if (received == 0) - { - //printf("service_RX() error processing requests\n"); - } - + { + //printf("service_RX() error processing requests\n"); + } + req.enable_interrupts(); } @@ -162,15 +162,15 @@ void VirtioBlk::read (block_t blk, on_read_func func) { // Virtio Std. § 5.1.6.3 auto* vbr = new request_t; - + vbr->hdr.type = VIRTIO_BLK_T_IN; vbr->hdr.ioprio = 0; vbr->hdr.sector = blk; vbr->io.handler = func; vbr->resp.status = VIRTIO_BLK_S_IOERR; - - printf("Enqueue handler: %p, total: %u\n", - &vbr->io.handler, sizeof(request_t)); + + printf("Enqueue handler: %p, total: %u\n", + &vbr->io.handler, sizeof(request_t)); // req.enqueue(&vbr->hdr, sizeof(scsi_header_t), 1, false); // out req.enqueue(&vbr->io, sizeof(blk_io_t), 0, false); // in diff --git a/src/virtio/console.cpp b/src/virtio/console.cpp index 8e12e5d562..697b316e55 100644 --- a/src/virtio/console.cpp +++ b/src/virtio/console.cpp @@ -27,70 +27,70 @@ extern "C" VirtioCon::VirtioCon(hw::PCI_Device& d) : Virtio(d), - rx(queue_size(0), 0, iobase()), + rx(queue_size(0), 0, iobase()), tx(queue_size(1), 1, iobase()), ctl_rx(queue_size(2), 2, iobase()), - ctl_tx(queue_size(3), 3, iobase()) + ctl_tx(queue_size(3), 3, iobase()) { INFO("VirtioCon", "Driver initializing"); - + uint32_t needed_features = FEAT(VIRTIO_CONSOLE_F_MULTIPORT); negotiate_features(needed_features); - + CHECK(features() & FEAT(VIRTIO_CONSOLE_F_SIZE), "Valid console dimensions"); CHECK(features() & FEAT(VIRTIO_CONSOLE_F_MULTIPORT), "Multiple ports support"); CHECK(features() & FEAT(VIRTIO_CONSOLE_F_EMERG_WRITE), "Emergency write support"); - + CHECK ((features() & needed_features) == needed_features, "Negotiated needed features"); - + // Step 1 - Initialize queues auto success = assign_queue(0, (uint32_t) rx.queue_desc()); CHECK(success, "Receive queue assigned (0x%x) to device", (uint32_t) rx.queue_desc()); - + success = assign_queue(1, (uint32_t) tx.queue_desc()); CHECK(success, "Transmit queue assigned (0x%x) to device", (uint32_t) tx.queue_desc()); - + success = assign_queue(2, (uint32_t) ctl_rx.queue_desc()); CHECK(success, "Control rx queue assigned (0x%x) to device", (uint32_t) ctl_rx.queue_desc()); - + success = assign_queue(3, (uint32_t) ctl_tx.queue_desc()); CHECK(success, "Control tx queue assigned (0x%x) to device", (uint32_t) ctl_tx.queue_desc()); - + /* success = assign_queue(4, (uint32_t) rx1.queue_desc()); CHECK(success, "rx1 queue assigned (0x%x) to device", (uint32_t) rx1.queue_desc()); - + success = assign_queue(5, (uint32_t) tx1.queue_desc()); CHECK(success, "tx1 queue assigned (0x%x) to device", (uint32_t) tx1.queue_desc()); */ - + // Step 3 - Fill receive queue with buffers - INFO("VirtioCon", "Queue size rx: %d tx: %d\n", + INFO("VirtioCon", "Queue size rx: %d tx: %d\n", rx.size(), tx.size()); - + // Get device configuration get_config(); - - // Signal setup complete. + + // Signal setup complete. setup_complete((features() & needed_features) == needed_features); CHECK((features() & needed_features) == needed_features, "Signalled driver OK"); - + // Hook up IRQ handler (inherited from Virtio) auto del(delegate::from(this)); IRQ_manager::subscribe(irq(), del); - IRQ_manager::enable_irq(irq()); - + IRQ_manager::enable_irq(irq()); + // Done INFO("VirtioCon", "Console with size (%u, %u), %u ports", config.cols, config.rows, config.max_nr_ports); @@ -106,24 +106,24 @@ void VirtioCon::irq_handler() { debug2(" IRQ handler\n"); - //Virtio Std. § 4.1.5.5, steps 1-3 - + //Virtio Std. § 4.1.5.5, steps 1-3 + // Step 1. read ISR unsigned char isr = hw::inp(iobase() + VIRTIO_PCI_ISR); - + // Step 2. A) - one of the queues have changed if (isr & 1) { // This now means service RX & TX interchangeably service_RX(); } - + // Step 2. B) if (isr & 2) { debug("\t Configuration change:\n"); - - //debug("\t Old status: 0x%x\n", config.status); + + //debug("\t Old status: 0x%x\n", config.status); get_config(); //debug("\t New status: 0x%x \n", config.status); } @@ -133,15 +133,15 @@ void VirtioCon::irq_handler() void VirtioCon::service_RX() { rx.disable_interrupts(); - + while (rx.new_incoming()) { uint32_t len = 0; char* condata = (char*) rx.dequeue(&len); - + uint32_t dontcare; rx.dequeue(&dontcare); - + if (condata) { //printf("service_RX() received %u bytes from virtio console\n", len); @@ -154,21 +154,21 @@ void VirtioCon::service_RX() //printf("No data, just len = %d\n", len); } } - + rx.enable_interrupts(); } void VirtioCon::write ( - const void* data, + const void* data, size_t len) { char* heapdata = new char[len]; memcpy(heapdata, data, len); - + scatterlist sg[1]; sg[0].data = (void*) heapdata; sg[0].size = len; // +1? - + tx.enqueue(sg, 1, 0, (void*) data); tx.kick(); } diff --git a/src/virtio/virtio.cpp b/src/virtio/virtio.cpp index 28c45faa3e..c9e044e94b 100644 --- a/src/virtio/virtio.cpp +++ b/src/virtio/virtio.cpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -22,13 +22,13 @@ #include void Virtio::set_irq(){ - - //Get device IRQ + + //Get device IRQ uint32_t value = _pcidev.read_dword(PCI::CONFIG_INTR); if ((value & 0xFF) > 0 && (value & 0xFF) < 32){ - _irq = value & 0xFF; + _irq = value & 0xFF; } - + } @@ -36,70 +36,70 @@ Virtio::Virtio(hw::PCI_Device& dev) : _pcidev(dev), _virtio_device_id(dev.product_id() + 0x1040) { INFO("Virtio","Attaching to PCI addr 0x%x",_pcidev.pci_addr()); - + /** PCI Device discovery. Virtio std. §4.1.2 */ - - /** - Match vendor ID and Device ID : §4.1.2.2 + + /** + Match vendor ID and Device ID : §4.1.2.2 */ if (_pcidev.vendor_id() != hw::PCI_Device::VENDOR_VIRTIO) panic("This is not a Virtio device"); CHECK(true, "Vendor ID is VIRTIO"); - + bool _STD_ID = _virtio_device_id >= 0x1040 and _virtio_device_id < 0x107f; - bool _LEGACY_ID = _pcidev.product_id() >= 0x1000 + bool _LEGACY_ID = _pcidev.product_id() >= 0x1000 and _pcidev.product_id() <= 0x103f; - + CHECK(_STD_ID or _LEGACY_ID, "Device ID 0x%x is in a valid range (%s)", - _pcidev.product_id(), + _pcidev.product_id(), _STD_ID ? ">= Virtio 1.0" : (_LEGACY_ID ? "Virtio LEGACY" : "INVALID")); - + assert(_STD_ID or _LEGACY_ID); - - /** - Match Device revision ID. Virtio Std. §4.1.2.2 + + /** + Match Device revision ID. Virtio Std. §4.1.2.2 */ bool rev_id_ok = ((_LEGACY_ID and _pcidev.rev_id() == 0) or (_STD_ID and _pcidev.rev_id() > 0)); - - - CHECK(rev_id_ok and version_supported(_pcidev.rev_id()), + + + CHECK(rev_id_ok and version_supported(_pcidev.rev_id()), "Device Revision ID (0x%x) supported", _pcidev.rev_id()); - + assert(rev_id_ok); // We'll try to continue if it's newer than supported. - + // Probe PCI resources and fetch I/O-base for device _pcidev.probe_resources(); - _iobase=_pcidev.iobase(); - + _iobase=_pcidev.iobase(); + CHECK(_iobase, "Unit has valid I/O base (0x%x)", _iobase); - + /** Device initialization. Virtio Std. v.1, sect. 3.1: */ - + // 1. Reset device reset(); INFO2("[*] Reset device"); - + // 2. Set ACKNOWLEGE status bit, and // 3. Set DRIVER status bit - + hw::outp(_iobase + VIRTIO_PCI_STATUS, hw::inp(_iobase + VIRTIO_PCI_STATUS) | - VIRTIO_CONFIG_S_ACKNOWLEDGE | + VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER); - + // THE REMAINING STEPS MUST BE DONE IN A SUBCLASS // 4. Negotiate features (Read, write, read) - // => In the subclass (i.e. Only the Nic driver knows if it wants a mac) - // 5. @todo IF >= Virtio 1.0, set FEATURES_OK status bit - // 6. @todo IF >= Virtio 1.0, Re-read Device Status to ensure features are OK - // 7. Device specifig setup. - - // Where the standard isn't clear, we'll do our best to separate work + // => In the subclass (i.e. Only the Nic driver knows if it wants a mac) + // 5. @todo IF >= Virtio 1.0, set FEATURES_OK status bit + // 6. @todo IF >= Virtio 1.0, Re-read Device Status to ensure features are OK + // 7. Device specifig setup. + + // Where the standard isn't clear, we'll do our best to separate work // between this class and subclasses. - + //Fetch IRQ from PCI resource set_irq(); @@ -108,20 +108,20 @@ Virtio::Virtio(hw::PCI_Device& dev) enable_irq_handler(); - + INFO("Virtio", "Initialization complete"); - - // It would be nice if we new that all queues were the same size. + + // It would be nice if we new that all queues were the same size. // Then we could pass this size on to the device-specific constructor // But, it seems there aren't any guarantees in the standard. - - // @note this is "the Legacy interface" according to Virtio std. 4.1.4.8. + + // @note this is "the Legacy interface" according to Virtio std. 4.1.4.8. // uint32_t queue_size = hw::inpd(_iobase + 0x0C); - + /* printf(queue_size > 0 and queue_size != PCI_WTF ? "\t [x] Queue Size : 0x%lx \n" : - "\t [ ] No qeuue Size? : 0x%lx \n" ,queue_size); */ - + "\t [ ] No qeuue Size? : 0x%lx \n" ,queue_size); */ + } void Virtio::get_config(void* buf, int len){ @@ -136,12 +136,12 @@ void Virtio::reset(){ hw::outp(_iobase + VIRTIO_PCI_STATUS, 0); } -uint32_t Virtio::queue_size(uint16_t index){ +uint32_t Virtio::queue_size(uint16_t index){ hw::outpw(iobase() + VIRTIO_PCI_QUEUE_SEL, index); return hw::inpw(iobase() + VIRTIO_PCI_QUEUE_SIZE); } -#define BTOP(x) ((unsigned long)(x) >> PAGESHIFT) +#define BTOP(x) ((unsigned long)(x) >> PAGESHIFT) bool Virtio::assign_queue(uint16_t index, uint32_t queue_desc){ hw::outpw(iobase() + VIRTIO_PCI_QUEUE_SEL, index); hw::outpd(iobase() + VIRTIO_PCI_QUEUE_PFN, BTOP(queue_desc)); @@ -175,39 +175,35 @@ void Virtio::default_irq_handler(){ printf("PRIVATE virtio IRQ handler: Call %i \n",calls++); printf("Old Features : 0x%x \n",_features); printf("New Features : 0x%x \n",probe_features()); - + unsigned char isr = hw::inp(_iobase + VIRTIO_PCI_ISR); printf("Virtio ISR: 0x%i \n",isr); printf("Virtio ISR: 0x%i \n",isr); - + IRQ_manager::eoi(_irq); - + } void Virtio::enable_irq_handler(){ //_irq=0; //Works only if IRQ2INTR(_irq), since 0 overlaps an exception. - - //auto del=delegate::from_method(this); + + //auto del=delegate::from_method(this); auto del(delegate::from(this)); - + IRQ_manager::subscribe(_irq,del); - + IRQ_manager::enable_irq(_irq); - - + + } /** void Virtio::enable_irq_handler(IRQ_manager::irq_delegate d){ //_irq=0; //Works only if IRQ2INTR(_irq), since 0 overlaps an exception. //IRQ_manager::set_handler(IRQ2INTR(_irq), irq_virtio_entry); - + IRQ_manager::subscribe(_irq,d); - + IRQ_manager::enable_irq(_irq); }*/ - - - - diff --git a/src/virtio/virtio_queue.cpp b/src/virtio/virtio_queue.cpp index 0df57e6774..30a30b2f30 100644 --- a/src/virtio/virtio_queue.cpp +++ b/src/virtio/virtio_queue.cpp @@ -157,26 +157,26 @@ int Virtio::Queue::enqueue(scatterlist sg[], uint32_t out, uint32_t in, void* UN return _num_free; } void Virtio::Queue::enqueue( - void* out, - uint32_t out_len, - void* in, - uint32_t in_len) + void* out, + uint32_t out_len, + void* in, + uint32_t in_len) { int total = (out) ? 1 : 0; total += (in) ? 1 : 0; - + printf("enqueue total: %d\n", total); - + if (_num_free < total) - { - // Queue is full (we think) - printf("Buffer full (%i avail," \ - " used.idx: %i, avail.idx: %i )\n", - _pci_index, num_avail(), - _queue.used->idx,_queue.avail->idx - ); - panic("Buffer full"); - } + { + // Queue is full (we think) + printf("Buffer full (%i avail," \ + " used.idx: %i, avail.idx: %i )\n", + _pci_index, num_avail(), + _queue.used->idx,_queue.avail->idx + ); + panic("Buffer full"); + } // Remove buffers from the free list _num_free -= total; @@ -187,31 +187,31 @@ void Virtio::Queue::enqueue( // (implicitly) Mark all outbound tokens as device-readable if (out) - { - current().flags = VIRTQ_DESC_F_NEXT; - current().addr = (intptr_t) out; - current().len = out_len; - - printf(" Enqueueing outbound: index %u len %u (actual: %u), next %d\n", - _pci_index, head, current().len, out_len, current().next); - - last = ¤t(); - // go to next - go_next(); - } + { + current().flags = VIRTQ_DESC_F_NEXT; + current().addr = (intptr_t) out; + current().len = out_len; + + printf(" Enqueueing outbound: index %u len %u (actual: %u), next %d\n", + _pci_index, head, current().len, out_len, current().next); + + last = ¤t(); + // go to next + go_next(); + } // Mark all inbound tokens as device-writable if (in) - { - printf(" Enqueuing inbound \n"); - current().flags = VIRTQ_DESC_F_NEXT | VIRTQ_DESC_F_WRITE; - current().addr = (intptr_t) in; - current().len = in_len; - - last = ¤t(); - // go to next - go_next(); - } + { + printf(" Enqueuing inbound \n"); + current().flags = VIRTQ_DESC_F_NEXT | VIRTQ_DESC_F_WRITE; + current().addr = (intptr_t) in; + current().len = in_len; + + last = ¤t(); + // go to next + go_next(); + } // No continue on last buffer last->flags &= ~VIRTQ_DESC_F_NEXT; @@ -224,15 +224,15 @@ void Virtio::Queue::enqueue( void Virtio::Queue::enqueue(void* data, uint32_t len, bool out, bool last) { if (_num_free < 1) - { - // Queue is full (we think) - printf("Buffer full (%i avail," \ - " used.idx: %i, avail.idx: %i )\n", - _pci_index, num_avail(), - _queue.used->idx,_queue.avail->idx - ); - panic("Buffer full"); - } + { + // Queue is full (we think) + printf("Buffer full (%i avail," \ + " used.idx: %i, avail.idx: %i )\n", + _pci_index, num_avail(), + _queue.used->idx,_queue.avail->idx + ); + panic("Buffer full"); + } // Remove buffers from the free list _num_free -= 1; @@ -244,17 +244,17 @@ void Virtio::Queue::enqueue(void* data, uint32_t len, bool out, bool last) current().flags = flags | (out ? 0 : VIRTQ_DESC_F_WRITE); current().addr = (intptr_t) data; current().len = len; - + if (out) - printf(" Enqueueing outbound: %p index %u len %u (actual: %u), next %d\n", - _pci_index, data, head, current().len, len, current().next); + printf(" Enqueueing outbound: %p index %u len %u (actual: %u), next %d\n", + _pci_index, data, head, current().len, len, current().next); else - printf(" Enqueueing inbound: %p index %u len %u (actual: %u), next %d\n", - _pci_index, data, head, current().len, len, current().next); - + printf(" Enqueueing inbound: %p index %u len %u (actual: %u), next %d\n", + _pci_index, data, head, current().len, len, current().next); + // go to next in ring go_next(); - + // SanOS: Put entry in available array, but do not update avail->idx until sync uint16_t avail = (_queue.avail->idx + _num_added++) % _size; _queue.avail->ring[avail] = head; @@ -263,10 +263,10 @@ void* Virtio::Queue::dequeue(uint32_t& len) { // Return NULL if there are no more completed buffers in the queue if (_last_used_idx == _queue.used->idx) - { - debug(" Can't dequeue - no used buffers \n",_pci_index); - return nullptr; - } + { + debug(" Can't dequeue - no used buffers \n",_pci_index); + return nullptr; + } // Get next completed buffer auto& e = _queue.used->ring[_last_used_idx % _size]; diff --git a/test/GSL/service.cpp b/test/GSL/service.cpp index 66aa6890b3..2f8a83596f 100644 --- a/test/GSL/service.cpp +++ b/test/GSL/service.cpp @@ -31,9 +31,9 @@ int clock_gettime(clockid_t clk_id, struct timespec *tp){ -(void*)clk_id; -(void*)tp; -return 0; + (void*)clk_id; + (void*)tp; + return 0; }; diff --git a/test/UDP/service.cpp b/test/UDP/service.cpp index 40eb05fc43..7f64fb33d3 100644 --- a/test/UDP/service.cpp +++ b/test/UDP/service.cpp @@ -36,24 +36,24 @@ void Service::start() {{ 255,255,0,0 }} ); // Netmask printf("Service IP address is %s\n", inet.ip_addr().str().c_str()); - + // UDP const UDP::port_t port = 4242; auto& sock = inet.udp().bind(port); - + sock.on_read( - [&sock] (UDP::addr_t addr, UDP::port_t port, - const char* data, size_t len) - { - std::string strdata(data, len); - CHECK(1, "Getting UDP data from %s: %d -> %s", - addr.str().c_str(), port, strdata.c_str()); - // send the same thing right back! - sock.sendto(addr, port, data, len, - [] { - INFO("UDP test", "SUCCESS"); - }); - }); - + [&sock] (UDP::addr_t addr, UDP::port_t port, + const char* data, size_t len) + { + std::string strdata(data, len); + CHECK(1, "Getting UDP data from %s: %d -> %s", + addr.str().c_str(), port, strdata.c_str()); + // send the same thing right back! + sock.sendto(addr, port, data, len, + [] { + INFO("UDP test", "SUCCESS"); + }); + }); + INFO("UDP test", "Listening on port %d\n", port); } diff --git a/test/fat/fat16.cpp b/test/fat/fat16.cpp index 1e36976ccd..23d11c8317 100644 --- a/test/fat/fat16.cpp +++ b/test/fat/fat16.cpp @@ -76,31 +76,31 @@ void Service::start() auto buf = fs.read(ent, 0, ent.size); auto banana = buf.to_string(); - CHECKSERT(banana == internal_banana, "Correct banana #1"); - - bool test = true; - - for (size_t i = 0; i < internal_banana.size(); i++) - { - // read one byte at a time - buf = fs.read(ent, i, 1); - /// @buf should evaluate to 'true' if its valid - CHECKSERT(buf, "Validate buffer"); - - // verify that it matches the same location in test-string - test = ((char) buf.buffer.get()[0] == internal_banana[i]); - if (!test) - { - printf("!! Random access read test failed on i = %u\n", i); - break; - } - } - CHECKSERT(test, "Validate random access sync read"); - - buf = fs.readFile("/banana.txt"); - banana = buf.to_string(); - CHECKSERT(banana == internal_banana, "Correct banana #2"); - }); + CHECKSERT(banana == internal_banana, "Correct banana #1"); + + bool test = true; + + for (size_t i = 0; i < internal_banana.size(); i++) + { + // read one byte at a time + buf = fs.read(ent, i, 1); + /// @buf should evaluate to 'true' if its valid + CHECKSERT(buf, "Validate buffer"); + + // verify that it matches the same location in test-string + test = ((char) buf.buffer.get()[0] == internal_banana[i]); + if (!test) + { + printf("!! Random access read test failed on i = %u\n", i); + break; + } + } + CHECKSERT(test, "Validate random access sync read"); + + buf = fs.readFile("/banana.txt"); + banana = buf.to_string(); + CHECKSERT(banana == internal_banana, "Correct banana #2"); + }); INFO("FAT16", "SUCCESS"); } diff --git a/test/fat/fat32.cpp b/test/fat/fat32.cpp index 65cfc76f02..9a501dd006 100644 --- a/test/fat/fat32.cpp +++ b/test/fat/fat32.cpp @@ -44,73 +44,73 @@ void Service::start() // auto-mount filesystem disk->mount(disk->MBR, - [] (fs::error_t err) - { - CHECKSERT(!err, "Filesystem auto-mounted"); + [] (fs::error_t err) + { + CHECKSERT(!err, "Filesystem auto-mounted"); - auto& fs = disk->fs(); - printf("\t\t%s filesystem\n", fs.name().c_str()); + auto& fs = disk->fs(); + printf("\t\t%s filesystem\n", fs.name().c_str()); - auto vec = fs::new_shared_vector(); - err = fs.ls("/", vec); - CHECKSERT(!err, "List root directory"); + auto vec = fs::new_shared_vector(); + err = fs.ls("/", vec); + CHECKSERT(!err, "List root directory"); - CHECKSERT(vec->size() == 2, "Exactly two ents in root dir"); + CHECKSERT(vec->size() == 2, "Exactly two ents in root dir"); - auto& e = vec->at(0); - CHECKSERT(e.is_file(), "Ent is a file"); - CHECKSERT(e.name() == "banana.txt", "Ents name is 'banana.txt'"); - }); + auto& e = vec->at(0); + CHECKSERT(e.is_file(), "Ent is a file"); + CHECKSERT(e.name() == "banana.txt", "Ents name is 'banana.txt'"); + }); // re-mount on VBR1 disk->mount(disk->VBR1, - [] (fs::error_t err) - { - CHECK(!err, "Filesystem mounted on VBR1"); - assert(!err); - - auto& fs = disk->fs(); - auto ent = fs.stat("/banana.txt"); - CHECKSERT(ent.is_valid(), "Stat file in root dir"); - CHECKSERT(ent.is_file(), "Entity is file"); - CHECKSERT(!ent.is_dir(), "Entity is not directory"); - CHECKSERT(ent.name() == "banana.txt", "Name is 'banana.txt'"); - - ent = fs.stat("/dir1/dir2/dir3/dir4/dir5/dir6/banana.txt"); - CHECKSERT(ent.is_valid(), "Stat file in deep dir"); - CHECKSERT(ent.is_file(), "Entity is file"); - CHECKSERT(!ent.is_dir(), "Entity is not directory"); - - CHECKSERT(ent.name() == "banana.txt", "Name is 'banana.txt'"); - - printf("%s\n", internal_banana.c_str()); - - // asynch file reading test - fs.read(ent, 0, ent.size, - [&fs] (fs::error_t err, fs::buffer_t buf, uint64_t len) - { - CHECKSERT(!err, "read: Read 'banana.txt' asynchronously"); - if (err) - { - panic("Failed to read file async"); - } - - std::string banana((char*) buf.get(), len); - CHECKSERT(banana == internal_banana, "Correct banana #1"); - - fs.readFile("/banana.txt", - [&fs] (fs::error_t err, fs::buffer_t buf, uint64_t len) - { - CHECKSERT(!err, "readFile: Read 'banana.txt' asynchronously"); - if (err) - { - panic("Failed to read file async"); - } - - std::string banana((char*) buf.get(), len); - CHECKSERT(banana == internal_banana, "Correct banana #2"); - }); - }); - }); + [] (fs::error_t err) + { + CHECK(!err, "Filesystem mounted on VBR1"); + assert(!err); + + auto& fs = disk->fs(); + auto ent = fs.stat("/banana.txt"); + CHECKSERT(ent.is_valid(), "Stat file in root dir"); + CHECKSERT(ent.is_file(), "Entity is file"); + CHECKSERT(!ent.is_dir(), "Entity is not directory"); + CHECKSERT(ent.name() == "banana.txt", "Name is 'banana.txt'"); + + ent = fs.stat("/dir1/dir2/dir3/dir4/dir5/dir6/banana.txt"); + CHECKSERT(ent.is_valid(), "Stat file in deep dir"); + CHECKSERT(ent.is_file(), "Entity is file"); + CHECKSERT(!ent.is_dir(), "Entity is not directory"); + + CHECKSERT(ent.name() == "banana.txt", "Name is 'banana.txt'"); + + printf("%s\n", internal_banana.c_str()); + + // asynch file reading test + fs.read(ent, 0, ent.size, + [&fs] (fs::error_t err, fs::buffer_t buf, uint64_t len) + { + CHECKSERT(!err, "read: Read 'banana.txt' asynchronously"); + if (err) + { + panic("Failed to read file async"); + } + + std::string banana((char*) buf.get(), len); + CHECKSERT(banana == internal_banana, "Correct banana #1"); + + fs.readFile("/banana.txt", + [&fs] (fs::error_t err, fs::buffer_t buf, uint64_t len) + { + CHECKSERT(!err, "readFile: Read 'banana.txt' asynchronously"); + if (err) + { + panic("Failed to read file async"); + } + + std::string banana((char*) buf.get(), len); + CHECKSERT(banana == internal_banana, "Correct banana #2"); + }); + }); + }); INFO("FAT32", "SUCCESS"); } diff --git a/test/serial/service.cpp b/test/serial/service.cpp index d6b9819e5f..fe959d1bdf 100644 --- a/test/serial/service.cpp +++ b/test/serial/service.cpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -23,17 +23,15 @@ using namespace std::chrono; void Service::start() { - - auto& com1 = hw::Serial::port<1>(); - - com1.on_readline([](const std::string& s){ + + auto& com1 = hw::Serial::port<1>(); + + com1.on_readline([](const std::string& s){ printf("\nReceived: %s \n", s.c_str()); - - }); - - INFO("Serial Test","Doing some serious serial"); + }); -} + INFO("Serial Test","Doing some serious serial"); +} diff --git a/test/transmit/service.cpp b/test/transmit/service.cpp index ab7eb9d1b7..746c7a9c6a 100644 --- a/test/transmit/service.cpp +++ b/test/transmit/service.cpp @@ -48,37 +48,37 @@ void Service::start() auto& conn = inet->udp().bind(port); conn.on_read([&] (UDP::addr_t addr, UDP::port_t port, - const char* data, int len) { - string received = std::string(data,len-1); - INFO("Test 2","Starting UDP-test (got UDP data from %s: %i: '%s')", - addr.str().c_str(), port, received.c_str()); + const char* data, int len) { + string received = std::string(data,len-1); + INFO("Test 2","Starting UDP-test (got UDP data from %s: %i: '%s')", + addr.str().c_str(), port, received.c_str()); - const int packets { 600 }; + const int packets { 600 }; - string first_reply {string("Received '") + received + - "'. Expect " + to_string(packets) + " packets in 1s\n" }; + string first_reply {string("Received '") + received + + "'. Expect " + to_string(packets) + " packets in 1s\n" }; - // Send the first packet, and then wait for ARP - conn.sendto(addr, port, first_reply.c_str(), first_reply.size()); + // Send the first packet, and then wait for ARP + conn.sendto(addr, port, first_reply.c_str(), first_reply.size()); - timer.onTimeout(1s, [&conn, addr, port, data, len]() { - INFO("Test 2", "Trying to transmit %i UDP packets at maximum throttle", packets); - auto bufcount = inet->buffers_available(); + timer.onTimeout(1s, [&conn, addr, port, data, len]() { + INFO("Test 2", "Trying to transmit %i UDP packets at maximum throttle", packets); + auto bufcount = inet->buffers_available(); - for (int i = 0; i < packets; i++) - conn.sendto(addr, port, data, len); + for (int i = 0; i < packets; i++) + conn.sendto(addr, port, data, len); - CHECK(1,"UDP-transmission didn't panic"); - auto bufcount2 = inet->buffers_available(); + CHECK(1,"UDP-transmission didn't panic"); + auto bufcount2 = inet->buffers_available(); - CHECKSERT(bufcount2 < bufcount, - "%i buffers available after transmission (Had %i). ", - bufcount2, bufcount); + CHECKSERT(bufcount2 < bufcount, + "%i buffers available after transmission (Had %i). ", + bufcount2, bufcount); - INFO("Transmision tests","SUCCESS"); - }); + INFO("Transmision tests","SUCCESS"); + }); - }); + }); eth0.on_transmit_queue_available([](size_t s){ CHECKSERT(s,"There is now room for %i packets in transmit queue", s); From 7a48d0ba6c2e6089ab743f7f0e22e1f453d754e0 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 12 Apr 2016 21:44:28 +0200 Subject: [PATCH 144/311] Virtio now does page calculation via OS --- src/virtio/virtio.cpp | 4 ++-- src/virtio/virtio_queue.cpp | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/virtio/virtio.cpp b/src/virtio/virtio.cpp index c9e044e94b..1536889d0c 100644 --- a/src/virtio/virtio.cpp +++ b/src/virtio/virtio.cpp @@ -144,8 +144,8 @@ uint32_t Virtio::queue_size(uint16_t index){ #define BTOP(x) ((unsigned long)(x) >> PAGESHIFT) bool Virtio::assign_queue(uint16_t index, uint32_t queue_desc){ hw::outpw(iobase() + VIRTIO_PCI_QUEUE_SEL, index); - hw::outpd(iobase() + VIRTIO_PCI_QUEUE_PFN, BTOP(queue_desc)); - return hw::inpd(iobase() + VIRTIO_PCI_QUEUE_PFN) == BTOP(queue_desc); + hw::outpd(iobase() + VIRTIO_PCI_QUEUE_PFN, OS::page_nr_from_addr(queue_desc)); + return hw::inpd(iobase() + VIRTIO_PCI_QUEUE_PFN) == OS::page_nr_from_addr(queue_desc); } uint32_t Virtio::probe_features(){ diff --git a/src/virtio/virtio_queue.cpp b/src/virtio/virtio_queue.cpp index 30a30b2f30..28968468dd 100644 --- a/src/virtio/virtio_queue.cpp +++ b/src/virtio/virtio_queue.cpp @@ -18,6 +18,7 @@ //#define DEBUG // Allow debug //#define DEBUG2 +#include #include #include #include @@ -51,7 +52,7 @@ void Virtio::Queue::init_queue(int size, void* buf){ // (This is a formula from sanos - don't know why it works, but it does // align the used queue to the next page border) _queue.used = (virtq_used*)(((uint32_t)&_queue.avail->ring[size] + - sizeof(uint16_t)+PAGESIZE-1) & ~(PAGESIZE -1)); + sizeof(uint16_t)+OS::page_size()-1) & ~(OS::page_size() -1)); debug("\t * Queue used @ 0x%lx \n ",(long)_queue.used); } From 8deaf48c71f6975b39196172db0782ec07d4a8d9 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 12 Apr 2016 23:00:30 +0200 Subject: [PATCH 145/311] Added a virtio-queue test. WIP --- test/virtio_queue/Makefile | 24 ++++++++++ test/virtio_queue/README.md | 6 +++ test/virtio_queue/run.sh | 3 ++ test/virtio_queue/service.cpp | 89 +++++++++++++++++++++++++++++++++++ test/virtio_queue/test.sh | 5 ++ 5 files changed, 127 insertions(+) create mode 100644 test/virtio_queue/Makefile create mode 100644 test/virtio_queue/README.md create mode 100755 test/virtio_queue/run.sh create mode 100644 test/virtio_queue/service.cpp create mode 100755 test/virtio_queue/test.sh diff --git a/test/virtio_queue/Makefile b/test/virtio_queue/Makefile new file mode 100644 index 0000000000..e9f2a091ba --- /dev/null +++ b/test/virtio_queue/Makefile @@ -0,0 +1,24 @@ +################################################# +# IncludeOS SERVICE makefile # +################################################# + +# The name of your service +SERVICE = test_virtio_queue +SERVICE_NAME = Virtio Queue Test + +# Your service parts +FILES = service.cpp + +LOCAL_INCLUDES=-I$(PWD)/../lest/include/lest -I$(PWD)/../../mod/GSL/include + +# Your disk image +DISK= + + + +# IncludeOS location +ifndef INCLUDEOS_INSTALL +INCLUDEOS_INSTALL=$(HOME)/IncludeOS_install +endif + +include $(INCLUDEOS_INSTALL)/Makeseed diff --git a/test/virtio_queue/README.md b/test/virtio_queue/README.md new file mode 100644 index 0000000000..e4ff29ef50 --- /dev/null +++ b/test/virtio_queue/README.md @@ -0,0 +1,6 @@ +# Test Virtio::Queue. WIP + +Sucess: Outputs SUCCESS if all tests pass +Fail: Panic if any test fails + +NOTE: This test uses the `lest` unit test framework as well for some tests. The result of those tests will also be reported. diff --git a/test/virtio_queue/run.sh b/test/virtio_queue/run.sh new file mode 100755 index 0000000000..3b2132d2cb --- /dev/null +++ b/test/virtio_queue/run.sh @@ -0,0 +1,3 @@ +#! /bin/bash +source ${INCLUDEOS_HOME-$HOME/IncludeOS_install}/etc/run.sh + diff --git a/test/virtio_queue/service.cpp b/test/virtio_queue/service.cpp new file mode 100644 index 0000000000..5ee2bb5372 --- /dev/null +++ b/test/virtio_queue/service.cpp @@ -0,0 +1,89 @@ +// This file is a part of the IncludeOS unikernel - www.includeos.org +// +// Copyright 2015 Oslo and Akershus University College of Applied Sciences +// and Alfred Bratterud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + A very superficial test to verify that basic STL is working + This is useful when we mess with / replace STL implementations + +**/ + + +#include + +#include +#include +#include + +int clock_gettime(clockid_t clk_id, struct timespec *tp){ + (void*)clk_id; + (void*)tp; + return 0; +}; + +using namespace std; + +const lest::test virtio_tests[] = { + { + + + SCENARIO( "Virtio Queues work" ) + { + const int queue_size = 256; + + GIVEN( "A virtio queue with 10 tokens" ) { + Virtio::Queue vq(queue_size, 0, 0); + enum Direction { IN, OUT }; + + EXPECT (vq.num_free() == queue_size); + + WHEN ("You enqueue 10 tokens") { + for (int i = 0; i < 10; i++) + vq.enqueue(malloc(100), 100, OUT, 0); + + EXPECT (vq.num_free() == (queue_size - 10)); + + THEN("You dequeue 10 tokens") { + uint32_t res; + for (int i = 0; i < 10; i++) + vq.dequeue(res); + + EXPECT (vq.num_free() == 0); + } + } + + WHEN ("You insert too many tokens") { + for (int i = 0; i < queue_size * 3; i++) + vq.enqueue(malloc(100), 100, OUT, 0); + + THEN ("Queue reports 10 items") { + EXPECT (vq.num_free() == (queue_size - 10)); + } + } + + } + } + } +}; + +#define MYINFO(X,...) INFO("Test STL",X,##__VA_ARGS__) + +void Service::start() +{ + + CHECK( lest::run(virtio_tests, {"-p"}) == 0, "All tests passed" ); + MYINFO("SUCCESS"); +} diff --git a/test/virtio_queue/test.sh b/test/virtio_queue/test.sh new file mode 100755 index 0000000000..c98a6ccd47 --- /dev/null +++ b/test/virtio_queue/test.sh @@ -0,0 +1,5 @@ +#!/bin/bash +source ../test_base + +make +start test_virtio_queue.img From 53ded45b2deb90c6ce0954b2bad1dcbb523e6a47 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Wed, 13 Apr 2016 08:13:51 +0200 Subject: [PATCH 146/311] Minor updates to TCP test setup --- test/tcp/Makefile | 4 ++-- test/tcp/README.md | 5 +++-- test/tcp/test.sh | 6 ++++++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/test/tcp/Makefile b/test/tcp/Makefile index 7d7164a3f7..486480e48a 100644 --- a/test/tcp/Makefile +++ b/test/tcp/Makefile @@ -3,8 +3,8 @@ ################################################# # The name of your service -SERVICE = "IncludeOS_TCP_Test" -SERVICE_NAME = "TCP\ Test\ Service" +SERVICE = test_tcp +SERVICE_NAME = TCP Test Service # Your service parts FILES = service.cpp diff --git a/test/tcp/README.md b/test/tcp/README.md index 1658ef3c24..c744227e03 100644 --- a/test/tcp/README.md +++ b/test/tcp/README.md @@ -1,7 +1,8 @@ # TCP Test ### Usage: -` $ python test.py $GUEST_IP $HOST_IP ` +1. Start the TCP test service, with `./test.sh` +2. Start the python test with `$ python test.py $GUEST_IP $HOST_IP ` Guest and Host IP are optional (default are GUEST=`10.0.0.42` HOST=`10.0.0.1`). @@ -18,7 +19,7 @@ This test is developed on OS X using Virtualbox. Here's an recepie how to try it 4. Open Virtualbox => TCP_test => Settings => Network 5. Change *Adapter 1* to use *NAT* => Advanced => Port Forwarding 6. Add the following rules: - + ``` $ vboxmanage showvminfo TCP_test ... diff --git a/test/tcp/test.sh b/test/tcp/test.sh index e69de29bb2..ee020d5f84 100755 --- a/test/tcp/test.sh +++ b/test/tcp/test.sh @@ -0,0 +1,6 @@ +#! /bin/bash + +source ../test_base + +make +start test_tcp.img From fce1932a2347b093939a0337d05dc70458292a53 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Wed, 13 Apr 2016 12:36:01 +0200 Subject: [PATCH 147/311] fs: Add support for instantiating custom filesystem --- api/fs/disk.hpp | 35 ++++-- src/fs/disk.cpp | 210 ++++++++++++++++++----------------- src/kernel/terminal_disk.cpp | 206 +++++++++++++++++----------------- test/fat/fat16.cpp | 112 +++++++++---------- 4 files changed, 291 insertions(+), 272 deletions(-) diff --git a/api/fs/disk.hpp b/api/fs/disk.hpp index 0f8e857d6d..d096b8fc20 100644 --- a/api/fs/disk.hpp +++ b/api/fs/disk.hpp @@ -31,30 +31,28 @@ namespace fs { class Disk { public: - struct Partition; //< Representation of a disk partition - - /** Callbacks */ + struct Partition; using on_parts_func = std::function&)>; using on_mount_func = std::function; + using lba_t = uint32_t; /** Constructor */ explicit Disk(hw::IDiskDevice&); enum partition_t { MBR = 0, //< Master Boot Record (0) - /** extended partitions (1-4) */ - VBR1, + VBR1, //> extended partitions (1-4) VBR2, VBR3, VBR4, - + INVALID - }; //< enum partition_t - + }; + struct Partition { explicit Partition(const uint8_t fl, const uint8_t Id, - const uint32_t LBA, const uint32_t sz) noexcept : - flags {fl}, + const uint32_t LBA, const uint32_t sz) noexcept + : flags {fl}, id {Id}, lba_begin {LBA}, sectors {sz} @@ -92,10 +90,21 @@ namespace fs { { return device.size() == 0; } // Mounts the first partition detected (MBR -> VBR1-4 -> ext) + // NOTE: Always detects and instantiates a FAT filesystem void mount(on_mount_func func); - - // Mount partition @part as the filesystem FS + + // Mounts specified partition + // NOTE: Always detects and instantiates a FAT filesystem void mount(partition_t part, on_mount_func func); + + // mount custom filesystem on MBR or VBRn + template + void mount(Args&&... args, partition_t part, on_mount_func func) + { + // construct custom filesystem + filesys.reset(new T(args...)); + internal_mount(part, func); + } /** * Returns a vector of the partitions on a disk @@ -105,6 +114,8 @@ namespace fs { void partitions(on_parts_func func); private: + void internal_mount(partition_t part, on_mount_func func); + hw::IDiskDevice& device; std::unique_ptr filesys; }; //< class Disk diff --git a/src/fs/disk.cpp b/src/fs/disk.cpp index 00a6ea21b0..bfa2942fef 100644 --- a/src/fs/disk.cpp +++ b/src/fs/disk.cpp @@ -22,126 +22,134 @@ namespace fs { Disk::Disk(hw::IDiskDevice& dev) - : device {dev} -{ - // for now we can only assume FAT, anyways - filesys.reset(new FAT(device)); -} - + : device {dev} {} + void Disk::partitions(on_parts_func func) { /** Read Master Boot Record (sector 0) */ device.read(0, - [this, func] (hw::IDiskDevice::buffer_t data) - { - std::vector parts; - - if (!data) { - func(true, parts); - return; - } - - // First sector is the Master Boot Record - auto* mbr =(MBR::mbr*) data.get(); - - for (int i {0}; i < 4; ++i) { - // all the partitions are offsets to potential Volume Boot Records - parts.emplace_back( - mbr->part[i].flags, //< flags - mbr->part[i].type, //< id - mbr->part[i].lba_begin, //< LBA - mbr->part[i].sectors); - } - - func(no_error, parts); - }); + [this, func] (hw::IDiskDevice::buffer_t data) + { + std::vector parts; + + if (!data) { + func(true, parts); + return; + } + + // First sector is the Master Boot Record + auto* mbr =(MBR::mbr*) data.get(); + + for (int i {0}; i < 4; ++i) { + // all the partitions are offsets to potential Volume Boot Records + parts.emplace_back( + mbr->part[i].flags, //< flags + mbr->part[i].type, //< id + mbr->part[i].lba_begin, //< LBA + mbr->part[i].sectors); + } + + func(no_error, parts); + }); } void Disk::mount(on_mount_func func) { device.read(0, - [this, func] (hw::IDiskDevice::buffer_t data) - { - if (!data) { - // TODO: error-case for unable to read MBR - mount(INVALID, func); - return; - } - - // auto-detect FAT on MBR: - auto* mbr = (MBR::mbr*) data.get(); - MBR::BPB* bpb = mbr->bpb(); - - if (bpb->bytes_per_sector >= 512 - && bpb->fa_tables != 0 - && bpb->signature != 0) // check MBR signature too - { - // we have FAT on MBR (and we are assuming mount FAT) - mount(MBR, func); - return; - } - - // go through partition list - for (int i = 0; i < 4; i++) - { - if (mbr->part[i].type != 0 // 0 is unused partition - && mbr->part[i].lba_begin != 0 // 0 is MBR anyways - && mbr->part[i].sectors != 0) // 0 means no size, so... - { - mount((partition_t) (VBR1 + i), func); - return; - } - } - - // no partition was found (TODO: extended partitions) - mount(INVALID, func); - return; - }); - } + [this, func] (hw::IDiskDevice::buffer_t data) + { + if (!data) { + // TODO: error-case for unable to read MBR + internal_mount(INVALID, func); + return; + } - void Disk::mount(partition_t part, on_mount_func func) { - - if (part == INVALID) + // auto-detect FAT on MBR: + auto* mbr = (MBR::mbr*) data.get(); + MBR::BPB* bpb = mbr->bpb(); + + if (bpb->bytes_per_sector >= 512 + && bpb->fa_tables != 0 + && bpb->signature != 0) // check MBR signature too { - // Something bad happened maybe in auto-detect - // Either way, no partition was found - func(true); + // detected FAT on MBR + filesys.reset(new FAT(device)); + // mount on MBR + internal_mount(MBR, func); return; } - else if (part == MBR) + + // go through partition list + for (int i = 0; i < 4; i++) { - // For the MBR case, all we need to do is mount on sector 0 - fs().mount(0, device.size(), func); + if (mbr->part[i].type != 0 // 0 is unused partition + && mbr->part[i].lba_begin != 0 // 0 is MBR anyways + && mbr->part[i].sectors != 0) // 0 means no size, so... + { + // FIXME: for now we can only assume FAT, anyways + // To be replaced with lookup table for partition identifiers, + // but we really only have FAT atm, so its just wasteful + filesys.reset(new FAT(device)); + // mount on VBRn + internal_mount((partition_t) (VBR1 + i), func); + return; + } } + + // no partition was found (TODO: extended partitions) + internal_mount(INVALID, func); + }); + } + + void Disk::mount(partition_t part, on_mount_func func) + { + filesys.reset(new FAT(device)); + internal_mount(part, func); + } + + void Disk::internal_mount(partition_t part, on_mount_func func) { + + if (part == INVALID) + { + // Something bad happened maybe in auto-detect + // Either way, no partition was found + func(true); + return; + } + else if (part == MBR) + { + // For the MBR case, all we need to do is mount on sector 0 + fs().mount(0, device.size(), func); + } else + { + /** + * Otherwise, we will have to read the LBA offset + * of the partition to be mounted + */ + device.read(0, + [this, part, func] (hw::IDiskDevice::buffer_t data) { + if (!data) { + // TODO: error-case for unable to read MBR + func(true); + return; + } + + auto* mbr = (MBR::mbr*) data.get(); //< Treat data as MBR + auto pint = static_cast(part - 1); //< Treat VBR1 as index 0 etc. + + /** Get LBA from selected partition */ + auto lba_base = mbr->part[pint].lba_begin; + auto lba_size = mbr->part[pint].sectors; + /** - * Otherwise, we will have to read the LBA offset - * of the partition to be mounted + * Call the filesystems mount function + * with lba_begin as base address */ - device.read(0, - [this, part, func] (hw::IDiskDevice::buffer_t data) - { - if (!data) { - // TODO: error-case for unable to read MBR - func(true); - return; - } - - auto* mbr = (MBR::mbr*) data.get(); //< Treat data as MBR - auto pint = static_cast(part - 1); //< Treat VBR1 as index 0 etc. - - /** Get LBA from selected partition */ - auto lba_base = mbr->part[pint].lba_begin; - auto lba_size = mbr->part[pint].sectors; - - /** - * Call the filesystems mount function - * with lba_begin as base address - */ - fs().mount(lba_base, lba_size, func); - }); - } + fs().mount(lba_base, lba_size, func); + }); + } } std::string Disk::Partition::name() const { diff --git a/src/kernel/terminal_disk.cpp b/src/kernel/terminal_disk.cpp index 62db898cfd..ad2446fd8e 100644 --- a/src/kernel/terminal_disk.cpp +++ b/src/kernel/terminal_disk.cpp @@ -45,116 +45,116 @@ void Terminal::add_disk_commands(Disk_ptr disk) // add 'cd' command add("cd", "Change current directory", - [this, curdir, disk] (const std::vector& args) -> int - { - // current directory, somehow... - std::string target = "/"; - if (!args.empty()) target = args[0]; - - Path path(*curdir); - path += target; - - int rv = target_directory(disk, path); - if (rv) - { - this->write("cd: %s: No such file or directory\r\n", target.c_str()); - return rv; - } - *curdir = path.to_string(); - return 0; - }); + [this, curdir, disk] (const std::vector& args) -> int + { + // current directory, somehow... + std::string target = "/"; + if (!args.empty()) target = args[0]; + + Path path(*curdir); + path += target; + + int rv = target_directory(disk, path); + if (rv) + { + this->write("cd: %s: No such file or directory\r\n", target.c_str()); + return rv; + } + *curdir = path.to_string(); + return 0; + }); // add 'ls' command add("ls", "List files in a folder", - [this, curdir, disk] (const std::vector& args) -> int + [this, curdir, disk] (const std::vector& args) -> int + { + // current directory, somehow... + Path path(*curdir); + if (!args.empty()) path += args[0]; + + int rv = target_directory(disk, path); + if (rv) + { + this->write("ls: %s: No such file or directory\r\n", path.to_string().c_str()); + return rv; + } + + std::string target = path.to_string(); + + auto& fs = disk->fs(); + auto vec = fs::new_shared_vector(); + auto err = fs.ls(target, vec); + if (!err) + { + this->write("%s \t%s \t%s \t%s\r\n", + "Name", "Size", "Type", "Sector"); + for (auto& ent : *vec) { - // current directory, somehow... - Path path(*curdir); - if (!args.empty()) path += args[0]; - - int rv = target_directory(disk, path); - if (rv) - { - this->write("ls: %s: No such file or directory\r\n", path.to_string().c_str()); - return rv; - } - - std::string target = path.to_string(); - - auto& fs = disk->fs(); - auto vec = fs::new_shared_vector(); - auto err = fs.ls(target, vec); - if (!err) - { - this->write("%s \t%s \t%s \t%s\r\n", - "Name", "Size", "Type", "Sector"); - for (auto& ent : *vec) - { - this->write("%s \t%llu \t%s \t%llu\r\n", - ent.name().c_str(), ent.size, ent.type_string().c_str(), ent.block); - } - this->write("Total %u\r\n", vec->size()); - return 0; - } - else - { - this->write("Could not list %s\r\n", args[0].c_str()); - return 1; - } - }); + this->write("%s \t%llu \t%s \t%llu\r\n", + ent.name().c_str(), ent.size, ent.type_string().c_str(), ent.block); + } + this->write("Total %u\r\n", vec->size()); + return 0; + } + else + { + this->write("Could not list %s\r\n", args[0].c_str()); + return 1; + } + }); // add 'stat' command add("stat", "List file information", - [this, disk] (const std::vector& args) -> int + [this, disk] (const std::vector& args) -> int + { + if (!args.empty()) + { + auto& fs = disk->fs(); + auto ent = fs.stat(args[0]); + if (ent.is_valid()) + { + this->write("%s \t%s \t%s \t%s\r\n", + "Name", "Size", "Type", "Sector"); + this->write("%s \t%llu \t%s \t%llu\r\n", + ent.name().c_str(), ent.size, ent.type_string().c_str(), ent.block); + return 0; + } + else { - if (!args.empty()) - { - auto& fs = disk->fs(); - auto ent = fs.stat(args[0]); - if (ent.is_valid()) - { - this->write("%s \t%s \t%s \t%s\r\n", - "Name", "Size", "Type", "Sector"); - this->write("%s \t%llu \t%s \t%llu\r\n", - ent.name().c_str(), ent.size, ent.type_string().c_str(), ent.block); - return 0; - } - else - { - this->write("stat: Cannot stat '%s'\r\n", args[0].c_str()); - return 1; - } - } - else - { - this->write("%s\r\n", "stat: Not enough arguments"); - return 1; - } - }); + this->write("stat: Cannot stat '%s'\r\n", args[0].c_str()); + return 1; + } + } + else + { + this->write("%s\r\n", "stat: Not enough arguments"); + return 1; + } + }); // add 'cat' command add("cat", "Concatenate files and print", - [this, disk] (const std::vector& args) -> int + [this, disk] (const std::vector& args) -> int + { + auto& fs = disk->fs(); + + for (const auto& file : args) + { + // get file information + auto ent = fs.stat(file); + if (!ent.is_valid()) { - auto& fs = disk->fs(); - - for (const auto& file : args) - { - // get file information - auto ent = fs.stat(file); - if (!ent.is_valid()) - { - this->write("cat: '%s': No such file or directory\r\n", file.c_str()); - return 1; - } - // read file contents - auto buf = fs.read(ent, 0, ent.size); - if (!buf.buffer) - { - this->write("cat: '%s': I/O error\r\n", file.c_str()); - return 1; - } - // write to terminal client - std::string buffer((char*) buf.buffer.get(), buf.len); - this->write("%s\r\n", buffer.c_str()); - } - return 0; - }); + this->write("cat: '%s': No such file or directory\r\n", file.c_str()); + return 1; + } + // read file contents + auto buf = fs.read(ent, 0, ent.size); + if (!buf.buffer) + { + this->write("cat: '%s': I/O error\r\n", file.c_str()); + return 1; + } + // write to terminal client + std::string buffer((char*) buf.buffer.get(), buf.len); + this->write("%s\r\n", buffer.c_str()); + } + return 0; + }); } diff --git a/test/fat/fat16.cpp b/test/fat/fat16.cpp index 23d11c8317..2ce4bc481f 100644 --- a/test/fat/fat16.cpp +++ b/test/fat/fat16.cpp @@ -38,69 +38,69 @@ void Service::start() // auto-mount filesystem disk->mount( - [disk] (fs::error_t err) - { - CHECKSERT(!err, "Filesystem auto-mounted"); + [disk] (fs::error_t err) + { + CHECKSERT(!err, "Filesystem auto-mounted"); - auto& fs = disk->fs(); - printf("\t\t%s filesystem\n", fs.name().c_str()); + auto& fs = disk->fs(); + printf("\t\t%s filesystem\n", fs.name().c_str()); - auto vec = fs::new_shared_vector(); - err = fs.ls("/", vec); - CHECKSERT(!err, "List root directory"); + auto vec = fs::new_shared_vector(); + err = fs.ls("/", vec); + CHECKSERT(!err, "List root directory"); - CHECKSERT(vec->size() == 1, "Exactly one ent in root dir"); + CHECKSERT(vec->size() == 1, "Exactly one ent in root dir"); - auto& e = vec->at(0); - CHECKSERT(e.is_file(), "Ent is a file"); - CHECKSERT(e.name() == "banana.txt", "Ents name is 'banana.txt'"); + auto& e = vec->at(0); + CHECKSERT(e.is_file(), "Ent is a file"); + CHECKSERT(e.name() == "banana.txt", "Ents name is 'banana.txt'"); - }); + }); // re-mount on VBR1 disk->mount(disk->VBR1, - [disk] (fs::error_t err) - { - CHECKSERT(!err, "Filesystem mounted on VBR1"); - - // verify that we can read file - auto& fs = disk->fs(); - auto ent = fs.stat("/banana.txt"); - CHECKSERT(ent.is_valid(), "Stat file in root dir"); - CHECKSERT(ent.is_file(), "Entity is file"); - CHECKSERT(!ent.is_dir(), "Entity is not directory"); - CHECKSERT(ent.name() == "banana.txt", "Name is 'banana.txt'"); - - printf("%s\n", internal_banana.c_str()); - - // try reading banana-file - auto buf = fs.read(ent, 0, ent.size); - auto banana = buf.to_string(); - - CHECKSERT(banana == internal_banana, "Correct banana #1"); - - bool test = true; - - for (size_t i = 0; i < internal_banana.size(); i++) - { - // read one byte at a time - buf = fs.read(ent, i, 1); - /// @buf should evaluate to 'true' if its valid - CHECKSERT(buf, "Validate buffer"); - - // verify that it matches the same location in test-string - test = ((char) buf.buffer.get()[0] == internal_banana[i]); - if (!test) - { - printf("!! Random access read test failed on i = %u\n", i); - break; - } - } - CHECKSERT(test, "Validate random access sync read"); - - buf = fs.readFile("/banana.txt"); - banana = buf.to_string(); - CHECKSERT(banana == internal_banana, "Correct banana #2"); - }); + [disk] (fs::error_t err) + { + CHECKSERT(!err, "Filesystem mounted on VBR1"); + + // verify that we can read file + auto& fs = disk->fs(); + auto ent = fs.stat("/banana.txt"); + CHECKSERT(ent.is_valid(), "Stat file in root dir"); + CHECKSERT(ent.is_file(), "Entity is file"); + CHECKSERT(!ent.is_dir(), "Entity is not directory"); + CHECKSERT(ent.name() == "banana.txt", "Name is 'banana.txt'"); + + printf("%s\n", internal_banana.c_str()); + + // try reading banana-file + auto buf = fs.read(ent, 0, ent.size); + auto banana = buf.to_string(); + + CHECKSERT(banana == internal_banana, "Correct banana #1"); + + bool test = true; + + for (size_t i = 0; i < internal_banana.size(); i++) + { + // read one byte at a time + buf = fs.read(ent, i, 1); + /// @buf should evaluate to 'true' if its valid + CHECKSERT(buf, "Validate buffer"); + + // verify that it matches the same location in test-string + test = ((char) buf.buffer.get()[0] == internal_banana[i]); + if (!test) + { + printf("!! Random access read test failed on i = %u\n", i); + break; + } + } + CHECKSERT(test, "Validate random access sync read"); + + buf = fs.readFile("/banana.txt"); + banana = buf.to_string(); + CHECKSERT(banana == internal_banana, "Correct banana #2"); + }); INFO("FAT16", "SUCCESS"); } From 14b05a3a11d4aa67beded8a44ce2ceec61f91061 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Wed, 13 Apr 2016 14:02:49 +0200 Subject: [PATCH 148/311] fs: Commentary on disk header --- api/fs/disk.hpp | 62 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/api/fs/disk.hpp b/api/fs/disk.hpp index d096b8fc20..539125b5d5 100644 --- a/api/fs/disk.hpp +++ b/api/fs/disk.hpp @@ -15,6 +15,37 @@ // See the License for the specific language governing permissions and // limitations under the License. +/** + * /// Create basic FAT disk /// + * + * // create disk from a given disk-device + * auto disk = std::make_shared (device); + * // mount filesystem on auto-detected volume + * disk->mount( + * [disk] (fs::error_t err) { + * if (err) { + * printf("Bad!\n"); + * return; + * } + * // reference to filesystem + * auto& fs = disk->fs(); + * // synchronous stat: + * auto dirent = fs.stat("/file"); + * }); + * + * /// Construct custom filesystem /// + * + * // constructing on MBR means mount on sector 0 + * disk->mount(filesystem_args..., Disk::MBR, + * [disk] { + * printf("Disk mounted!\n"); + * auto& fs = disk->fs(); + * + * auto dirent = fs.stat("/file"); + * }); + * +**/ + #pragma once #ifndef FS_DISK_HPP #define FS_DISK_HPP @@ -36,9 +67,6 @@ namespace fs { using on_mount_func = std::function; using lba_t = uint32_t; - /** Constructor */ - explicit Disk(hw::IDiskDevice&); - enum partition_t { MBR = 0, //< Master Boot Record (0) VBR1, //> extended partitions (1-4) @@ -76,15 +104,15 @@ namespace fs { }; //< struct Partition - /** Return a reference to the specified filesystem */ - FileSystem& fs() noexcept - { return *filesys; } - //************** disk functions **************// + // construct a disk with a given disk-device + explicit Disk(hw::IDiskDevice&); + + // returns the device the disk is using hw::IDiskDevice& dev() noexcept { return device; } - + // Returns true if the disk has no sectors bool empty() const noexcept { return device.size() == 0; } @@ -106,13 +134,19 @@ namespace fs { internal_mount(part, func); } - /** - * Returns a vector of the partitions on a disk - * - * The disk does not need to be mounted beforehand - */ + // Creates a vector of the partitions on disk (see: on_parts_func) + // Note: The disk does not need to be mounted beforehand void partitions(on_parts_func func); - + + // returns true if a filesystem is mounted + bool fs_mounted() const noexcept + { return filesys; } + + // Returns a reference to a mounted filesystem + // If no filesystem is mounted, the results are undefined + FileSystem& fs() noexcept + { return *filesys; } + private: void internal_mount(partition_t part, on_mount_func func); From 4230bc24d5de58b15748a292980fc2bc26a019a8 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Wed, 13 Apr 2016 14:09:00 +0200 Subject: [PATCH 149/311] fs: Explicit cast for unique_ptr --- api/fs/disk.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/fs/disk.hpp b/api/fs/disk.hpp index 539125b5d5..07ae90969e 100644 --- a/api/fs/disk.hpp +++ b/api/fs/disk.hpp @@ -140,7 +140,7 @@ namespace fs { // returns true if a filesystem is mounted bool fs_mounted() const noexcept - { return filesys; } + { return (bool) filesys; } // Returns a reference to a mounted filesystem // If no filesystem is mounted, the results are undefined From 4efcc28e48f01c8f907b1f7bd37e1bc05a0b36a5 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Wed, 13 Apr 2016 15:02:49 +0200 Subject: [PATCH 150/311] New virtio interface, using GSL span (WIP) --- api/common | 2 + api/virtio/virtio.hpp | 71 +++++----- src/Makefile | 9 +- src/seed/Makefile | 2 +- src/virtio/virtio_queue.cpp | 235 +++++----------------------------- src/virtio/virtionet.cpp | 38 +++--- test/virtio_queue/service.cpp | 18 ++- test/virtio_queue/test.sh | 4 + 8 files changed, 115 insertions(+), 264 deletions(-) diff --git a/api/common b/api/common index 6c363dd72a..24b56e1c8b 100644 --- a/api/common +++ b/api/common @@ -54,4 +54,6 @@ #include "warn" #include "info" +#include + #endif diff --git a/api/virtio/virtio.hpp b/api/virtio/virtio.hpp index 1d601b630f..3166b90a5a 100644 --- a/api/virtio/virtio.hpp +++ b/api/virtio/virtio.hpp @@ -61,18 +61,18 @@ #define VIRTIO_CONFIG_S_DRIVER_OK 4 #define VIRTIO_CONFIG_S_FAILED 0x80 -/** A simple scatter-gather list used for Queue::enqueue. - ( From sanos, virtio.h - probably Linux originally) -*/ -struct scatterlist { - void* data; - int size; -}; //#include class Virtio { + public: + /** A wrapper for buffers to be passed in to the Queue */ + struct Token { + uint8_t* data; + size_t size; + }; + // http://docs.oasis-open.org/virtio/virtio/v1.0/csprd01/virtio-v1.0-csprd01.html#x1-860005 // Virtio device types enum virtiotype_t @@ -95,13 +95,19 @@ class Virtio /** Virtio Queue class. */ class Queue { - /** @note Using typedefs in order to keep the standard notation. */ - typedef uint64_t le64; - typedef uint32_t le32; - typedef uint16_t le16; - typedef uint16_t u16; - typedef uint8_t u8; + public: + // "Direction" of tokens + enum Direction { IN, OUT }; + + private: + + /** @note Using typedefs in order to keep the standard notation. */ + using le64 = uint64_t; + using le32 = uint32_t; + using le16 = uint16_t; + using u16 = uint16_t; + using u8 = uint8_t; /** Virtio Ring Descriptor. Virtio std. §2.4.5 */ struct virtq_desc { @@ -154,7 +160,7 @@ class Virtio /** Virtqueue. Virtio std. §2.4.2 */ struct virtq { - // The actual descriptors (16 bytes each) + // The actual descriptors (i.e. tokens) (16 bytes each) virtq_desc* desc;// [ /* Queue Size*/ ]; // A ring of available descriptor heads with free-running index. @@ -180,13 +186,10 @@ class Virtio virtq _queue; uint16_t _iobase = 0; // Device PCI location - uint16_t _num_free = 0; // Number of free descriptors uint16_t _free_head = 0; // First available descriptor uint16_t _num_added = 0; // Entries to be added to _queue.avail->idx uint16_t _last_used_idx = 0; // Last entry inserted by device uint16_t _pci_index = 0; // Queue nr. - //void **_data; - /** Handler for data coming in on virtq.used. */ delegate _data_handler; @@ -195,6 +198,14 @@ class Virtio void init_queue(int size, void* buf); public: + /** + Update the available index */ + inline void update_avail_idx () + { + _queue.avail->idx += _num_added; + _num_added = 0; + } + /** Kick hypervisor. Will notify the host (Qemu/Virtualbox etc.) about pending data */ @@ -207,11 +218,10 @@ class Virtio virtq_desc* queue_desc() const { return _queue.desc; } /** Push data tokens onto the queue. - @param sg : A scatterlist of tokens - @param out : The number of outbound tokens (device-readable - TX) - @param in : The number of tokens to be inbound (device-writable RX) + @param buffers : A span of buffers + @param out : true if the buffers are device readable, otherwise false */ - int enqueue(scatterlist sg[], uint32_t out, uint32_t in, void*); + int enqueue(gsl::span buffers, bool out); /** Dequeue a received packet. From SanOS */ uint8_t* dequeue(uint32_t* len); @@ -224,23 +234,20 @@ class Virtio /** Release token. @param head : the token ID to release*/ void release(uint32_t head); - /** Get number of free tokens in Queue */ - uint16_t num_free() const noexcept - { return _num_free; } - - /** Get number of new incoming buffers */ + /** Get number of new incoming buffers, i.e. the increase in + queue_used_->idx since we last checked. An increase means the device + has inserted tokens into the used ring.*/ uint16_t new_incoming() const noexcept { return _queue.used->idx - _last_used_idx; } /** Get number of used buffers */ - uint16_t num_avail() const noexcept + uint16_t num_used() const noexcept { return _queue.avail->idx - _queue.used->idx; } - // gonzoified enqueue & dequeue - void enqueue(void* out, uint32_t out_len, void* in, uint32_t in_len); - void enqueue(void* data, uint32_t len, bool out, bool last); - void* dequeue(uint32_t& len); - + /** Get number of free tokens in Queue */ + uint16_t num_free() const noexcept + { return size() - _free_head; } + // access the current index virtq_desc& current() { diff --git a/src/Makefile b/src/Makefile index 374e14170a..44f44aaa53 100644 --- a/src/Makefile +++ b/src/Makefile @@ -45,7 +45,7 @@ endif CCOPTS = -target i686-elf CPPOPTS = -target i686-elf -INCLUDES = -I../api/sys -I$(INSTALL)/libcxx/include -I$(INC_NEWLIB) -Iinclude -I../api # +INCLUDES = -I../api/sys -I$(INSTALL)/libcxx/include -I$(INC_NEWLIB) -Iinclude -I../api -I../mod/GSL/include # CINCLUDES = -I../api/sys -I$(INC_NEWLIB) -Iinclude -I../api # CCOPTS += $(CAPABS) $(WARNS) -c -m32 -fno-stack-protector -fno-builtin -march=i686 $(CINCLUDES) @@ -66,7 +66,6 @@ OS_OBJECTS = kernel/kernel_start.o kernel/syscalls.o kernel/vga.o \ util/memstream.o \ hw/ide.o hw/pit.o hw/pic.o hw/pci_device.o hw/cpu_freq_sampling.o hw/serial.o\ virtio/virtio.o virtio/virtio_queue.o virtio/virtionet.o \ - virtio/block.o virtio/console.o \ net/ethernet.o net/inet_common.o net/ip4/arp.o net/ip4/ip4.o \ net/tcp.o net/tcp_connection.o net/tcp_connection_states.o \ net/ip4/icmpv4.o net/ip4/udp.o net/ip4/udp_socket.o \ @@ -74,7 +73,7 @@ OS_OBJECTS = kernel/kernel_start.o kernel/syscalls.o kernel/vga.o \ net/ip6/ip6.o net/ip6/icmp6.o net/ip6/udp6.o net/ip6/ndp.o \ net/packet.o net/buffer_store.o \ fs/disk.o fs/filesystem.o fs/mbr.o fs/vbr.o fs/path.o \ - fs/ext4.o fs/fat.o fs/fat_async.o fs/fat_sync.o fs/memdisk.o + fs/ext4.o fs/fat.o fs/fat_async.o fs/fat_sync.o fs/memdisk.o # virtio/console.o virtio/block.o\ CRTI_OBJ = crt/crti.o CRTN_OBJ = crt/crtn.o @@ -100,6 +99,7 @@ stripped: all test # Build like "all" but with debugging output (i.e. the 'debug'-macro) enabled debug-info: CAPABS += -UNO_DEBUG +debug-info: CAPABS += -DGSL_THROW_ON_CONTRACT_VIOLATION debug-info: all test # Build with debugging symbols (OBS: Dramatically increases binary size) @@ -180,6 +180,9 @@ install: $(CRTI_OBJ) $(CRTN_OBJ) # Seed related cp util/service_name.cpp $(INSTALL) cp seed/Makefile $(INSTALL)/Makeseed + # Eexternal dependencies related + mkdir -p $(INSTALL)/mod/ + cp -r ../mod/GSL $(INSTALL)/mod @echo "\nDone!" # Makefile recipes diff --git a/src/seed/Makefile b/src/seed/Makefile index 8ca7a8f325..71a8852abd 100644 --- a/src/seed/Makefile +++ b/src/seed/Makefile @@ -41,7 +41,7 @@ ifndef LD_INC LD_INC = ld endif -INCLUDES = -I$(INC_LIBCXX) -I$(INSTALL)/api/sys -I$(INC_NEWLIB) -I$(INSTALL)/api $(LOCAL_INCLUDES) +INCLUDES = -I$(INC_LIBCXX) -I$(INSTALL)/api/sys -I$(INC_NEWLIB) -I$(INSTALL)/api -I$(INSTALL)/mod/GSL/include $(LOCAL_INCLUDES) all: CAPABS = $(CAPABS_COMMON) -O2 debug: CAPABS = $(CAPABS_COMMON) -O0 diff --git a/src/virtio/virtio_queue.cpp b/src/virtio/virtio_queue.cpp index 28968468dd..df5da58217 100644 --- a/src/virtio/virtio_queue.cpp +++ b/src/virtio/virtio_queue.cpp @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//#define DEBUG // Allow debug +#define DEBUG // Allow debug //#define DEBUG2 #include @@ -40,7 +40,7 @@ unsigned Virtio::Queue::virtq_size(unsigned int qsz) void Virtio::Queue::init_queue(int size, void* buf){ - // The buffer starts with is an array of queue descriptors + // The buffer starts with is an array of queue descriptors (i.e. tokens) _queue.desc = (virtq_desc*)buf; debug("\t * Queue desc @ 0x%lx \n ",(long)_queue.desc); @@ -70,7 +70,7 @@ int empty_handler(uint8_t* UNUSED(data),int UNUSED(size)) { /** Constructor */ Virtio::Queue::Queue(uint16_t size, uint16_t q_index, uint16_t iobase) - : _size(size),_size_bytes(virtq_size(size)),_iobase(iobase),_num_free(size), + : _size(size),_size_bytes(virtq_size(size)),_iobase(iobase), _free_head(0), _num_added(0),_last_used_idx(0),_pci_index(q_index), _data_handler(delegate(empty_handler)) { @@ -91,196 +91,44 @@ Virtio::Queue::Queue(uint16_t size, uint16_t q_index, uint16_t iobase) } -/** Ported more or less directly from SanOS. */ -int Virtio::Queue::enqueue(scatterlist sg[], uint32_t out, uint32_t in, void* UNUSED(data)){ - - uint16_t i,avail,head, prev = _free_head; - - while (_num_free < out + in){ // Queue is full (we think) - //while( num_avail() >= _size) // Wait for Virtio - printf("Buffer full (%i avail," \ - " used.idx: %i, avail.idx: %i )\n", - _pci_index,num_avail(), - _queue.used->idx,_queue.avail->idx - ); - panic("Buffer full"); +/** Ported more or less directly from SanOS. */ +int Virtio::Queue::enqueue(gsl::span buffers, bool out){ + debug ("Enqueuing %i tokens \n", buffers.size()); + Expects(_free_head >= 0); + Expects(_free_head < size()); + Expects(_num_added + 1 > _num_added); + + uint16_t last = _free_head; + uint16_t first = _free_head; + // Place each buffer in a token + for( auto buf : buffers ) { + debug (" buf @ %p \n", buffers.data()); + + // Set read / write flags + _queue.desc[_free_head].flags = + out ? VIRTQ_DESC_F_NEXT : VIRTQ_DESC_F_NEXT | VIRTQ_DESC_F_WRITE; + + // Assign raw buffer + _queue.desc[_free_head].addr = (uint64_t) buf.data; + _queue.desc[_free_head].len = buf.size; + + last = _free_head; + _free_head ++; } - // Remove buffers from the free list - _num_free -= out + in; - head = _free_head; - - - // (implicitly) Mark all outbound tokens as device-readable - for (i = _free_head; out; i = _queue.desc[i].next, out--) - { - _queue.desc[i].flags = VIRTQ_DESC_F_NEXT; - _queue.desc[i].addr = (uint64_t)sg->data; - _queue.desc[i].len = sg->size; - - debug(" Enqueueing outbound: index %i len %li, next %i\n", - _pci_index,i,_queue.desc[i].len,_queue.desc[i].next); - - prev = i; - sg++; - } - - // Mark all inbound tokens as device-writable - for (; in; i = _queue.desc[i].next, in--) - { - debug(" Enqueuing inbound \n"); - _queue.desc[i].flags = VIRTQ_DESC_F_NEXT | VIRTQ_DESC_F_WRITE; - _queue.desc[i].addr = (uint64_t)sg->data; - _queue.desc[i].len = sg->size; - prev = i; - sg++; - } - - // No continue on last buffer - _queue.desc[prev].flags &= ~VIRTQ_DESC_F_NEXT; - - - // Update free pointer - _free_head = i; - - // Set callback token - //vq->data[head] = data; - - // SanOS: Put entry in available array, but do not update avail->idx until sync - avail = (_queue.avail->idx + _num_added++) % _size; - _queue.avail->ring[avail] = head; - debug(" avail: %i \n",_pci_index,avail); - - // Notify about free buffers - //if (_num_free > 0) set_event(&vq->bufavail); - - return _num_free; -} -void Virtio::Queue::enqueue( - void* out, - uint32_t out_len, - void* in, - uint32_t in_len) -{ - int total = (out) ? 1 : 0; - total += (in) ? 1 : 0; - - printf("enqueue total: %d\n", total); - - if (_num_free < total) - { - // Queue is full (we think) - printf("Buffer full (%i avail," \ - " used.idx: %i, avail.idx: %i )\n", - _pci_index, num_avail(), - _queue.used->idx,_queue.avail->idx - ); - panic("Buffer full"); - } - - // Remove buffers from the free list - _num_free -= total; - // remember current head for later - uint16_t head = _free_head; - // the last buffer in queue - virtq_desc* last = nullptr; - - // (implicitly) Mark all outbound tokens as device-readable - if (out) - { - current().flags = VIRTQ_DESC_F_NEXT; - current().addr = (intptr_t) out; - current().len = out_len; - - printf(" Enqueueing outbound: index %u len %u (actual: %u), next %d\n", - _pci_index, head, current().len, out_len, current().next); - - last = ¤t(); - // go to next - go_next(); - } - - // Mark all inbound tokens as device-writable - if (in) - { - printf(" Enqueuing inbound \n"); - current().flags = VIRTQ_DESC_F_NEXT | VIRTQ_DESC_F_WRITE; - current().addr = (intptr_t) in; - current().len = in_len; - - last = ¤t(); - // go to next - go_next(); - } - // No continue on last buffer - last->flags &= ~VIRTQ_DESC_F_NEXT; + _queue.desc[last].flags &= ~VIRTQ_DESC_F_NEXT; - // SanOS: Put entry in available array, but do not update avail->idx until sync - uint16_t avail = (_queue.avail->idx + _num_added++) % _size; - _queue.avail->ring[avail] = head; - debug(" avail: %u\n", _pci_index, avail); -} -void Virtio::Queue::enqueue(void* data, uint32_t len, bool out, bool last) -{ - if (_num_free < 1) - { - // Queue is full (we think) - printf("Buffer full (%i avail," \ - " used.idx: %i, avail.idx: %i )\n", - _pci_index, num_avail(), - _queue.used->idx,_queue.avail->idx - ); - panic("Buffer full"); - } + // Place the head of this current chain in the avail ring + uint16_t avail_index = (_queue.avail->idx + _num_added++) % _size; + _queue.avail->ring[avail_index] = first; - // Remove buffers from the free list - _num_free -= 1; - // remember current head for later - uint16_t head = _free_head; - // No continue on last buffer - uint16_t flags = last ? 0 : VIRTQ_DESC_F_NEXT; - // WRITE for inbound - current().flags = flags | (out ? 0 : VIRTQ_DESC_F_WRITE); - current().addr = (intptr_t) data; - current().len = len; - - if (out) - printf(" Enqueueing outbound: %p index %u len %u (actual: %u), next %d\n", - _pci_index, data, head, current().len, len, current().next); - else - printf(" Enqueueing inbound: %p index %u len %u (actual: %u), next %d\n", - _pci_index, data, head, current().len, len, current().next); - - // go to next in ring - go_next(); - - // SanOS: Put entry in available array, but do not update avail->idx until sync - uint16_t avail = (_queue.avail->idx + _num_added++) % _size; - _queue.avail->ring[avail] = head; -} -void* Virtio::Queue::dequeue(uint32_t& len) -{ - // Return NULL if there are no more completed buffers in the queue - if (_last_used_idx == _queue.used->idx) - { - debug(" Can't dequeue - no used buffers \n",_pci_index); - return nullptr; - } - - // Get next completed buffer - auto& e = _queue.used->ring[_last_used_idx % _size]; - - printf(" Releasing token %u. Len: %u\n",_pci_index, e.id, e.len); - void* data = (void*) _queue.desc[e.id].addr; - len = e.len; - - // Release buffer - release(e.id); - _last_used_idx++; + debug(" avail_index: %i size: %i, _free_head %i \n", + _pci_index, avail_index, size(), _free_head ); - return data; + Ensures(_free_head <= size()); + return buffers.size(); } void Virtio::Queue::release(uint32_t head) @@ -288,15 +136,9 @@ void Virtio::Queue::release(uint32_t head) // Mark queue element "head" as free (the whole token chain) uint32_t i = head; - //It's at least one token... - _num_free++; - - //...possibly with a tail - while (_queue.desc[i].flags & VIRTQ_DESC_F_NEXT) { i = _queue.desc[i].next; - _num_free++; } // Add buffers back to free list @@ -342,15 +184,8 @@ void Virtio::Queue::enable_interrupts(){ } void Virtio::Queue::kick(){ - //__sync_synchronize (); - - // Atomically increment (maybe not necessary?) - //__sync_add_and_fetch(&(_queue.avail->idx),_num_added); - _queue.avail->idx += _num_added; - //__sync_synchronize (); - - _num_added = 0; + update_avail_idx(); if (!(_queue.used->flags & VIRTQ_USED_F_NO_NOTIFY)){ debug(" Kicking virtio. Iobase 0x%x \n", diff --git a/src/virtio/virtionet.cpp b/src/virtio/virtionet.cpp index 3a03c23b97..f83598d198 100644 --- a/src/virtio/virtionet.cpp +++ b/src/virtio/virtionet.cpp @@ -159,26 +159,22 @@ VirtioNet::VirtioNet(hw::PCI_Device& d) }; -/** Port-ish from SanOS */ + int VirtioNet::add_receive_buffer(){ - virtio_net_hdr* hdr; - scatterlist sg[2]; + // Virtio Std. § 5.1.6.3 auto buf = bufstore_.get_raw_buffer(); debug2(" Added receive-bufer @ 0x%x \n", (uint32_t)buf); - hdr = (virtio_net_hdr*)buf; - - sg[0].data = hdr; + std::array tokens; + tokens[0].data = buf; + tokens[0].size = sizeof(virtio_net_hdr); + tokens[1].data = buf + sizeof(virtio_net_hdr); + tokens[1].size = bufsize() - sizeof(virtio_net_hdr); - //NOTE: using separate empty header doesn't work for RX, but it works for TX... - //sg[0].data = (void*)&empty_header; - sg[0].size = sizeof(virtio_net_hdr); - sg[1].data = buf + sizeof(virtio_net_hdr); - sg[1].size = bufsize()-sizeof(virtio_net_hdr); - rx_q.enqueue(sg, 0, 2,buf); + rx_q.enqueue(tokens, Virtio::Queue::Direction::IN); return 0; } @@ -217,10 +213,8 @@ void VirtioNet::irq_handler(){ } void VirtioNet::service_queues(){ - debug2(" %i new packets, %i available tokens \n", - rx_q.new_incoming(),rx_q.num_avail()); - - + debug2(" %i new packets \n", + rx_q.new_incoming()); /** For RX, we dequeue, add new buffers and let receiver is responsible for memory management (they know when they're done with the packet.) */ @@ -364,15 +358,15 @@ void VirtioNet::transmit(net::Packet_ptr pckt){ void VirtioNet::enqueue(net::Packet_ptr pckt){ // A scatterlist for virtio-header + data - scatterlist sg[2]; + std::array tokens; // This setup requires all tokens to be pre-chained like in SanOS - sg[0].data = (void*)&empty_header; - sg[0].size = sizeof(virtio_net_hdr); - sg[1].data = (void*)pckt->buffer(); - sg[1].size = pckt->size(); + tokens[0].data = (uint8_t*) &empty_header; + tokens[0].size = sizeof(virtio_net_hdr); + tokens[1].data = pckt->buffer(); + tokens[1].size = pckt->size(); // Enqueue scatterlist, 2 pieces readable, 0 writable. - tx_q.enqueue(sg, 2, 0, 0); + tx_q.enqueue(tokens, Virtio::Queue::Direction::OUT); } diff --git a/test/virtio_queue/service.cpp b/test/virtio_queue/service.cpp index 5ee2bb5372..eeb11875a7 100644 --- a/test/virtio_queue/service.cpp +++ b/test/virtio_queue/service.cpp @@ -51,29 +51,35 @@ const lest::test virtio_tests[] = { EXPECT (vq.num_free() == queue_size); WHEN ("You enqueue 10 tokens") { - for (int i = 0; i < 10; i++) - vq.enqueue(malloc(100), 100, OUT, 0); + + for (int i = 0; i < 10; i++) { + Virtio::Token token {(uint8_t*) malloc(100), 100 }; + vq.enqueue(token , Virtio::Queue::Direction::OUT); + printf("Free tokens: %i \n", vq.num_free()); + } EXPECT (vq.num_free() == (queue_size - 10)); THEN("You dequeue 10 tokens") { uint32_t res; for (int i = 0; i < 10; i++) - vq.dequeue(res); + vq.dequeue(&res); EXPECT (vq.num_free() == 0); } } WHEN ("You insert too many tokens") { - for (int i = 0; i < queue_size * 3; i++) - vq.enqueue(malloc(100), 100, OUT, 0); + + for (int i = 0; i < queue_size * 3; i++) { + Virtio::Token token {(uint8_t*) malloc(100), 100 }; + vq.enqueue(token, Virtio::Queue::Direction::OUT); + } THEN ("Queue reports 10 items") { EXPECT (vq.num_free() == (queue_size - 10)); } } - } } } diff --git a/test/virtio_queue/test.sh b/test/virtio_queue/test.sh index c98a6ccd47..c663df1801 100755 --- a/test/virtio_queue/test.sh +++ b/test/virtio_queue/test.sh @@ -3,3 +3,7 @@ source ../test_base make start test_virtio_queue.img + +cd ../tcp +make clean && make +start test_tcp.img From 2ff42e1f2f9bcdbe7faa833b0ff686bdf7a81f9e Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Wed, 13 Apr 2016 15:18:38 +0200 Subject: [PATCH 151/311] dhcp: Timeout --- api/hw/pit.hpp | 5 ++- api/net/dhcp/dh4client.hpp | 29 ++++++++------- api/net/inet.hpp | 2 -- api/net/inet4.hpp | 8 ++--- api/net/inet4.inc | 6 ++-- src/debug/test_service.cpp | 72 +++++++++++++++++++------------------- src/net/dhcp/dh4client.cpp | 51 +++++++++++++++++++-------- 7 files changed, 101 insertions(+), 72 deletions(-) diff --git a/api/hw/pit.hpp b/api/hw/pit.hpp index 127da36b70..a730f50eed 100644 --- a/api/hw/pit.hpp +++ b/api/hw/pit.hpp @@ -97,7 +97,10 @@ namespace hw { /** Stop a timer. @param it: A valid iterator to timer */ void stop_timer(Timer_iterator it); - + + static void stop(Timer_iterator it) + { instance().stop_timer(it); } + inline size_t active_timers() { return timers_.size(); } /** No copy or move. The OS owns one instance forever. */ diff --git a/api/net/dhcp/dh4client.hpp b/api/net/dhcp/dh4client.hpp index c55bfa3b5f..190479eba6 100644 --- a/api/net/dhcp/dh4client.hpp +++ b/api/net/dhcp/dh4client.hpp @@ -19,8 +19,8 @@ #ifndef NET_DHCP_DH4CLIENT_HPP #define NET_DHCP_DH4CLIENT_HPP +#include #include "../packet.hpp" -#include namespace net { @@ -33,28 +33,31 @@ namespace net { public: using Stack = Inet; - using On_config = delegate; + using config_func = delegate; DHClient() = delete; DHClient(DHClient&) = delete; - DHClient(Stack& inet) - : stack(inet) {} + DHClient(Stack& inet); - Stack& stack; - void negotiate(); // --> offer - inline void on_config(On_config handler){ - config_handler = handler; - } + // negotiate with local DHCP server + void negotiate(double timeout_secs); + + // handler for result of DHCP negotation + // timeout is true if the negotiation timed out + void on_config(config_func handler) + { config_handler = handler; } private: void offer(UDPSocket&, const char* data, size_t len); void request(UDPSocket&); // --> acknowledge void acknowledge(const char* data, size_t len); - uint32_t xid; - IP4::addr ipaddr, netmask, router, dns_server; - uint32_t lease_time; - On_config config_handler = [](Stack&){ INFO("DHCPv4::On_config","Config complete"); }; + Stack& stack; + uint32_t xid; + IP4::addr ipaddr, netmask, router, dns_server; + uint32_t lease_time; + config_func config_handler; + hw::PIT::Timer_iterator timeout; }; } diff --git a/api/net/inet.hpp b/api/net/inet.hpp index 33b4823e25..348f100091 100644 --- a/api/net/inet.hpp +++ b/api/net/inet.hpp @@ -45,8 +45,6 @@ namespace net { virtual TCP& tcp() = 0; virtual UDP& udp() = 0; - virtual std::shared_ptr dhclient() = 0; - virtual constexpr uint16_t MTU() const = 0; virtual Packet_ptr createPacket(size_t size) = 0; diff --git a/api/net/inet4.hpp b/api/net/inet4.hpp index b90e04868e..1035e6dfbc 100644 --- a/api/net/inet4.hpp +++ b/api/net/inet4.hpp @@ -26,15 +26,15 @@ #include "ip4/arp.hpp" #include "ip4/ip4.hpp" #include "ip4/udp.hpp" +#include "ip4/icmpv4.hpp" #include "dns/client.hpp" #include "tcp.hpp" -#include "dhcp/dh4client.hpp" #include -#include "ip4/icmpv4.hpp" - namespace net { + class DHClient; + /** A complete IP4 network stack */ template class Inet4 : public Inet{ @@ -65,7 +65,7 @@ namespace net { UDP& udp() override { return udp_; } /** Get the DHCP client (if any) */ - inline std::shared_ptr dhclient() override { return dhcp_; } + auto dhclient() { return dhcp_; } /** Create a Packet, with a preallocated buffer. @param size : the "size" reported by the allocated packet. diff --git a/api/net/inet4.inc b/api/net/inet4.inc index 5b9e7e0a81..be8d4a788f 100644 --- a/api/net/inet4.inc +++ b/api/net/inet4.inc @@ -1,6 +1,7 @@ //-*- C++ -*- #define DEBUG #include +#include "dhcp/dh4client.hpp" namespace net { @@ -25,7 +26,7 @@ namespace net /** Upstream wiring */ // Packets available nic.on_transmit_queue_available( - transmit_avail_delg::from, &Inet4::process_sendq>(*this)); + transmit_avail_delg::from, &Inet4::process_sendq>(*this)); // Phys -> Eth (Later, this will be passed through router) nic.set_linklayer_out(eth_bottom); @@ -82,7 +83,8 @@ namespace net { INFO("Inet4","Applying DHCP client"); dhcp_ = std::make_shared(*this); - dhcp_->negotiate(); + // 2 second timeout for DHCP-server negotation + dhcp_->negotiate(2.0); } template diff --git a/src/debug/test_service.cpp b/src/debug/test_service.cpp index 49fc5b85cb..5210266a8a 100644 --- a/src/debug/test_service.cpp +++ b/src/debug/test_service.cpp @@ -17,7 +17,6 @@ #include #include -#include #include "ircd.hpp" using namespace std::chrono; @@ -31,10 +30,10 @@ void Service::start() hw::Nic& eth0 = hw::Dev::eth<0,VirtioNet>(); inet = std::make_unique >(eth0); inet->network_config( - {{ 10,0,0,42 }}, // IP - {{ 255,255,255,0 }}, // Netmask - {{ 10,0,0,1 }}, // Gateway - {{ 8,8,8,8 }} ); // DNS + {{ 10,0,0,42 }}, // IP + {{ 255,255,255,0 }}, // Netmask + {{ 10,0,0,1 }}, // Gateway + {{ 8,8,8,8 }} ); // DNS /* auto& tcp = inet->tcp(); @@ -72,41 +71,42 @@ void Service::start() }); });*/ + using namespace net; const UDP::port_t port = 4242; auto& sock = inet->udp().bind(port); - + sock.on_read( - [&sock] (UDP::addr_t addr, UDP::port_t port, - const char* data, size_t len) - { - std::string strdata(data, len); - CHECK(1, "Getting UDP data from %s:%d -> %s", - addr.str().c_str(), port, strdata.c_str()); - // send the same thing right back! - sock.sendto(addr, port, data, len, - [&sock, addr, port] - { - // print this message once - printf("*** Starting spam (you should see this once)\n"); - - typedef std::function rnd_gen_t; - auto next = std::make_shared (); - - *next = - [next, &sock, addr, port] () - { - // spam this message at max speed - std::string text("Spamorino Cappucino\n"); - - sock.sendto(addr, port, text.data(), text.size(), - [next] { (*next)(); }); - }; - - // start spamming - (*next)(); - }); - }); + [&sock] (UDP::addr_t addr, UDP::port_t port, + const char* data, size_t len) + { + std::string strdata(data, len); + CHECK(1, "Getting UDP data from %s:%d -> %s", + addr.str().c_str(), port, strdata.c_str()); + // send the same thing right back! + sock.sendto(addr, port, data, len, + [&sock, addr, port] + { + // print this message once + printf("*** Starting spam (you should see this once)\n"); + + typedef std::function rnd_gen_t; + auto next = std::make_shared (); + + *next = + [next, &sock, addr, port] () + { + // spam this message at max speed + std::string text("Spamorino Cappucino\n"); + + sock.sendto(addr, port, text.data(), text.size(), + [next] { (*next)(); }); + }; + + // start spamming + (*next)(); + }); + }); printf("*** TEST SERVICE STARTED *** \n"); } diff --git a/src/net/dhcp/dh4client.cpp b/src/net/dhcp/dh4client.cpp index 8d23d662d1..b26b2da91e 100644 --- a/src/net/dhcp/dh4client.cpp +++ b/src/net/dhcp/dh4client.cpp @@ -154,9 +154,30 @@ namespace net { return (dhcp_option_t*) option; } - - void DHClient::negotiate() + + DHClient::DHClient(Stack& inet) + : stack(inet) + { + config_handler = + [] (Stack&, bool timeout) { + if (timeout) + INFO("DHCPv4","Negotiation timed out"); + else + INFO("DHCPv4","Config complete"); + }; + } + + void DHClient::negotiate(double timeout_secs) { + // set timeout handler + this->timeout = hw::PIT::instance().on_timeout(timeout_secs, + [this] { + // reset session ID + this->xid = 0; + // call on_config with timeout = true + this->config_handler(stack, true); + }); + // create a random session ID this->xid = OS::cycles_since_boot() & 0xFFFFFFFF; MYINFO("Negotiating IP-address (xid=%u)", xid); @@ -220,17 +241,17 @@ namespace net socket.bcast(IP4::INADDR_ANY, DHCP_DEST_PORT, packet, packetlen); socket.on_read( - [this, &socket] (IP4::addr, UDP::port_t port, - const char* data, size_t len) - { - if (port == DHCP_DEST_PORT) - { - // we have got a DHCP Offer - debug("Received possible DHCP OFFER from %s:%d\n", - addr.str().c_str(), DHCP_DEST_PORT); - this->offer(socket, data, len); - } - }); + [this, &socket] (IP4::addr, UDP::port_t port, + const char* data, size_t len) + { + if (port == DHCP_DEST_PORT) + { + // we have got a DHCP Offer + debug("Received possible DHCP OFFER from %s:%d\n", + addr.str().c_str(), DHCP_DEST_PORT); + this->offer(socket, data, len); + } + }); } const dhcp_option_t* get_option(const uint8_t* options, uint8_t code) @@ -437,7 +458,9 @@ namespace net MYINFO("Server acknowledged our request!"); stack.network_config(this->ipaddr, this->netmask, this->router, this->dns_server); + // stop timeout from happening + hw::PIT::stop(timeout); // run some post-DHCP event to release the hounds - this->config_handler(stack); + this->config_handler(stack, false); } } From 20f53b5a36a70fbbdba47729d512879ce322237a Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Wed, 13 Apr 2016 17:02:10 +0200 Subject: [PATCH 152/311] dhcp: Add on_config callback to inet --- api/net/dhcp/dh4client.hpp | 2 +- api/net/inet4.hpp | 17 +++++---- api/net/inet4.inc | 8 ++++- src/debug/test_service.cpp | 71 +++++++++++++++++++++----------------- src/net/dhcp/dh4client.cpp | 59 ++++++++++++++++--------------- 5 files changed, 86 insertions(+), 71 deletions(-) diff --git a/api/net/dhcp/dh4client.hpp b/api/net/dhcp/dh4client.hpp index 190479eba6..d1eaecadeb 100644 --- a/api/net/dhcp/dh4client.hpp +++ b/api/net/dhcp/dh4client.hpp @@ -33,7 +33,7 @@ namespace net { public: using Stack = Inet; - using config_func = delegate; + using config_func = delegate; DHClient() = delete; DHClient(DHClient&) = delete; diff --git a/api/net/inet4.hpp b/api/net/inet4.hpp index 1035e6dfbc..79d1fe27cb 100644 --- a/api/net/inet4.hpp +++ b/api/net/inet4.hpp @@ -94,19 +94,22 @@ namespace net { * @func a delegate that provides a hostname and its address, which is 0 if the * name @hostname was not found. Note: Test with INADDR_ANY for a 0-address. **/ - inline virtual void - resolve(const std::string& hostname, - resolve_func func) override + virtual void resolve(const std::string& hostname, + resolve_func func) override { dns.resolve(this->dns_server, hostname, func); } - - inline virtual void - set_dns_server(IP4::addr server) override + + virtual void set_dns_server(IP4::addr server) override { this->dns_server = server; } - + + // handler called after the network successfully, or + // unsuccessfully negotiated with DHCP-server + // the timeout parameter indicates whether dhcp negotitation failed + void on_config(delegate handler); + /** We don't want to copy or move an IP-stack. It's tied to a device. */ Inet4(Inet4&) = delete; Inet4(Inet4&&) = delete; diff --git a/api/net/inet4.inc b/api/net/inet4.inc index be8d4a788f..1363b60d56 100644 --- a/api/net/inet4.inc +++ b/api/net/inet4.inc @@ -86,7 +86,13 @@ namespace net // 2 second timeout for DHCP-server negotation dhcp_->negotiate(2.0); } - + + template + void Inet4::on_config(delegate handler) + { + dhcp_->on_config(handler); + } + template void Inet4::process_sendq(size_t packets) { diff --git a/src/debug/test_service.cpp b/src/debug/test_service.cpp index 5210266a8a..7a1055ea6a 100644 --- a/src/debug/test_service.cpp +++ b/src/debug/test_service.cpp @@ -72,41 +72,48 @@ void Service::start() });*/ - using namespace net; - const UDP::port_t port = 4242; - auto& sock = inet->udp().bind(port); - - sock.on_read( - [&sock] (UDP::addr_t addr, UDP::port_t port, - const char* data, size_t len) + inet->on_config( + [] (bool timeout) { - std::string strdata(data, len); - CHECK(1, "Getting UDP data from %s:%d -> %s", - addr.str().c_str(), port, strdata.c_str()); - // send the same thing right back! - sock.sendto(addr, port, data, len, - [&sock, addr, port] + printf("Inet::on_config(%d)\n", timeout); + + using namespace net; + const UDP::port_t port = 4242; + auto& sock = inet->udp().bind(port); + + sock.on_read( + [&sock] (UDP::addr_t addr, UDP::port_t port, + const char* data, size_t len) { - // print this message once - printf("*** Starting spam (you should see this once)\n"); - - typedef std::function rnd_gen_t; - auto next = std::make_shared (); - - *next = - [next, &sock, addr, port] () + std::string strdata(data, len); + CHECK(1, "Getting UDP data from %s:%d -> %s", + addr.str().c_str(), port, strdata.c_str()); + // send the same thing right back! + sock.sendto(addr, port, data, len, + [&sock, addr, port] { - // spam this message at max speed - std::string text("Spamorino Cappucino\n"); + // print this message once + printf("*** Starting spam (you should see this once)\n"); - sock.sendto(addr, port, text.data(), text.size(), - [next] { (*next)(); }); - }; - - // start spamming - (*next)(); - }); - }); - + typedef std::function rnd_gen_t; + auto next = std::make_shared (); + + *next = + [next, &sock, addr, port] () + { + // spam this message at max speed + std::string text("Spamorino Cappucino\n"); + + sock.sendto(addr, port, text.data(), text.size(), + [next] { (*next)(); }); + }; + + // start spamming + (*next)(); + }); + }); // sock on_read + + }); // on_config + printf("*** TEST SERVICE STARTED *** \n"); } diff --git a/src/net/dhcp/dh4client.cpp b/src/net/dhcp/dh4client.cpp index b26b2da91e..721c8f2904 100644 --- a/src/net/dhcp/dh4client.cpp +++ b/src/net/dhcp/dh4client.cpp @@ -159,7 +159,7 @@ namespace net : stack(inet) { config_handler = - [] (Stack&, bool timeout) { + [] (bool timeout) { if (timeout) INFO("DHCPv4","Negotiation timed out"); else @@ -175,7 +175,7 @@ namespace net // reset session ID this->xid = 0; // call on_config with timeout = true - this->config_handler(stack, true); + this->config_handler(true); }); // create a random session ID @@ -244,13 +244,13 @@ namespace net [this, &socket] (IP4::addr, UDP::port_t port, const char* data, size_t len) { - if (port == DHCP_DEST_PORT) - { - // we have got a DHCP Offer - debug("Received possible DHCP OFFER from %s:%d\n", - addr.str().c_str(), DHCP_DEST_PORT); - this->offer(socket, data, len); - } + if (port == DHCP_DEST_PORT) + { + // we have got a DHCP Offer + debug("Received possible DHCP OFFER from %s:%d\n", + addr.str().c_str(), DHCP_DEST_PORT); + this->offer(socket, data, len); + } }); } @@ -414,18 +414,18 @@ namespace net // set our onRead function to point to a hopeful DHCP ACK! sock.on_read( - [this] (IP4::addr, UDP::port_t port, - const char* data, size_t len) - { - if (port == DHCP_DEST_PORT) - { - // we have hopefully got a DHCP Ack - debug("\tReceived DHCP ACK from %s:%d\n", - addr.str().c_str(), DHCP_DEST_PORT); - this->acknowledge(data, len); - } - }); - + [this] (IP4::addr, UDP::port_t port, + const char* data, size_t len) + { + if (port == DHCP_DEST_PORT) + { + // we have hopefully got a DHCP Ack + debug("\tReceived DHCP ACK from %s:%d\n", + addr.str().c_str(), DHCP_DEST_PORT); + this->acknowledge(data, len); + } + }); + // send our DHCP Request sock.bcast(IP4::INADDR_ANY, DHCP_DEST_PORT, packet, packetlen); } @@ -443,14 +443,13 @@ namespace net opt = get_option(dhcp->options, DHO_DHCP_MESSAGE_TYPE); if (opt->code == DHO_DHCP_MESSAGE_TYPE) - { - // verify that the type is indeed DHCPOFFER - debug("\tFound DHCP message type %d (DHCP Ack = %d)\n", - opt->val[0], DHCPACK); - - // ignore when not a DHCP Offer - if (opt->val[0] != DHCPACK) return; - } + { + // verify that the type is indeed DHCPOFFER + debug("\tFound DHCP message type %d (DHCP Ack = %d)\n", + opt->val[0], DHCPACK); + // ignore when not a DHCP Offer + if (opt->val[0] != DHCPACK) return; + } // ignore message when DHCP message type is missing else return; @@ -461,6 +460,6 @@ namespace net // stop timeout from happening hw::PIT::stop(timeout); // run some post-DHCP event to release the hounds - this->config_handler(stack, false); + this->config_handler(false); } } From eaaba2fb37a502c0b0ee501095a044656ad88e39 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Thu, 14 Apr 2016 13:02:10 +0200 Subject: [PATCH 153/311] dhcp: Silence output --- api/net/dhcp/dh4client.hpp | 5 ++ src/debug/test_service.cpp | 22 +++++--- src/net/dhcp/dh4client.cpp | 112 ++++++++++++++++++++----------------- 3 files changed, 79 insertions(+), 60 deletions(-) diff --git a/api/net/dhcp/dh4client.hpp b/api/net/dhcp/dh4client.hpp index d1eaecadeb..b9f341ab8b 100644 --- a/api/net/dhcp/dh4client.hpp +++ b/api/net/dhcp/dh4client.hpp @@ -47,6 +47,10 @@ namespace net void on_config(config_func handler) { config_handler = handler; } + // disable or enable console spam + void set_silent(bool sil) + { this->console_spam = !sil; } + private: void offer(UDPSocket&, const char* data, size_t len); void request(UDPSocket&); // --> acknowledge @@ -58,6 +62,7 @@ namespace net uint32_t lease_time; config_func config_handler; hw::PIT::Timer_iterator timeout; + bool console_spam; }; } diff --git a/src/debug/test_service.cpp b/src/debug/test_service.cpp index 7a1055ea6a..28d632c938 100644 --- a/src/debug/test_service.cpp +++ b/src/debug/test_service.cpp @@ -36,11 +36,11 @@ void Service::start() {{ 8,8,8,8 }} ); // DNS /* - auto& tcp = inet->tcp(); - auto& server = tcp.bind(6667); // IRCd default port - server.onConnect( - [] (auto csock) - { + auto& tcp = inet->tcp(); + auto& server = tcp.bind(6667); // IRCd default port + server.onConnect( + [] (auto csock) + { printf("*** Received connection from %s\n", csock->remote().to_string().c_str()); @@ -69,13 +69,19 @@ void Service::start() /// inform others about disconnect //client.bcast(TK_QUIT, "Disconnected"); }); - });*/ - + });*/ + + inet->dhclient()->set_silent(true); inet->on_config( [] (bool timeout) { - printf("Inet::on_config(%d)\n", timeout); + if (timeout) + printf("Inet::on_config: Timeout\n"); + else + printf("Inet::on_config: DHCP Server acknowledged our request!\n"); + printf("Service IP address: %s, router: %s\n", + inet->ip_addr().str().c_str(), inet->router().str().c_str()); using namespace net; const UDP::port_t port = 4242; diff --git a/src/net/dhcp/dh4client.cpp b/src/net/dhcp/dh4client.cpp index 721c8f2904..d430f6e000 100644 --- a/src/net/dhcp/dh4client.cpp +++ b/src/net/dhcp/dh4client.cpp @@ -156,14 +156,17 @@ namespace net } DHClient::DHClient(Stack& inet) - : stack(inet) + : stack(inet), xid(0), console_spam(true) { config_handler = - [] (bool timeout) { - if (timeout) - INFO("DHCPv4","Negotiation timed out"); - else - INFO("DHCPv4","Config complete"); + [this] (bool timeout) { + if (console_spam) + { + if (timeout) + INFO("DHCPv4","Negotiation timed out"); + else + INFO("DHCPv4","Config complete"); + } }; } @@ -180,7 +183,8 @@ namespace net // create a random session ID this->xid = OS::cycles_since_boot() & 0xFFFFFFFF; - MYINFO("Negotiating IP-address (xid=%u)", xid); + if (console_spam) + MYINFO("Negotiating IP-address (xid=%u)", xid); // create DHCP discover packet const size_t packetlen = sizeof(dhcp_packet_t); @@ -278,70 +282,72 @@ namespace net opt = get_option(dhcp->options, DHO_DHCP_MESSAGE_TYPE); if (opt->code == DHO_DHCP_MESSAGE_TYPE) - { - // verify that the type is indeed DHCPOFFER - debug("Found DHCP message type %d (DHCP Offer = %d)\n", - opt->val[0], DHCPOFFER); - - // ignore when not a DHCP Offer - if (opt->val[0] != DHCPOFFER) return; - } + { + // verify that the type is indeed DHCPOFFER + debug("Found DHCP message type %d (DHCP Offer = %d)\n", + opt->val[0], DHCPOFFER); + + // ignore when not a DHCP Offer + if (opt->val[0] != DHCPOFFER) return; + } // ignore message when DHCP message type is missing else return; // the offered IP address: this->ipaddr = dhcp->yiaddr; - MYINFO("IP ADDRESS: \t%s", - this->ipaddr.str().c_str()); - + if (console_spam) + MYINFO("IP ADDRESS: \t%s", this->ipaddr.str().c_str()); + opt = get_option(dhcp->options, DHO_SUBNET_MASK); if (opt->code == DHO_SUBNET_MASK) - { - memcpy(&this->netmask, opt->val, sizeof(IP4::addr)); - MYINFO("SUBNET MASK: \t%s", - this->netmask.str().c_str()); - } - + { + memcpy(&this->netmask, opt->val, sizeof(IP4::addr)); + if (console_spam) + MYINFO("SUBNET MASK: \t%s", this->netmask.str().c_str()); + } + opt = get_option(dhcp->options, DHO_DHCP_LEASE_TIME); if (opt->code == DHO_DHCP_LEASE_TIME) - { - memcpy(&this->lease_time, opt->val, sizeof(this->lease_time)); + { + memcpy(&this->lease_time, opt->val, sizeof(this->lease_time)); + if (console_spam) MYINFO("LEASE TIME: \t%u mins", this->lease_time / 60); - } - + } + // now validate the offer, checking for minimum information opt = get_option(dhcp->options, DHO_ROUTERS); if (opt->code == DHO_ROUTERS) - { - memcpy(&this->router, opt->val, sizeof(IP4::addr)); - MYINFO("GATEWAY: \t%s", - this->router.str().c_str()); - } + { + memcpy(&this->router, opt->val, sizeof(IP4::addr)); + if (console_spam) + MYINFO("GATEWAY: \t%s", this->router.str().c_str()); + } // assume that the server we received the request from is the gateway else + { + opt = get_option(dhcp->options, DHO_DHCP_SERVER_IDENTIFIER); + if (opt->code == DHO_DHCP_SERVER_IDENTIFIER) { - opt = get_option(dhcp->options, DHO_DHCP_SERVER_IDENTIFIER); - if (opt->code == DHO_DHCP_SERVER_IDENTIFIER) - { - memcpy(&this->router, opt->val, sizeof(IP4::addr)); - MYINFO("GATEWAY: \t%s", - this->router.str().c_str()); - } - // silently ignore when both ROUTER and SERVER_ID is missing - else return; + memcpy(&this->router, opt->val, sizeof(IP4::addr)); + if (console_spam) + MYINFO("GATEWAY: \t%s", this->router.str().c_str()); } - + // silently ignore when both ROUTER and SERVER_ID is missing + else return; + } + opt = get_option(dhcp->options, DHO_DOMAIN_NAME_SERVERS); if (opt->code == DHO_DOMAIN_NAME_SERVERS) - { - memcpy(&this->dns_server, opt->val, sizeof(IP4::addr)); - } + { + memcpy(&this->dns_server, opt->val, sizeof(IP4::addr)); + } else - { // just try using ROUTER as DNS server - this->dns_server = this->router; - } - MYINFO("DNS SERVER: \t%s", this->dns_server.str().c_str()); - + { // just try using ROUTER as DNS server + this->dns_server = this->router; + } + if (console_spam) + MYINFO("DNS SERVER: \t%s", this->dns_server.str().c_str()); + // we can accept the offer now by requesting the IP! this->request(sock); } @@ -453,8 +459,10 @@ namespace net // ignore message when DHCP message type is missing else return; + if (console_spam) + MYINFO("Server acknowledged our request!"); + // configure our network stack - MYINFO("Server acknowledged our request!"); stack.network_config(this->ipaddr, this->netmask, this->router, this->dns_server); // stop timeout from happening From de724b546fa01e77b18f299a8edbe45e91dc5feb Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Thu, 14 Apr 2016 14:12:32 +0200 Subject: [PATCH 154/311] virtio: Update to use new vring --- api/virtio/block.hpp | 2 +- src/Makefile | 3 ++- src/virtio/block.cpp | 23 ++++++++++++++++------- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/api/virtio/block.hpp b/api/virtio/block.hpp index 048a3ce460..aca86ae3ff 100644 --- a/api/virtio/block.hpp +++ b/api/virtio/block.hpp @@ -79,7 +79,7 @@ class VirtioBlk : public Virtio, public hw::IDiskDevice uint8_t alignment_offset; // Alignment offset in logical blocks uint16_t min_io_size; // Minimum I/O size without performance penalty in logical blocks uint32_t opt_io_size; // Optimal sustained I/O size in logical blocks - } __attribute__((packed)); + }; struct scsi_header_t { diff --git a/src/Makefile b/src/Makefile index 44f44aaa53..d8d8cc26ba 100644 --- a/src/Makefile +++ b/src/Makefile @@ -73,7 +73,8 @@ OS_OBJECTS = kernel/kernel_start.o kernel/syscalls.o kernel/vga.o \ net/ip6/ip6.o net/ip6/icmp6.o net/ip6/udp6.o net/ip6/ndp.o \ net/packet.o net/buffer_store.o \ fs/disk.o fs/filesystem.o fs/mbr.o fs/vbr.o fs/path.o \ - fs/ext4.o fs/fat.o fs/fat_async.o fs/fat_sync.o fs/memdisk.o # virtio/console.o virtio/block.o\ + fs/ext4.o fs/fat.o fs/fat_async.o fs/fat_sync.o fs/memdisk.o \ + virtio/block.o # virtio/console.o CRTI_OBJ = crt/crti.o CRTN_OBJ = crt/crtn.o diff --git a/src/virtio/block.cpp b/src/virtio/block.cpp index fa3f5fbdf7..59004520d1 100644 --- a/src/virtio/block.cpp +++ b/src/virtio/block.cpp @@ -132,10 +132,10 @@ void VirtioBlk::service_RX() uint32_t len; request_t* hdr; - while ((hdr = (request_t*) req.dequeue(len)) != nullptr) + while ((hdr = (request_t*) req.dequeue(&len)) != nullptr) { - printf("service_RX() received %u bytes for sector %llu\n", - len, hdr->hdr.sector); + //&printf("service_RX() received %u bytes for sector %llu\n", + // len, hdr->hdr.sector); // blk_resp_t* resp = &hdr->resp; printf("blk response: %u\n", resp->status); @@ -167,14 +167,23 @@ void VirtioBlk::read (block_t blk, on_read_func func) vbr->hdr.ioprio = 0; vbr->hdr.sector = blk; vbr->io.handler = func; - vbr->resp.status = VIRTIO_BLK_S_IOERR; + vbr->resp.status = VIRTIO_BLK_S_IOERR; printf("Enqueue handler: %p, total: %u\n", &vbr->io.handler, sizeof(request_t)); // - req.enqueue(&vbr->hdr, sizeof(scsi_header_t), 1, false); // out - req.enqueue(&vbr->io, sizeof(blk_io_t), 0, false); // in - req.enqueue(&vbr->resp, sizeof(blk_resp_t), 0, true); // in, last + std::array tout; + std::array tin; + + tout[0].data = (uint8_t*) &vbr->hdr; + tout[0].size = sizeof(scsi_header_t); + tin[0].data = (uint8_t*) &vbr->io; + tin[0].size = sizeof(blk_io_t); + tin[1].data = (uint8_t*) &vbr->resp; + tin[1].size = sizeof(blk_resp_t); + + req.enqueue(tout, Virtio::Queue::Direction::OUT); + req.enqueue(tin, Virtio::Queue::Direction::IN); req.kick(); } From 7c23ab1c88f74d3e34bbae7c59abcd4ceed0b77a Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Thu, 14 Apr 2016 14:37:11 +0200 Subject: [PATCH 155/311] Added support for exporting secondary hard-drive option --- etc/qemu_cmd.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/etc/qemu_cmd.sh b/etc/qemu_cmd.sh index 27cc16766e..059677b4bb 100755 --- a/etc/qemu_cmd.sh +++ b/etc/qemu_cmd.sh @@ -18,7 +18,9 @@ export qemu_ifup="$INCLUDEOS_HOME/etc/qemu-ifup" [ ! -v GRAPHICS ] && export GRAPHICS="-nographic" [ ! -v SERIAL ] && export SERIAL="-virtioconsole stdio" [ ! -v MEM ] && export MEM="-m 128" -[ ! -v HDD ] && export HDD="-drive file=$IMAGE,format=raw,if=ide" +[ ! -v HDA ] && export HDA="-drive file=$IMAGE,format=raw,if=ide" +[ ! -v HDB ] && export HDB="" +[ ! -v HDD ] && export HDD="$HDA $HDB" [ ! -v CPU ] && export CPU="" export QEMU_OPTS="$HDD $NET $GRAPHICS $SMP $MEM $CPU" From 5d23b6c9088e540de880494944d0e6baf8031d45 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Fri, 15 Apr 2016 00:35:30 +0200 Subject: [PATCH 156/311] Added simple validation tool / schema for (future) test folders --- test/UDP/vm.json | 6 +++++ test/validate_all.sh | 2 ++ test/validate_test.py | 44 +++++++++++++++++++++++++++++++++++ test/vm.schema.json | 54 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 106 insertions(+) create mode 100644 test/UDP/vm.json create mode 100755 test/validate_all.sh create mode 100755 test/validate_test.py create mode 100644 test/vm.schema.json diff --git a/test/UDP/vm.json b/test/UDP/vm.json new file mode 100644 index 0000000000..479c6b5ec0 --- /dev/null +++ b/test/UDP/vm.json @@ -0,0 +1,6 @@ +{ + "image" : "test_UDP.img", + "drives" : [{"file":"test.txt", "type" :"virtio"}], + "cpu" : "host", + "mem" : 256 +} diff --git a/test/validate_all.sh b/test/validate_all.sh new file mode 100755 index 0000000000..ea772bf748 --- /dev/null +++ b/test/validate_all.sh @@ -0,0 +1,2 @@ +#! /bin/bash +for t in `ls -d */`; do ./validate_test.py $t; done diff --git a/test/validate_test.py b/test/validate_test.py new file mode 100755 index 0000000000..81495c218a --- /dev/null +++ b/test/validate_test.py @@ -0,0 +1,44 @@ +#! /usr/bin/python +import jsonschema +import json +import sys +import os +import glob + +vm_schema = json.loads(open("vm.schema.json").read()); + +def validate_vm_spec(filename): + # Load and parse as JSON + try: + vm_spec = json.loads(open(filename).read()) + except: + raise Exception("JSON load / parse Error for " + filename) + + # Validate JSON according to schema + try: + jsonschema.validate(vm_spec, vm_schema) + except Exception as err: + raise Exception("JSON schema validation failed: " + err.message) + + +def has_required_stuff(path): + + # Certain files are mandatory + required_files = [ "Makefile", "test.py", "README.md", "*.cpp" ] + for file in required_files: + if not glob.glob(file): + raise Exception("missing " + file) + + # JSON-files must conform to VM-schema + for json in glob.glob("*.json"): + validate_vm_spec(json) + + +path = sys.argv[1] if len(sys.argv) > 1 else "." +os.chdir(path) + +try: + has_required_stuff(path) + print "\tPASS: ",os.getcwd() +except Exception as err: + print "\tFAIL: unmet requirements in " + path, ": " , err.message diff --git a/test/vm.schema.json b/test/vm.schema.json new file mode 100644 index 0000000000..befb9952ba --- /dev/null +++ b/test/vm.schema.json @@ -0,0 +1,54 @@ +{ + "$schema": "http://json-schema.org/schema#", + "title" : "Virtual Machine Image", + "type" : "object", + "properties" : { + + "image" : { + + "description" : "A bootable virtual machine image", + "type" : "string", + "default" : "service.img" + }, + + "drives" : { + + "description" : "Additional virtual hard drives", + "type" : "array", + "items" : { + "type" : "object", + "properties" : { + "file" : { "type" : "string" }, + "type" : { "enum" : ["ide", "virtio"] }, + "name" : { "type" : "string" } + }, + + "required" : ["file"] + } + }, + + + "mem" : { + + "description" : "Amount of memory in megabytes", + "type" : "number", + "default" : 128 + }, + + "cpu" : { + + "description" : "The virtual CPU", + "enum" : ["host", "pentium"] + }, + + + "smp" : { + + "description" : "Number of virtual CPU's", + "type" : "number" + } + + }, + + "required" : ["image"] +} From ec228b0d9072f14d59aa3e499b781d7fbd6e0d07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Fri, 15 Apr 2016 14:56:02 +0200 Subject: [PATCH 157/311] tcp: extended work on Retransmission and Congestion Control (Reno) --- api/net/tcp.hpp | 237 +++++++++++++++++++++++------- src/net/tcp.cpp | 4 +- src/net/tcp_connection.cpp | 207 ++++++++++++++++++++------ src/net/tcp_connection_states.cpp | 129 +++++++++++----- 4 files changed, 439 insertions(+), 138 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index a9af1eb2b0..78a1d496a9 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -363,6 +363,8 @@ namespace net { inline bool isset(TCP::Flag f) { return ntohs(header().offset_flags.whole) & f; } + //TCP::Flag flags() const { return (htons(header().offset_flags.whole) << 8) & 0xFF; } + /// OFFSET, OPTIONS, DATA /// @@ -431,6 +433,10 @@ namespace net { return total; } + bool is_acked_by(const Seq ack) const { + return ack >= (seq() + data_length()); + } + inline std::string to_string() { std::ostringstream os; os << "[ S:" << source().to_string() << " D:" << destination().to_string() @@ -662,9 +668,9 @@ namespace net { class State { public: enum Result { - CLOSED = -1, - OK = 0, - CLOSE = 1 + CLOSED = -1, // This inditactes that a Connection is done and should be closed. + OK = 0, // Does nothing + CLOSE = 1 // This indicates that the CLIENT (peer) has/wants to close their end. }; /* Open a Connection. @@ -779,6 +785,7 @@ namespace net { uint16_t MSS; // Maximum segment size for outgoing segments. uint32_t cwnd; // Congestion window [RFC 5681] + Seq recover; // New Reno [RFC 6582] } SND; // << TCP::Seq ISS; // initial send sequence number @@ -795,7 +802,7 @@ namespace net { uint32_t ssthresh; // slow start threshold [RFC 5681] TCB() { - SND = { 0, 0, TCP::default_window_size, 0, 0, 0, TCP::default_mss, 0 }; + SND = { 0, 0, TCP::default_window_size, 0, 0, 0, TCP::default_mss, 0, 0 }; ISS = 0; RCV = { 0, TCP::default_window_size, 0, 0 }; IRS = 0; @@ -1106,10 +1113,22 @@ namespace net { */ bool queued_; + /* + Retransmission queue + */ + std::deque retransq; + struct { - TCP::Seq ACK = 0; - size_t count = 0; - } dup_acks_; + hw::PIT::Timer_iterator iter; + bool active = false; + size_t i = 0; + } rt_timer; + + + /* + Keep track of duplicate ACK + */ + size_t DUP_ACK = 0; /* Bytes queued for transmission. @@ -1122,20 +1141,22 @@ namespace net { uint64_t time_wait_started; + // [RFC 6298] - struct RoundTripCalc { + // Round Trip Time Measurer + struct RTTM { using timestamp_t = double; using duration_t = double; // clock granularity - static constexpr duration_t CLOCK_G = hw::PIT::frequency().count(); + //static constexpr duration_t CLOCK_G = hw::PIT::frequency().count() / 1000; + static constexpr duration_t CLOCK_G = 0.0011; static constexpr double K = 4.0; static constexpr double alpha = 1.0/8; static constexpr double beta = 1.0/4; - TCP::Seq SEQ; // current sequence number measured timestamp_t t; // tick when measure is started duration_t SRTT; // smoothed round-trip time @@ -1144,16 +1165,25 @@ namespace net { bool active = false; - void start(Seq seq) { - SEQ = seq; + RTTM() : t(OS::uptime()), RTO(1.0), active(false) {} + + void start() { t = OS::uptime(); active = true; } - void stop() { + void stop(bool first = false) { + assert(active); active = false; // round trip time (RTT) - sub_rtt_measurement(OS::uptime() - t); + auto rtt = OS::uptime() - t; + debug2(" RTT: %ums\n", + (uint32_t)(rtt * 1000)); + if(!first) + sub_rtt_measurement(rtt); + else { + first_rtt_measurement(rtt); + } } /* @@ -1165,7 +1195,7 @@ namespace net { where K = 4. */ - void first_rtt_measurement(duration_t R) { + inline void first_rtt_measurement(duration_t R) { SRTT = R; RTTVAR = R/2; update_rto(); @@ -1188,16 +1218,19 @@ namespace net { After the computation, a host MUST update RTO <- SRTT + max (G, K*RTTVAR) */ - void sub_rtt_measurement(duration_t R) { + inline void sub_rtt_measurement(duration_t R) { RTTVAR = (1 - beta) * RTTVAR + beta * std::abs(SRTT-R); SRTT = (1 - alpha) * SRTT + alpha * R; + update_rto(); } - void update_rto() { + inline void update_rto() { RTO = std::max(SRTT + std::max(CLOCK_G, K * RTTVAR), 1.0); + debug2(" RTO updated: %ums\n", + (uint32_t)(RTO * 1000)); } - } round_trip; + } rttm; /// CALLBACK HANDLING /// @@ -1301,7 +1334,7 @@ namespace net { Returns if the connection has a doable write job. */ inline bool has_doable_job() { - return !write_queue.empty() and usable_window() >= MSDS(); + return !write_queue.empty() and usable_window() >= SMSS(); } /* @@ -1363,41 +1396,101 @@ namespace net { inline Connection::TCB& tcb() { return control_block; } inline int32_t usable_window() const { - auto x = (int64_t)control_block.SND.UNA + (int64_t)control_block.SND.WND - (int64_t)control_block.SND.NXT; - return std::min((int32_t) x, (int32_t)control_block.SND.cwnd); + auto x = (int64_t)congestion_window() - (int64_t)control_block.SND.NXT; + return (int32_t) x; } - /// Congestion Control [RFC 5681] /// + /* - inline uint16_t SMSS() const { - return host_.MSS(); + Note: + Made a function due to future use when Window Scaling Option is added. + */ + inline int32_t send_window() const { + return (int32_t)control_block.SND.WND; } - inline uint16_t RMSS() const { - return control_block.SND.MSS; + inline int32_t congestion_window() const { + auto win = control_block.SND.UNA + std::min((int32_t)control_block.SND.cwnd, send_window()); + return win; } - inline int32_t flight_size() const { - return control_block.SND.NXT - control_block.SND.UNA; + /* + Acknowledge a packet + - TCB update, Congestion control handling, RTT calculation and RT handling. + */ + void acknowledge(Seq ACK); + + /// Congestion Control [RFC 5681] /// + + inline void setup_congestion_control() + { reno_init(); } + + inline uint16_t SMSS() const + { return host_.MSS(); } + + inline uint16_t RMSS() const + { return control_block.SND.MSS; } + + inline int32_t flight_size() const + { return control_block.SND.NXT - control_block.SND.UNA; } + + /// Reno /// + + inline void reno_init() { + reno_init_cwnd(3); + reno_init_sshtresh(); } - inline void init_cwnd(uint32_t segments) { + inline void reno_init_cwnd(size_t segments) + { control_block.SND.cwnd = segments*SMSS(); + printf(" Cwnd initilized: %u\n", control_block.SND.cwnd); } - inline void reduce_slow_start_threshold() { + inline void reno_init_sshtresh() + { control_block.ssthresh = control_block.SND.WND; } + + inline bool reno_slow_start() const + { return control_block.SND.cwnd < control_block.ssthresh; } + + inline void reno_increase_cwnd(uint16_t n) + { control_block.SND.cwnd += std::min(n, SMSS()); } + + inline void reno_reduce_ssthresh() { control_block.ssthresh = std::max( (flight_size() / 2), (2 * SMSS()) ); - debug2("TCP::Connection::reduce_slow_start_threshold> Slow start threshold reduced: %u\n", + printf(" Slow start threshold reduced: %u\n", control_block.ssthresh); } - inline void segment_loss_detected() { - reduce_slow_start_threshold(); + inline void reno_fast_retransmit() { + printf(" Fast retransmit initiated.\n"); + retransmit(); + control_block.SND.cwnd = control_block.ssthresh + (3 * SMSS()); } - /* - */ - size_t duplicate_ack(TCP::Seq ack); + inline void reno_loss_detected() { + reno_reduce_ssthresh(); + reno_fast_retransmit(); + } + + inline bool reno_is_dup_ack(TCP::Packet_ptr in) { + bool is_dup_ack = flight_size() > 0 + and !in->has_data() + and !in->isset(FIN) and !in->isset(SYN) + //and ((in->flags() & (FIN | SYN)) == 0) + and in->win() == control_block.SND.WND; + + return is_dup_ack; + } + + inline void reno_dup_ack() { + if(++DUP_ACK == 3) { + printf(" Duplicate ACK - Strike 3!\n"); + reno_loss_detected(); + } else if(DUP_ACK > 3) { + control_block.SND.cwnd += SMSS(); + } + } /* Generate a new ISS. @@ -1421,18 +1514,13 @@ namespace net { */ void transmit(TCP::Packet_ptr); - /* - Retransmit the packet. - */ - void retransmit(TCP::Packet_ptr); - /* Creates a new outgoing packet with the current TCB values and options. */ TCP::Packet_ptr create_outgoing_packet(); /* - */ + */ inline TCP::Packet_ptr outgoing_packet() { return create_outgoing_packet(); } @@ -1441,21 +1529,57 @@ namespace net { /// RETRANSMISSION /// /* - Starts a retransmission timer that retransmits the packet when RTO has passed. + Retransmit the first packet in retransmission queue. + */ + void retransmit(); + + /* + Start retransmission timer. + */ + void rt_start(); - // TODO: Calculate RTO, currently hardcoded to 1 second (1000ms). - */ - void queue_retransmission(TCP::Packet_ptr, size_t rt_attempt = 1); + /* + Stop retransmission timer. + */ + void rt_stop(); + + /* + Restart retransmission timer. + */ + inline void rt_restart() { + rt_stop(); + rt_start(); + } + + /* + Number of retransmission attempts on the packet first in RT-queue + */ + size_t rto_attempt = 0; + + /* + Remove all packets acknowledge by ACK in retransmission queue + */ + void rt_ack_queue(Seq ack); + + /* + Flush the queue (transmit every packet in queue) + */ + void rt_flush(); /* - Measure the elapsed time between sending a data octet with a - particular sequence number and receiving an acknowledgment that - covers that sequence number (segments sent do not have to match - segments received). This measured elapsed time is the Round Trip - Time (RTT). + Delete retransmission queue */ - //std::chrono::milliseconds RTT() const; - std::chrono::milliseconds RTO() const; + void rt_clear(); + + /* + When retransmission times out. + */ + inline void rt_timeout() { + if(rto_attempt++ == 0) + reno_reduce_ssthresh(); + retransmit(); + } + /* Start the time wait timeout for 2*MSL @@ -1576,7 +1700,12 @@ namespace net { /* Show all connections for TCP as a string. */ - std::string status() const; + std::string to_string() const; + + inline std::string status() const + { return to_string(); } + + private: diff --git a/src/net/tcp.cpp b/src/net/tcp.cpp index 609fac7e37..73a25e4f41 100644 --- a/src/net/tcp.cpp +++ b/src/net/tcp.cpp @@ -215,7 +215,7 @@ size_t TCP::send(Connection_ptr conn, Connection::WriteBuffer& buffer) { if(written < buffer.remaining and !conn->is_queued()) { write_queue.push(conn); conn->set_queued(true); - debug2(" %s wrote %u bytes (%u remaining) and is Re-queued.\n", + printf(" %s wrote %u bytes (%u remaining) and is Re-queued.\n", conn->to_string().c_str(), written, buffer.remaining-written); } @@ -230,7 +230,7 @@ size_t TCP::send(Connection_ptr conn, Connection::WriteBuffer& buffer) { TODO: Make sure Recv, Send, In, Out is correct and add them to output. Also, alignment? */ -string TCP::status() const { +string TCP::to_string() const { // Write all connections in a cute list. stringstream ss; ss << "LISTENING SOCKETS:\n"; diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index b8020b10bd..5dc6eb1ca3 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -25,6 +25,8 @@ using Connection = TCP::Connection; using namespace std; +const TCP::Connection::RTTM::duration_t TCP::Connection::RTTM::CLOCK_G; + /* This is most likely used in a ACTIVE open */ @@ -40,7 +42,7 @@ Connection::Connection(TCP& host, Port local_port, Socket remote) : queued_(false), time_wait_started(0) { - init_cwnd(3); + setup_congestion_control(); } /* @@ -141,12 +143,12 @@ bool Connection::offer(size_t& packets) { return !has_doable_job(); } - +// TODO: This is starting to get complex and ineffective, refactor.. size_t Connection::send(const char* buffer, size_t remaining, size_t& packet_count, bool PUSH) { assert(packet_count && remaining); size_t bytes_written{0}; - while(remaining and packet_count and usable_window() >= MSDS()) { + while(remaining and packet_count and usable_window() >= SMSS()) { // retreive a new packet auto packet = create_outgoing_packet(); // reduce the amount of packets available by one @@ -161,18 +163,20 @@ size_t Connection::send(const char* buffer, size_t remaining, size_t& packet_cou bytes_written += written; remaining -= written; - debug2(" Packet Limit: %u - Written: %u" - " - Remaining: %u - Packet count: %u, Window: %u\n", - packet_limit, written, remaining, packet_count, usable_window()); - // If last packet, add PUSH. - if(!remaining and PUSH) + // TODO: Redefine "push" + if((!remaining or !packet_count or usable_window() < SMSS()) and PUSH) + //if(!remaining and PUSH) packet->set_flag(PSH); // Advance outgoing sequence number (SND.NXT) with the length of the data. control_block.SND.NXT += packet->data_length(); // TODO: Replace with chaining transmit(packet); + + debug2(" Packet Limit: %u - Written: %u" + " - Remaining: %u - Packet count: %u, Window: %u\n", + packet_limit, written, remaining, packet_count, usable_window()); } debug(" Sent %u bytes of data\n", bytes_written); return bytes_written; @@ -251,6 +255,7 @@ void Connection::segment_arrived(TCP::Packet_ptr incoming) { } case State::CLOSED: { debug(" State handle finished with CLOSED. We're done, ask host() to delete the connection. \n"); + rt_clear(); signal_close(); break; }; @@ -294,55 +299,163 @@ TCP::Packet_ptr Connection::create_outgoing_packet() { void Connection::transmit(TCP::Packet_ptr packet) { debug(" Transmitting: %s \n", packet->to_string().c_str()); - host_.transmit(packet); - // Don't think we would like to retransmit reset packets..? - //if(!packet->isset(RST)) - // queue_retransmission(packet); -} + if(!rttm.active) { + //printf(" Starting RTT measurement.\n"); + rttm.start(); + } -void Connection::retransmit(TCP::Packet_ptr packet) { - debug(" Retransmitting: %s \n", packet->to_string().c_str()); host_.transmit(packet); + if(packet->has_data()) + retransq.push_back(packet); + if(!rt_timer.active) + rt_start(); } -void Connection::queue_retransmission(TCP::Packet_ptr packet, size_t rt_attempt) { - const size_t ATTEMPT_LIMIT = 3; - auto self = shared_from_this(); - - if(rt_attempt <= ATTEMPT_LIMIT) { - hw::PIT::instance().onTimeout(RTO() * rt_attempt, - [packet, self, rt_attempt] - { - // Packet hasnt been ACKed. - if(packet->seq() > self->tcb().SND.UNA) { - debug(" Packet unacknowledge, retransmitting...\n"); - if(rt_attempt == 1) - self->segment_loss_detected(); - //packet->set_ack(self->tcb().RCV.NXT); - self->retransmit(packet); - self->queue_retransmission(packet, rt_attempt+1); - } else { - debug2(" Packet acknowledged %s \n", packet->to_string().c_str()); - // Signal user? - } - }); + +/* + As specified in [RFC3390], the SYN/ACK and the acknowledgment of the + SYN/ACK MUST NOT increase the size of the congestion window. + Further, if the SYN or SYN/ACK is lost, the initial window used by a + sender after a correctly transmitted SYN MUST be one segment + consisting of at most SMSS bytes. +*/ +void Connection::acknowledge(Seq ACK) { + DUP_ACK = 0; + size_t bytes_acked = ACK - control_block.SND.UNA; + control_block.SND.UNA = ACK; + + if(reno_slow_start()) { + reno_increase_cwnd(bytes_acked); + debug2(" Slow start - cwnd increased: %u\n", + control_block.SND.cwnd); } + // congestion avoidance else { - printf(" Give up already... Already tried %u times. Time to kill connection?\n", - ATTEMPT_LIMIT); + if(rttm.active) { + reno_increase_cwnd(bytes_acked); + debug2(" Congestion avoidance - cwnd increased: %u\n", + control_block.SND.cwnd); + } + } + + if(rttm.active) + rttm.stop(); + + rt_ack_queue(ACK); +} + +/* + [RFC 6298] + + (5.2) When all outstanding data has been acknowledged, turn off the + retransmission timer. + + (5.3) When an ACK is received that acknowledges new data, restart the + retransmission timer so that it will expire after RTO seconds + (for the current value of RTO). +*/ +void Connection::rt_ack_queue(Seq ack) { + auto x = retransq.size(); + while(!retransq.empty()) { + if(retransq.front()->is_acked_by(ack)) + retransq.pop_front(); + else + break; + } + /* + When all outstanding data has been acknowledged, turn off the + retransmission timer. + */ + if(retransq.empty() and rt_timer.active) { + rt_stop(); + } + /* + When an ACK is received that acknowledges new data, restart the + retransmission timer so that it will expire after RTO seconds + (for the current value of RTO). + */ + else if(x - retransq.size() > 0) { + rto_attempt = 0; + rt_restart(); + } + //printf(" ACK'ed %u packets. Retransq: %u\n", + // x-retransq.size(), retransq.size()); +} + +/* + When the retransmission timer expires, do the following: + + (5.4) Retransmit the earliest segment that has not been acknowledged + by the TCP receiver. + + (5.5) The host MUST set RTO <- RTO * 2 ("back off the timer"). The + maximum value discussed in (2.5) above may be used to provide + an upper bound to this doubling operation. + + (5.6) Start the retransmission timer, such that it expires after RTO + seconds (for the value of RTO after the doubling operation + outlined in 5.5). + + (5.7) If the timer expires awaiting the ACK of a SYN segment and the + TCP implementation is using an RTO less than 3 seconds, the RTO + MUST be re-initialized to 3 seconds when data transmission + begins (i.e., after the three-way handshake completes). +*/ +void Connection::retransmit() { + if(retransq.empty()) + return; + auto packet = retransq.front(); + printf(" Retransmitting: %s \n", packet->to_string().c_str()); + host_.transmit(packet); + /* + Every time a packet containing data is sent (including a + retransmission), if the timer is not running, start it running + so that it will expire after RTO seconds (for the current value + of RTO). + */ + if(!packet->isset(SYN)) { + rttm.RTO *= 2; + } else { + rttm.RTO = 3.0; } - debug2(" Packet queued for retransmission [%u] \n", retransmit_try); + if(!rt_timer.active) + rt_start(); + else + rt_restart(); } -size_t Connection::duplicate_ack(TCP::Seq ack) { - // if its another duplicate, increment count - if(dup_acks_.ACK == ack) - return ++dup_acks_.count; +void Connection::rt_start() { + assert(!rt_timer.active); + auto i = rt_timer.i; + rt_timer.iter = hw::PIT::instance().on_timeout(rttm.RTO, + [this, i] + { + rt_timer.active = false; + printf(" %s Timed out. rt_q: %u, i: %u rt_i: %u\n", + to_string().c_str(), retransq.size(), i, rt_timer.i); + rt_timeout(); + }); + rt_timer.i++; + rt_timer.active = true; +} + +void Connection::rt_stop() { + assert(rt_timer.active); + hw::PIT::instance().stop_timer(rt_timer.iter); + rt_timer.active = false; +} + +void Connection::rt_flush() { + while(!retransq.empty()) { + host_.transmit(retransq.front()); + retransq.pop_front(); + } +} - // if not, set the new ack and set count to 1 - dup_acks_.ACK = ack; - dup_acks_.count = 1; - return dup_acks_.count; +void Connection::rt_clear() { + if(rt_timer.active) + rt_stop(); + retransq.clear(); } TCP::Seq Connection::generate_iss() { diff --git a/src/net/tcp_connection_states.cpp b/src/net/tcp_connection_states.cpp index 074b0af77e..2037a24351 100644 --- a/src/net/tcp_connection_states.cpp +++ b/src/net/tcp_connection_states.cpp @@ -212,24 +212,68 @@ bool Connection::State::check_ack(Connection& tcp, TCP::Packet_ptr in) { drop the segment, and return. */ // Correction: [RFC 1122 p. 94] - if( tcb.SND.UNA < in->ack() and in->ack() <= tcb.SND.NXT ) { - tcb.SND.UNA = in->ack(); + // ACK is inside sequence space + if(in->ack() <= tcb.SND.NXT ) { + // this is a "new" ACK + if(tcb.SND.UNA <= in->ack()) { + /* + If SND.UNA =< SEG.ACK =< SND.NXT, the send window should be + updated. If (SND.WL1 < SEG.SEQ or (SND.WL1 = SEG.SEQ and + SND.WL2 =< SEG.ACK)), set SND.WND <- SEG.WND, set + SND.WL1 <- SEG.SEQ, and set SND.WL2 <- SEG.ACK. + */ + if( tcb.SND.WL1 < in->seq() or ( tcb.SND.WL1 = in->seq() and tcb.SND.WL2 <= in->ack() ) ) { + tcb.SND.WND = in->win(); + tcb.SND.WL1 = in->seq(); + tcb.SND.WL2 = in->ack(); + debug2(" Send window updated: %u \n", tcb.SND.WND); + } + + // this is a NEW ACK + if(tcb.SND.UNA < in->ack()) + { + tcp.acknowledge(in->ack()); + } + // [RFC 5681] + /* + DUPLICATE ACKNOWLEDGMENT: + An acknowledgment is considered a + "duplicate" in the following algorithms when + (a) the receiver of the ACK has outstanding data + (b) the incoming acknowledgment carries no data + (c) the SYN and FIN bits are both off + (d) the acknowledgment number is equal to the greatest acknowledgment + received on the given connection (TCP.UNA from [RFC793]) and + (e) the advertised window in the incoming acknowledgment equals the + advertised window in the last incoming acknowledgment. + + Note that a sender using SACK [RFC2018] MUST NOT send + new data unless the incoming duplicate acknowledgment contains + new SACK information. + */ + // this is a RFC 5681 DUP ACK + //!in->isset(FIN) and !in->isset(SYN) + else if(tcp.reno_is_dup_ack(in)) { + debug2(" Reno Dup ACK %u\n", in->ack()); + tcp.reno_dup_ack(); + } + // this is an RFC 793 DUP ACK + else { + //printf(" RFC 793 Dup ACK %u\n", in->ack()); + } + + + } + // this is an ACK out of order + else { + + } + debug2(" Usable window slided (%i) %u\n", tcp.usable_window(), tcb.SND.cwnd); // tcp.signal_sent(); // return that buffer has been SENT - currently no support to receipt sent buffer. - /* - If SND.UNA < SEG.ACK =< SND.NXT, the send window should be - updated. If (SND.WL1 < SEG.SEQ or (SND.WL1 = SEG.SEQ and - SND.WL2 =< SEG.ACK)), set SND.WND <- SEG.WND, set - SND.WL1 <- SEG.SEQ, and set SND.WL2 <- SEG.ACK. - */ - if( tcb.SND.WL1 < in->seq() or ( tcb.SND.WL1 = in->seq() and tcb.SND.WL2 <= in->ack() ) ) { - tcb.SND.WND = in->win(); - tcb.SND.WL1 = in->seq(); - tcb.SND.WL2 = in->ack(); - debug2(" Send window updated: %u \n", tcb.SND.WND); - } + /* Note that SND.WND is an offset from SND.UNA, that SND.WL1 records the sequence number of the last segment used to update @@ -237,27 +281,10 @@ bool Connection::State::check_ack(Connection& tcp, TCP::Packet_ptr in) { the last segment used to update SND.WND. The check here prevents using old segments to update the window. */ - } - /* If the ACK is a duplicate (SEG.ACK < SND.UNA), it can be ignored. */ - // Correction: [RFC 1122 p. 94] - else if( in->ack() <= tcb.SND.UNA ) { - debug2(" Dup ACK.\n"); - // [RFC 5681] - /* - Note that a sender using SACK [RFC2018] MUST NOT send - new data unless the incoming duplicate acknowledgment contains - new SACK information. - */ - auto dup_count = tcp.duplicate_ack(in->ack()); - if(dup_count == 3) { - debug(" Duplicate ACK strike! (>= 3)\n"); - tcp.reduce_slow_start_threshold(); - } else if(dup_count > 3) { - tcb.SND.cwnd += tcp.SMSS(); - } + } /* If the ACK acks something not yet sent (SEG.ACK > SND.NXT) then send an ACK, drop the segment, and return. */ - else if( in->ack() > tcb.SND.NXT ) { + else { auto packet = tcp.outgoing_packet(); packet->set_flag(ACK); tcp.transmit(packet); @@ -420,6 +447,8 @@ void Connection::State::send_reset(Connection& tcp) { tcp.write_queue_reset(); auto packet = tcp.outgoing_packet(); packet->set_seq(tcp.tcb().SND.NXT).set_ack(0).set_flag(RST); + // flush retransmission queue + tcp.rt_flush(); tcp.transmit(packet); } ///////////////////////////////////////////////////////////////////// @@ -476,6 +505,7 @@ void Connection::Closed::open(Connection& tcp, bool active) { if(!tcp.remote().is_empty()) { auto& tcb = tcp.tcb(); tcb.ISS = tcp.generate_iss(); + tcb.SND.recover = tcb.ISS; // [RFC 6582] auto packet = tcp.outgoing_packet(); packet->set_seq(tcb.ISS).set_flag(SYN); @@ -500,6 +530,7 @@ void Connection::Listen::open(Connection& tcp, bool) { if(!tcp.remote().is_empty()) { auto& tcb = tcp.tcb(); tcb.ISS = tcp.generate_iss(); + tcb.SND.recover = tcb.ISS; // [RFC 6582] auto packet = tcp.outgoing_packet(); packet->set_seq(tcb.ISS).set_flag(SYN); tcb.SND.UNA = tcb.ISS; @@ -776,6 +807,7 @@ State::Result Connection::Listen::handle(Connection& tcp, TCP::Packet_ptr in) { tcb.RCV.NXT = in->seq()+1; tcb.IRS = in->seq(); tcb.ISS = tcp.generate_iss(); + tcb.SND.recover = tcb.ISS; // [RFC 6582] tcb.SND.NXT = tcb.ISS+1; tcb.SND.UNA = tcb.ISS; debug(" Received SYN Packet: %s TCB Updated:\n %s \n", @@ -818,6 +850,9 @@ State::Result Connection::SynSent::handle(Connection& tcp, TCP::Packet_ptr in) { return OK; } // If SND.UNA =< SEG.ACK =< SND.NXT then the ACK is acceptable. + } else { + if(tcp.rttm.active) + tcp.rttm.stop(true); } } @@ -877,6 +912,8 @@ State::Result Connection::SynSent::handle(Connection& tcp, TCP::Packet_ptr in) { tcb.IRS = in->seq(); tcb.SND.UNA = in->ack(); + tcp.rt_ack_queue(in->ack()); + // (our SYN has been ACKed) if(tcb.SND.UNA > tcb.ISS) { tcp.set_state(Connection::Established::instance()); @@ -955,7 +992,7 @@ State::Result Connection::SynReceived::handle(Connection& tcp, TCP::Packet_ptr i and return. */ // Since we create a new connection when it starts listening, we don't wanna do this, but just delete it. - + // TODO: Remove string comparision if(tcp.prev_state().to_string() == Connection::SynSent::instance().to_string()) { tcp.signal_disconnect(Disconnect::REFUSED); } @@ -979,9 +1016,29 @@ State::Result Connection::SynReceived::handle(Connection& tcp, TCP::Packet_ptr i */ if(tcb.SND.UNA <= in->ack() and in->ack() <= tcb.SND.NXT) { debug(" SND.UNA =< SEG.ACK =< SND.NXT, continue in ESTABLISHED. \n"); + if(tcp.rttm.active) + tcp.rttm.stop(true); tcp.set_state(Connection::Established::instance()); + + // Taken from acknowledge (without congestion control) + tcb.SND.UNA = in->ack(); + if(tcp.rttm.active) + tcp.rttm.stop(); + tcp.rt_ack_queue(in->ack()); + + // 7. proccess the segment text + if(in->has_data()) { + process_segment(tcp, in); + } + tcp.signal_connect(); // NOTE: User callback - return tcp.state().handle(tcp,in); // TODO: Fix. This is kinda bad, need to make the above steps again. + + // 8. check FIN bit + if(in->isset(FIN)) { + process_fin(tcp, in); + tcp.set_state(Connection::CloseWait::instance()); + return CLOSE; + } } /* If the segment acknowledgment is not acceptable, form a @@ -1102,6 +1159,7 @@ State::Result Connection::FinWait1::handle(Connection& tcp, TCP::Packet_ptr in) if(in->ack() == tcp.tcb().SND.NXT) { // TODO: I guess or FIN is ACK'ed..? tcp.set_state(TimeWait::instance()); + tcp.rt_stop(); tcp.start_time_wait_timeout(); } else { tcp.set_state(Closing::instance()); @@ -1147,6 +1205,7 @@ State::Result Connection::FinWait2::handle(Connection& tcp, TCP::Packet_ptr in) Start the time-wait timer, turn off the other timers. */ tcp.set_state(Connection::TimeWait::instance()); + tcp.rt_stop(); tcp.start_time_wait_timeout(); } return OK; From ed80618d4bb67aa385a04b2a3e9b01cdf8773a6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Fri, 15 Apr 2016 15:18:47 +0200 Subject: [PATCH 158/311] messed up merge conflict in f7fc9cd :facepalm: --- src/net/tcp_connection.cpp | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index b064fea597..3ed5a3075b 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -311,8 +311,6 @@ void Connection::transmit(TCP::Packet_ptr packet) { rt_start(); } -<<<<<<< HEAD - /* As specified in [RFC3390], the SYN/ACK and the acknowledgment of the SYN/ACK MUST NOT increase the size of the congestion window. @@ -471,24 +469,6 @@ void Connection::set_state(State& state) { } -/* - Next compute a Smoothed Round Trip Time (SRTT) as: - - SRTT = ( ALPHA * SRTT ) + ((1-ALPHA) * RTT) - - and based on this, compute the retransmission timeout (RTO) as: - - RTO = min[UBOUND,max[LBOUND,(BETA*SRTT)]] - - where UBOUND is an upper bound on the timeout (e.g., 1 minute), - LBOUND is a lower bound on the timeout (e.g., 1 second), ALPHA is - a smoothing factor (e.g., .8 to .9), and BETA is a delay variance - factor (e.g., 1.3 to 2.0). -*/ -std::chrono::milliseconds Connection::RTO() const { - return 1s; -} - void Connection::start_time_wait_timeout() { debug2(" Time Wait timer started. \n"); time_wait_started = OS::cycles_since_boot(); From c0975ab10f5acb55ea32d3d9bcbe4880ffc07acf Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sat, 16 Apr 2016 11:38:33 +0200 Subject: [PATCH 159/311] Update CONTRIBUTE.md --- CONTRIBUTE.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTE.md b/CONTRIBUTE.md index 801044d0e0..2e8db55a28 100644 --- a/CONTRIBUTE.md +++ b/CONTRIBUTE.md @@ -2,10 +2,10 @@ Feel free to [clone, edit and send pull-request](https://help.github.com/articles/using-pull-requests). -* Send any and all pull-requests to the dev-branch. It's ok if it comes from your master branch. -* Do exactly one thing pr. pull-request. This makes it possible to quickly see and understand what you've done. +* Send any and all pull-requests to the [dev-branch](https://github.com/hioa-cs/IncludeOS/tree/dev). It's ok if it comes from your master branch. +* Do "one thing" pr. pull-request. This makes it possible to quickly see and understand what you've done. * Please don't redo the folder-structure - if you have suggestions for this, just post an issue explaining the benefits of your suggested structure. -* Everything you commit will be under the same license as this repo (Undecided so far) and HiOA will retain the right to publish your commits under a different license. +* Everything you commit will be under the same license as this repo and the copyright holders will retain the right to publish your commits under a different license. ### Consider making a standalone module! We're working on a github-based package manager, much like [npm](https://www.npmjs.com/). Most new functionality from us, such as HTTP and a REST-framework, will probably come out like separate packages - each with their own repository. This will help keep the IncludeOS core small, and easier to maintain. Clearly, we also want to gather everything in one place, and our upcoming package manager will be doing that. Meanwhile: If you do want make a module - just make it a separate github-repo, and let us know about it. We'll link to it from here, until the package manager is ready. From fdaf797bf5f0000d295b4a2eda91842ae6f552f3 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sat, 16 Apr 2016 20:04:57 +0200 Subject: [PATCH 160/311] Updated submodules to use https --- .gitmodules | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitmodules b/.gitmodules index 811cbbf272..73399617e9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,10 +1,10 @@ [submodule "mod/rapidjson"] path = mod/rapidjson - url = git@github.com:fwsGonzo/rapidjson.git + url = https://github.com/fwsGonzo/rapidjson.git [submodule "mod/GSL"] path = mod/GSL - url = git@github.com:Microsoft/GSL.git + url = https://github.com/Microsoft/GSL.git [submodule "test/lest"] path = test/lest - url = git@github.com:martinmoene/lest.git + url = https://github.com/martinmoene/lest.git From b69ccb107e43cc35bd17c507b7923d081134596f Mon Sep 17 00:00:00 2001 From: Rico Antonio Felix Date: Sat, 16 Apr 2016 17:24:27 -0400 Subject: [PATCH 161/311] Update common --- api/common | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/api/common b/api/common index 24b56e1c8b..7d5ddbb128 100644 --- a/api/common +++ b/api/common @@ -56,4 +56,46 @@ #include +/* Remove Microsoft's original termination policy */ +/* since it doesn't generate relevant information */ +/* about the reason for termination. */ +#if defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION) +#undef Expects +#undef Ensures +#endif + +/* Define our own termination policy which will now */ +/* generate relevant information about the reason */ +/* for termination. */ +#if defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION) + +/* Function used to set termination behaviour */ +inline void expects_and_ensures_termination() { std::exit(EXIT_FAILURE); } + +#define Expects(cond) \ + do { \ + if (not (cond)) { \ + std::cerr << "GSL: Precondition (" GSL_STRINGIFY(cond) \ + << ") failed...\n" << " ...in function: " \ + << __func__ << " @" << __FILE__ << ":" \ + << __LINE__ << '\n'; \ + std::set_terminate(expects_and_ensures_termination); \ + std::terminate(); \ + } \ + }while(0) \ + +#define Ensures(cond) \ + do { \ + if (not (cond)) { \ + std::cerr << "GSL: Postcondition (" GSL_STRINGIFY(cond) \ + << ") failed...\n" << " ...in function: " \ + << __func__ << " @" << __FILE__ << ":" \ + << __LINE__ << '\n'; \ + std::set_terminate(expects_and_ensures_termination); \ + std::terminate(); \ + } \ + }while(0) \ + +#endif //< defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION) + #endif From bcac8725a0ef818a638842a698095c0b1bdf62ee Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sun, 17 Apr 2016 22:37:52 +0200 Subject: [PATCH 162/311] Updated UDP-test to use new vmrunner --- test/UDP/test.py | 38 ++++++++++++++++++++++++++++++++++++++ test/UDP/vm.json | 4 ++-- 2 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 test/UDP/test.py diff --git a/test/UDP/test.py b/test/UDP/test.py new file mode 100644 index 0000000000..56f45ce011 --- /dev/null +++ b/test/UDP/test.py @@ -0,0 +1,38 @@ +import sys +sys.path.insert(0,"..") + +import vmrunner +import socket + + +def UDP_test(): + print " Performing UDP tests" + HOST, PORT = "10.0.0.42", 4242 + sock = socket.socket + # SOCK_DGRAM is the socket type to use for UDP sockets + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + + data = "Douche" + sock.sendto(data+"\n", (HOST, PORT)) + received = sock.recv(1024) + + print " Sent: {}".format(data) + print " Received: {}".format(received) + + data = "Bag" + sock.sendto(data+"\n", (HOST, PORT)) + received = sock.recv(1024) + + print " Sent: {}".format(data) + print " Received: {}".format(received) + + +# Get an auto-created VM from the vmrunner +vm = vmrunner.vms[0] + +# Add custom event-handler +vm.on_output("IncludeOS UDP test", UDP_test) + +# Boot the VM, taking a timeout as parameter +timeout = sys.argv[1] if len(sys.argv) > 1 else 30 +vm.boot(20) diff --git a/test/UDP/vm.json b/test/UDP/vm.json index 479c6b5ec0..24576f36b3 100644 --- a/test/UDP/vm.json +++ b/test/UDP/vm.json @@ -1,6 +1,6 @@ { - "image" : "test_UDP.img", - "drives" : [{"file":"test.txt", "type" :"virtio"}], + "image" : "test_udp.img", + "net" : [{"type" : "virtio", "mac" : "c0:01:0a:00:00:2a"}], "cpu" : "host", "mem" : 256 } From d2b0b3bb4f9af4307d1e76b2e3b54827fd098156 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sun, 17 Apr 2016 22:39:21 +0200 Subject: [PATCH 163/311] A python module to run test VMs --- test/vmrunner.py | 214 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 test/vmrunner.py diff --git a/test/vmrunner.py b/test/vmrunner.py new file mode 100644 index 0000000000..762de4affc --- /dev/null +++ b/test/vmrunner.py @@ -0,0 +1,214 @@ +print "vmrunner.py running" + +import os +import sys +import subprocess +import threading +import time +print os.getcwd() +import re + +import validate_test + +def abstract(): + raise Exception("Abstract class method called. Use a subclass") +# Hypervisor base / super class +# (It seems to be recommended for "new style classes" to inherit object) +class hypervisor(object): + + def __init__(self, vm): + self._vm = vm; + + # Boot a VM, returning a hypervisor handle for reuse + def boot(self): + abstract() + + # Stop the VM booted by boot + def stop(self): + abstract() + + # Read a line of output from vm + def readline(self): + abstract() + + # Verify that the hypervisor is available + def available(self, config_data = None): + abstract() + + # Wait for this VM to exit + def wait(self): + abstract() + + # Wait for this VM to exit + def poll(self): + abstract() + +# Start a process we expect to not finish immediately (i.e. a VM) +def start_process(popen_param_list): + # Start a subprocess + proc = subprocess.Popen(popen_param_list, + stdout = subprocess.PIPE, + stderr = subprocess.PIPE) + + # After half a second it should be started, otherwise throw + time.sleep(0.5) + if (proc.poll()): + data, err = proc.communicate() + raise Exception("Process exited. ERROR: " + err + " " + data); + + print " Started process PID ",proc.pid + return proc + + +# Qemu Hypervisor interface +class qemu(hypervisor): + + def drive_arg(self, filename, drive_type="virtio", drive_format="raw"): + return ["-drive","file="+filename+",format="+drive_format+",if="+drive_type] + + def net_arg(self, if_type = "virtio", if_name = "net0", mac="c0:01:0a:00:00:2a"): + type_names = {"virtio" : "virtio-net"} + qemu_ifup = os.environ['INCLUDEOS_HOME']+"/etc/qemu-ifup" + return ["-device", type_names[if_type]+",netdev="+if_name+",mac="+mac, + "-netdev", "tap,id="+if_name+",script="+qemu_ifup] + + + def boot(self): + self._out_sign = "<" + type(self).__name__ + ">" + print self._out_sign,"booting ",self._vm["image"] + + disk_args = self.drive_arg(self._vm["image"], "ide") + if self._vm.has_key("drives"): + for disk in self._vm["drives"]: + disk_args += drive_arg(disk["file"], disk["type"], disk["format"]) + + net_args = [] + i = 0 + if self._vm.has_key("net"): + for net in self._vm["net"]: + net_args += self.net_arg(net["type"], "net"+str(i), net["mac"]) + i+=1 + + command = ["sudo", "qemu-system-x86_64", "-nographic" ] + disk_args + net_args + print self._out_sign, "command:", command + + self._proc = start_process(command) + + def stop(self): + if hasattr(self, "_proc") and self._proc.poll() == None : + print self._out_sign,"Stopping", self._vm["image"], "PID",self._proc.pid + # Kill with sudo + subprocess.check_call(["sudo","kill", "-SIGTERM", str(self._proc.pid)]) + # Wait for termination (avoids the need to reset the terminal) + self._proc.wait() + + def wait(self): + print "Waiting for process to terminate" + self._proc.wait() + + def readline(self): + if self._proc.poll(): + raise Exception("Process completed") + return self._proc.stdout.readline() + + def poll(self): + return self._proc.poll() + +# VM class +class vm: + + def __init__(self, config, hyper = qemu): + self._exit_status = 0 + self._config = config + self._on_success = lambda : self.exit(0, " SUCCESS : All tests passed") + self._on_panic = lambda : self.exit(66, " FAIL : " + self._hyper.readline()) + self._on_timeout = lambda : self.exit(67, " TIMEOUT: Test timed out") + self._on_output = { + "PANIC" : self._on_panic, + "SUCCESS" : self._on_success } + assert(issubclass(hyper, hypervisor)) + self._hyper = hyper(config) + self._timer = None + + def exit(self, status, msg): + self.stop() + print msg + self._exit_status = status + sys.exit(status) + + def on_output(self, output, callback): + self._on_output[ output ] = callback + + def on_success(self, callback): + self._on_success = callback + + def on_panic(self, callack): + self._on_panic = callback + + def on_timeout(self, callback): + self._on_timeout = callback + + def boot(self, timeout = None): + + # Start the timeout thread + if (timeout): + self._timer = threading.Timer(timeout, self._on_timeout) + self._timer.start() + + # Boot via hypervisor + try: + self._hyper.boot() + except Exception as err: + self._timer.cancel() + raise err + #self.exit(1, err) + + # Start analyzing output + while self._hyper.poll() == None and not self._exit_status: + line = self._hyper.readline() + print "",line.rstrip() + + # Look for event-triggers + for pattern, func in self._on_output.iteritems(): + if re.search(pattern, line): + func() + return self + + def stop(self): + self._hyper.stop() + if hasattr(self, "_timer") and self._timer: + self._timer.cancel() + + + def wait(self): + if hasattr(self, "_timer") and self._timer: + self._timer.join() + self._hyper.wait() + return self._exit_status + + +print +print "", "Validating test" + +validate_test.load_schema("../vm.schema.json") +validate_test.has_required_stuff(".") + +print +print "", "Building test with 'make'" +subprocess.check_call(["make"]) + +default_spec = {"image" : "test.img"} + +# Provide a list of VM's with validated specs +vms = [] + +if validate_test.valid_vms: + print + print "", "Loaded VM specification(s) from JSON" + for spec in validate_test.valid_vms: + vms.append(vm(spec)) + +else: + print + print "", "No VM specification JSON found, trying default: ", default_spec + vms.append(vm(default_spec)) From 993364dfdbf2340b08fee842e492ce0fd337d43f Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sun, 17 Apr 2016 22:40:01 +0200 Subject: [PATCH 164/311] Added NIC info to vm schema --- test/vm.schema.json | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/test/vm.schema.json b/test/vm.schema.json index befb9952ba..c2ec0e780f 100644 --- a/test/vm.schema.json +++ b/test/vm.schema.json @@ -27,6 +27,21 @@ } }, + "net" : { + + "description" : "Network devices", + "type" : "array", + "items" : { + "type" : "object", + "properties" : { + "type" : { "enum" : ["virtio"] }, + "name" : { "type" : "string" } + }, + + "required" : ["type"] + } + }, + "mem" : { @@ -47,7 +62,6 @@ "description" : "Number of virtual CPU's", "type" : "number" } - }, "required" : ["image"] From c16edd2f00a45829563dad1a8072bc65418bd528 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sun, 17 Apr 2016 22:40:31 +0200 Subject: [PATCH 165/311] Test validator can now be used as a module --- test/validate_test.py | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/test/validate_test.py b/test/validate_test.py index 81495c218a..e31868daa2 100755 --- a/test/validate_test.py +++ b/test/validate_test.py @@ -5,9 +5,19 @@ import os import glob -vm_schema = json.loads(open("vm.schema.json").read()); +vm_schema = None +jsons = [] +valid_vms = [] + +def load_schema(filename): + global vm_schema + vm_schema = json.loads(open(filename).read()); def validate_vm_spec(filename): + + global valid_vms + vm_spec = None + # Load and parse as JSON try: vm_spec = json.loads(open(filename).read()) @@ -20,9 +30,13 @@ def validate_vm_spec(filename): except Exception as err: raise Exception("JSON schema validation failed: " + err.message) + valid_vms.append(vm_spec) + def has_required_stuff(path): + global jsons + # Certain files are mandatory required_files = [ "Makefile", "test.py", "README.md", "*.cpp" ] for file in required_files: @@ -30,15 +44,16 @@ def has_required_stuff(path): raise Exception("missing " + file) # JSON-files must conform to VM-schema - for json in glob.glob("*.json"): + jsons = glob.glob("*.json") + for json in jsons: validate_vm_spec(json) - -path = sys.argv[1] if len(sys.argv) > 1 else "." -os.chdir(path) - -try: - has_required_stuff(path) - print "\tPASS: ",os.getcwd() -except Exception as err: - print "\tFAIL: unmet requirements in " + path, ": " , err.message +if __name__ == "__main__": + path = sys.argv[1] if len(sys.argv) > 1 else "." + load_schema("vm.schema.json") + os.chdir(path) + try: + has_required_stuff(path) + print " \tPASS: ",os.getcwd() + except Exception as err: + print " \tFAIL: unmet requirements in " + path, ": " , err.message From 01d701fd52e1ed72306661d259bfd92a1e9335a3 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sun, 17 Apr 2016 22:41:38 +0200 Subject: [PATCH 166/311] Updated STL test to use new vmrunner --- test/STL/test.py | 5 +++++ test/STL/vm.json | 1 + 2 files changed, 6 insertions(+) create mode 100644 test/STL/test.py create mode 100644 test/STL/vm.json diff --git a/test/STL/test.py b/test/STL/test.py new file mode 100644 index 0000000000..b07ca7dfa9 --- /dev/null +++ b/test/STL/test.py @@ -0,0 +1,5 @@ +import sys +sys.path.insert(0,"..") + +import vmrunner +vmrunner.vms[0].boot() diff --git a/test/STL/vm.json b/test/STL/vm.json new file mode 100644 index 0000000000..6fb9c2fa3c --- /dev/null +++ b/test/STL/vm.json @@ -0,0 +1 @@ +{"image" : "test_STL.img" } From dc557a067b059adf607adb7c67d035548f8696f3 Mon Sep 17 00:00:00 2001 From: Rico Antonio Felix Date: Sun, 17 Apr 2016 18:59:48 -0400 Subject: [PATCH 167/311] Update common --- api/common | 71 ++++++++++++++++++++++++------------------------------ 1 file changed, 32 insertions(+), 39 deletions(-) diff --git a/api/common b/api/common index 7d5ddbb128..1a61de8236 100644 --- a/api/common +++ b/api/common @@ -45,7 +45,6 @@ # define UNUSED(x) UNUSED_ ## x #endif - /* BOCHS Break point */ #define BREAK __asm__ volatile("xchg %bx,%bx"); @@ -56,46 +55,40 @@ #include -/* Remove Microsoft's original termination policy */ -/* since it doesn't generate relevant information */ -/* about the reason for termination. */ -#if defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION) -#undef Expects -#undef Ensures -#endif +/* Define our own termination policy for contract */ +/* violation to generate relevant information about */ +/* the reason for termination. */ +#if defined(OS_TERMINATE_ON_CONTRACT_VIOLATION) -/* Define our own termination policy which will now */ -/* generate relevant information about the reason */ -/* for termination. */ -#if defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION) +#define OS_STRINGIFY(x) #x /* Function used to set termination behaviour */ inline void expects_and_ensures_termination() { std::exit(EXIT_FAILURE); } -#define Expects(cond) \ - do { \ - if (not (cond)) { \ - std::cerr << "GSL: Precondition (" GSL_STRINGIFY(cond) \ - << ") failed...\n" << " ...in function: " \ - << __func__ << " @" << __FILE__ << ":" \ - << __LINE__ << '\n'; \ - std::set_terminate(expects_and_ensures_termination); \ - std::terminate(); \ - } \ - }while(0) \ - -#define Ensures(cond) \ - do { \ - if (not (cond)) { \ - std::cerr << "GSL: Postcondition (" GSL_STRINGIFY(cond) \ - << ") failed...\n" << " ...in function: " \ - << __func__ << " @" << __FILE__ << ":" \ - << __LINE__ << '\n'; \ - std::set_terminate(expects_and_ensures_termination); \ - std::terminate(); \ - } \ - }while(0) \ - -#endif //< defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION) - -#endif +#define Expects(cond) \ + do { \ + if (not (cond)) { \ + std::cerr << "OS: Precondition (" OS_STRINGIFY(cond) \ + << ") failed...\n" << "\t...in function: " \ + << __func__ << " @" << __FILE__ << ":" \ + << __LINE__ << '\n'; \ + std::set_terminate(expects_and_ensures_termination); \ + std::terminate(); \ + } \ + } while(0) + +#define Ensures(cond) \ + do { \ + if (not (cond)) { \ + std::cerr << "OS: Postcondition (" OS_STRINGIFY(cond) \ + << ") failed...\n" << "\t...in function: " \ + << __func__ << " @" << __FILE__ << ":" \ + << __LINE__ << '\n'; \ + std::set_terminate(expects_and_ensures_termination); \ + std::terminate(); \ + } \ + } while(0) + +#endif //< defined(OS_TERMINATE_ON_CONTRACT_VIOLATION) + +#endif //< INCLUDEOS_COMMON_HEADER From ad7eb8f2fe7ff0c0753a196622c0beab7f65e9f4 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Mon, 18 Apr 2016 11:09:58 +0200 Subject: [PATCH 168/311] install: Add git submodule update --- etc/install_from_bundle.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/etc/install_from_bundle.sh b/etc/install_from_bundle.sh index 64dbd513d2..2d9bcb9eea 100755 --- a/etc/install_from_bundle.sh +++ b/etc/install_from_bundle.sh @@ -66,6 +66,12 @@ else tar -C $INCLUDEOS_INSTALL_LOC -xzf $filename fi +echo -e "\n\n>>> Installing submodules" +pushd $INCLUDEOS_SRC +git submodule init +git submodule update +popd + echo -e "\n\n>>> Building IncludeOS" pushd $INCLUDEOS_SRC/src make -j From acae3f1d567ac603250f4b61ce5747e83d5361dc Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Mon, 18 Apr 2016 11:17:30 +0200 Subject: [PATCH 169/311] test.py is now executable --- test/UDP/test.py | 1 + 1 file changed, 1 insertion(+) mode change 100644 => 100755 test/UDP/test.py diff --git a/test/UDP/test.py b/test/UDP/test.py old mode 100644 new mode 100755 index 56f45ce011..63e6c7fe47 --- a/test/UDP/test.py +++ b/test/UDP/test.py @@ -1,3 +1,4 @@ +#! /usr/bin/python import sys sys.path.insert(0,"..") From 28613dc3211290ab90c4b3290e770fdd7d1c02d1 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Mon, 18 Apr 2016 11:19:16 +0200 Subject: [PATCH 170/311] GSL-test is now run by test.py --- test/GSL/test.py | 7 +++++++ test/GSL/vm.json | 1 + 2 files changed, 8 insertions(+) create mode 100755 test/GSL/test.py create mode 100644 test/GSL/vm.json diff --git a/test/GSL/test.py b/test/GSL/test.py new file mode 100755 index 0000000000..1b330254fe --- /dev/null +++ b/test/GSL/test.py @@ -0,0 +1,7 @@ +#! /usr/bin/python + +import sys +sys.path.insert(0,"..") + +import vmrunner +vmrunner.vms[0].boot() diff --git a/test/GSL/vm.json b/test/GSL/vm.json new file mode 100644 index 0000000000..ca0d6ee531 --- /dev/null +++ b/test/GSL/vm.json @@ -0,0 +1 @@ +{"image" : "test_GSL.img" } From 33d57b7fa36c7bffb282fd31959d79369309fa23 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Mon, 18 Apr 2016 11:24:57 +0200 Subject: [PATCH 171/311] Added a default 'atexit' to get 'std::exit' to work --- api/kernel/syscalls.hpp | 5 ++-- src/kernel/os.cpp | 44 +++++++++++++++++---------------- src/kernel/syscalls.cpp | 54 ++++++++++++++++++++--------------------- 3 files changed, 53 insertions(+), 50 deletions(-) diff --git a/api/kernel/syscalls.hpp b/api/kernel/syscalls.hpp index 8d2d025c28..57b0b58cfc 100644 --- a/api/kernel/syscalls.hpp +++ b/api/kernel/syscalls.hpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -23,6 +23,7 @@ extern "C" { int kill(pid_t pid, int sig); void panic(const char* why) __attribute__((noreturn)); + void default_exit() __attribute__((noreturn)); } #endif //< KERNEL_SYSCALLS_HPP diff --git a/src/kernel/os.cpp b/src/kernel/os.cpp index 532e9e6eea..e895ff1b07 100644 --- a/src/kernel/os.cpp +++ b/src/kernel/os.cpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -33,60 +33,62 @@ MHz OS::cpu_mhz_ {1000}; // Set default rsprint_handler OS::rsprint_func OS::rsprint_handler_ = &OS::default_rsprint; -hw::Serial& OS::com1 = hw::Serial::port<1>(); +hw::Serial& OS::com1 = hw::Serial::port<1>(); extern "C" uint16_t _cpu_sampling_freq_divider_; void OS::start() { - + // Initialize serial port com1.init(); - + // Print a fancy header FILLINE('='); CAPTION("#include // Literally\n"); FILLINE('='); - + debug("\t[*] OS class started\n"); srand(time(NULL)); - + // Heap extern caddr_t heap_end; extern char _end; MYINFO("Heap start: @ %p", heap_end); MYINFO("Current end is: @ %p", &_end); - - // Set up interrupt handlers + + atexit(default_exit); + + // Set up interrupt handlers IRQ_manager::init(); - + // Initialize the Interval Timer hw::PIT::init(); // Initialize PCI devices PCI_manager::init(); - - /** Estimate CPU frequency + + /** Estimate CPU frequency MYINFO("Estimating CPU-frequency"); INFO2("|"); - INFO2("+--(10 samples, %f sec. interval)", + INFO2("+--(10 samples, %f sec. interval)", (hw::PIT::frequency() / _cpu_sampling_freq_divider_).count()); INFO2("|"); - + // TODO: Debug why actual measurments sometimes causes problems. Issue #246. cpu_mhz_ = hw::PIT::CPUFrequency(); INFO2("+--> %f MHz", cpu_mhz_.count()); - + **/ - + MYINFO("Starting %s", Service::name().c_str()); FILLINE('='); // Everything is ready Service::start(); - + event_loop(); } @@ -103,12 +105,12 @@ void OS::event_loop() { printf(" IncludeOS %s\n", version().c_str()); printf(" +--> Running [ %s ]\n", Service::name().c_str()); FILLINE('~'); - + while (power_) { - IRQ_manager::notify(); + IRQ_manager::notify(); debug(" Woke up @ t = %li\n", uptime()); } - + //Cleanup //Service::stop(); } @@ -118,7 +120,7 @@ size_t OS::rsprint(const char* str) { // Measure length while (str[len++]); - + // Output callback rsprint_handler_(str, len); return len; diff --git a/src/kernel/syscalls.cpp b/src/kernel/syscalls.cpp index 706fb0288e..78dd4c495f 100644 --- a/src/kernel/syscalls.cpp +++ b/src/kernel/syscalls.cpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -34,35 +34,30 @@ static bool debug_syscalls {true}; caddr_t heap_end; void _exit(int status) { - printf("\tSYSCALL EXIT: status %d. Nothing more we can do.\n", status); - printf("\tSTOPPING EXECUTION\n"); - while (1) - asm("cli; hlt;"); + panic("Exit called"); } -int close(int UNUSED(file)) { - debug("SYSCALL CLOSE Dummy, returning -1"); +int close(int UNUSED(file)) { + panic("SYSCALL CLOSE Dummy, returning -1"); return -1; }; -int execve(const char* UNUSED(name), - char* const* UNUSED(argv), +int execve(const char* UNUSED(name), + char* const* UNUSED(argv), char* const* UNUSED(env)) { - debug((char*) "SYSCALL EXECVE NOT SUPPORTED"); - errno = ENOMEM; + panic("SYSCALL EXECVE NOT SUPPORTED"); return -1; }; int fork() { - debug("SYSCALL FORK NOT SUPPORTED"); - errno=ENOMEM; + panic("SYSCALL FORK NOT SUPPORTED"); return -1; }; int fstat(int UNUSED(file), struct stat *st) { debug("SYSCALL FSTAT Dummy, returning OK 0"); - st->st_mode = S_IFCHR; + st->st_mode = S_IFCHR; return 0; }; @@ -78,34 +73,33 @@ int isatty(int file) { } // Not stdxxx, error out - debug("SYSCALL ISATTY Unknown descriptor %i", file); + panic("SYSCALL ISATTY Unknown descriptor "); errno = EBADF; return 0; } int link(const char* UNUSED(old), const char* UNUSED(_new)) { - debug("SYSCALL LINK - Unsupported"); - kill(1,9); + panic("SYSCALL LINK unsupported"); return -1; } int unlink(const char* UNUSED(name)) { - debug((char*)"SYSCALL UNLINK Dummy, returning -1"); + panic("SYSCALL UNLINK unsupported"); return -1; } off_t lseek(int UNUSED(file), off_t UNUSED(ptr), int UNUSED(dir)) { - debug("SYSCALL LSEEK returning 0"); + panic("SYSCALL LSEEK returning 0"); return 0; } int open(const char* UNUSED(name), int UNUSED(flags), ...) { - debug("SYSCALL OPEN Dummy, returning -1"); + panic("SYSCALL OPEN unsupported"); return -1; }; int read(int UNUSED(file), void* UNUSED(ptr), size_t UNUSED(len)) { - debug("SYSCALL READ Not supported, returning 0"); + panic("SYSCALL READ unsupported"); return 0; } @@ -130,7 +124,7 @@ int stat(const char* UNUSED(file), struct stat *st) { }; clock_t times(struct tms* UNUSED(buf)) { - debug((char*)"SYSCALL TIMES Dummy, returning -1"); + panic("SYSCALL TIMES Dummy, returning -1"); return -1; }; @@ -147,13 +141,13 @@ int gettimeofday(struct timeval* p, void* UNUSED(z)) { return 5; } -int kill(pid_t pid, int sig) { +int kill(pid_t pid, int sig) { printf("!!! Kill PID: %i, SIG: %i - %s ", pid, sig, strsignal(sig)); - + if (sig == 6ul) { printf("/ ABORT\n"); } - + panic("\tKilling a process doesn't make sense in IncludeOS. Panic."); errno = ESRCH; return -1; @@ -164,9 +158,15 @@ void panic(const char* why) { printf("\n\t **** PANIC: ****\n %s\n", why); printf("\tHeap end: %p\n", heap_end); while(1) __asm__("cli; hlt;"); - + } +// No continuation from here +void default_exit() { + panic("Exit was called"); +} + + // To keep our sanity, we need a reason for the abort void abort_ex(const char* why) { printf("\n\t !!! abort_ex. Why: %s", why); From 0e6ad266a960a468c8f91a4e48cb5e0d0b272938 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Mon, 18 Apr 2016 11:25:31 +0200 Subject: [PATCH 172/311] GSL is now included in common --- test/GSL/service.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/test/GSL/service.cpp b/test/GSL/service.cpp index 2f8a83596f..5c9c9e9445 100644 --- a/test/GSL/service.cpp +++ b/test/GSL/service.cpp @@ -21,15 +21,13 @@ **/ - -#include -#include +#include #define GSL_THROW_ON_CONTRACT_VIOLATION -#include +#include +#include #include - int clock_gettime(clockid_t clk_id, struct timespec *tp){ (void*)clk_id; (void*)tp; @@ -51,8 +49,12 @@ const lest::test test_basic_gsl[] = { class Math { public: static int div (int x, int y) { + + printf("Dividing %i by %i ", x, y); Expects( y > 0 ); + printf("Dividing %i by %i ", x, y); + int prevcount_ = divcount_; auto result = x / y; @@ -188,7 +190,7 @@ const lest::test test_basic_gsl[] = { void Service::start() { - + MYINFO ("Starting LEST-tests"); // Lest takes command line params as vector auto failed = lest::run(test_basic_gsl, {"-p"}); From 1a0fe7ad6c2c5f2ee500c506d5552c6e56b573ba Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Mon, 18 Apr 2016 11:30:11 +0200 Subject: [PATCH 173/311] New-style makefile for IDE --- test/IDE/Makefile | 128 +++------------------------------------------- 1 file changed, 7 insertions(+), 121 deletions(-) diff --git a/test/IDE/Makefile b/test/IDE/Makefile index c79b067a1b..c1e4407e0c 100644 --- a/test/IDE/Makefile +++ b/test/IDE/Makefile @@ -3,132 +3,18 @@ ################################################# # The name of your service -SERVICE = Test_IDE +SERVICE = test_IDE +SERVICE_NAME = IncludeOS IDE test # Your service parts FILES = service.cpp +# Your disk image +DISK= + # IncludeOS location ifndef INCLUDEOS_INSTALL - INCLUDEOS_INSTALL=$(HOME)/IncludeOS_install +INCLUDEOS_INSTALL=$(HOME)/IncludeOS_install endif -# Shorter name -INSTALL = $(INCLUDEOS_INSTALL) - -# Compiler/Linker -################################################### - -OPTIONS = -Ofast -msse3 -Wall -Wextra -mstackrealign - -# External Libraries -################################################### -LIBC_OBJ = $(INSTALL)/newlib/libc.a -LIBG_OBJ = $(INSTALL)/newlib/libg.a -LIBM_OBJ = $(INSTALL)/newlib/libm.a - -LIBGCC = $(INSTALL)/libgcc/libgcc.a -LIBCXX = $(INSTALL)/libcxx/libc++.a $(INSTALL)/libcxx/libc++abi.a - - -INC_NEWLIB=$(INSTALL)/newlib/include -INC_LIBCXX=$(INSTALL)/libcxx/include - -DEBUG_OPTS = -ggdb3 -v - -CPP = clang++-3.6 -target i686-elf -LD = ld - -INCLUDES = -I$(INC_LIBCXX) -I$(INSTALL)/api/sys -I$(INC_NEWLIB) -I$(INSTALL)/api - -CAPABS_COMMON = -msse3 -mstackrealign # Needed for 16-byte stack alignment (SSE) - -all: CAPABS = $(CAPABS_COMMON) -O2 -debug: CAPABS = $(CAPABS_COMMON) -O0 -stripped: CAPABS = $(CAPABS_COMMON) -Oz - -WARNS = -Wall -Wextra #-pedantic -CPPOPTS = $(CAPABS) $(WARNS) -c -m32 -std=c++14 -fno-stack-protector $(INCLUDES) -D_LIBCPP_HAS_NO_THREADS=1 #-flto -fno-exceptions - -LDOPTS = -nostdlib -melf_i386 -N --script=$(INSTALL)/linker.ld -flto - - -# Objects -################################################### - -CRTBEGIN_OBJ = $(INSTALL)/crt/crtbegin.o -CRTEND_OBJ = $(INSTALL)/crt/crtend.o -CRTI_OBJ = $(INSTALL)/crt/crti.o -CRTN_OBJ = $(INSTALL)/crt/crtn.o - -# Full link list -OBJS = $(FILES:.cpp=.o) .service_name.o -LIBS = $(INSTALL)/os.a $(LIBCXX) $(INSTALL)/os.a $(LIBC_OBJ) $(LIBM_OBJ) $(LIBGCC) - -OS_PRE = $(CRTBEGIN_OBJ) $(CRTI_OBJ) -OS_POST = $(CRTEND_OBJ) $(CRTN_OBJ) - -DEPS = $(OBJS:.o=.d) - -# Complete bulid -################################################### -# A complete build includes: -# - a "service", to be linked with OS-objects (OS included) - -all: service - -stripped: LDOPTS += -S #strip all -stripped: CPPOPTS += -Oz -stripped: service - - -# The same, but with debugging symbols (OBS: Dramatically increases binary size) -debug: CCOPTS += $(DEBUG_OPTS) -debug: CPPOPTS += $(DEBUG_OPTS) -debug: LDOPTS += -M --verbose - -debug: OBJS += $(LIBG_OBJ) - -debug: service #Don't wanna call 'all', since it strips debug info - -# Service -################################################### -service.o: service.cpp - @echo "\n>> Compiling the service" - $(CPP) $(CPPOPTS) -o $@ $< - -.service_name.o: $(INSTALL)/service_name.cpp - $(CPP) $(CPPOPTS) -DSERVICE_NAME="\"$(SERVICE)\"" -o $@ $< - -# Link the service with the os -service: $(OBJS) $(LIBS) - @echo "\n>> Linking service with OS" - $(LD) $(LDOPTS) $(OS_PRE) $(OBJS) $(LIBS) $(OS_POST) -o $(SERVICE) - @echo "\n>> Building image " $(SERVICE).img - $(INSTALL)/vmbuild $(INSTALL)/bootloader $(SERVICE) - -# Object files -################################################### - -# Runtime -crt%.o: $(INSTALL)/crt/crt%.s - @echo "\n>> Assembling C runtime:" $@ - $(CPP) $(CPPOPTS) -x assembler-with-cpp $< - -# General C++-files to object files -%.o: %.cpp - @echo "\n>> Compiling OS object without header" - $(CPP) $(CPPOPTS) -o $@ $< - -# AS-assembled object files -%.o: %.s - @echo "\n>> Assembling GNU 'as' files" - $(CPP) $(CPPOPTS) -x assembler-with-cpp $< - -# Cleanup -################################################### -clean: - $(RM) $(OBJS) $(DEPS) $(SERVICE) - $(RM) $(SERVICE).img - --include $(DEPS) +include $(INCLUDEOS_INSTALL)/Makeseed From 3d4c584dbb6c2f44713d54fc8658e3de4dc232a8 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Mon, 18 Apr 2016 11:39:27 +0200 Subject: [PATCH 174/311] install: Git submodule update in install.sh --- install.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/install.sh b/install.sh index 485d0d8e11..61b531a85c 100755 --- a/install.sh +++ b/install.sh @@ -72,6 +72,11 @@ fi echo -e "\n >>> DEPENDENCIES SUCCESSFULLY BUILT. Creating binary bundle \n" $INCLUDEOS_SRC/etc/create_binary_bundle.sh +echo -e "\n\n>>> Installing submodules" +pushd $INCLUDEOS_SRC +git submodule init +git submodule update +popd if [ ! -z $do_includeos ]; then # Build and install the vmbuilder @@ -90,9 +95,7 @@ if [ ! -z $do_includeos ]; then echo -e "\n >>> Installing IncludeOS" make install - popd - # RUNNING IncludeOS PREREQS_RUN="bridge-utils qemu-kvm" From 06db9e18c24d5af6bbb44590e6f8e29ac7e0a995 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Mon, 18 Apr 2016 11:41:38 +0200 Subject: [PATCH 175/311] A WIP test for virtio-block --- test/virtio_block/Makefile | 20 ++++++++ test/virtio_block/README.md | 1 + test/virtio_block/service.cpp | 96 +++++++++++++++++++++++++++++++++++ test/virtio_block/test.py | 3 ++ test/virtio_block/test.sh | 6 +++ test/virtio_block/test.txt | 22 ++++++++ test/virtio_block/vm.json | 4 ++ 7 files changed, 152 insertions(+) create mode 100644 test/virtio_block/Makefile create mode 100644 test/virtio_block/README.md create mode 100644 test/virtio_block/service.cpp create mode 100644 test/virtio_block/test.py create mode 100755 test/virtio_block/test.sh create mode 100644 test/virtio_block/test.txt create mode 100644 test/virtio_block/vm.json diff --git a/test/virtio_block/Makefile b/test/virtio_block/Makefile new file mode 100644 index 0000000000..b38ce33a8d --- /dev/null +++ b/test/virtio_block/Makefile @@ -0,0 +1,20 @@ +################################################# +# IncludeOS SERVICE makefile # +################################################# + +# The name of your service +SERVICE = test_virtio_block +SERVICE_NAME = Virtio Block Test Service + +# Your service parts +FILES=service.cpp + +# Your disk image +DISK= + +# IncludeOS location +ifndef INCLUDEOS_INSTALL +INCLUDEOS_INSTALL=$(HOME)/IncludeOS_install +endif + +include $(INCLUDEOS_INSTALL)/Makeseed diff --git a/test/virtio_block/README.md b/test/virtio_block/README.md new file mode 100644 index 0000000000..007fa45217 --- /dev/null +++ b/test/virtio_block/README.md @@ -0,0 +1 @@ +# Test Virtio block. WIP diff --git a/test/virtio_block/service.cpp b/test/virtio_block/service.cpp new file mode 100644 index 0000000000..4149cba9d9 --- /dev/null +++ b/test/virtio_block/service.cpp @@ -0,0 +1,96 @@ +// This file is a part of the IncludeOS unikernel - www.includeos.org +// +// Copyright 2015 Oslo and Akershus University College of Applied Sciences +// and Alfred Bratterud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include +std::shared_ptr disk; + +void list_partitions(decltype(disk)); + +#define MYINFO(X,...) INFO("VirtioBlk",X,##__VA_ARGS__) + +void Service::start() +{ + // instantiate memdisk with FAT filesystem + auto& device = hw::Dev::disk<1, VirtioBlk>(); + disk = std::make_shared (device); + + CHECKSERT(disk,"Disk created"); + + // if the disk is empty, we can't mount a filesystem anyways + CHECKSERT(not disk->empty(), "Disk is not empty"); + + // list extended partitions + list_partitions(disk); + + // mount first valid partition (auto-detect and mount) + disk->mount([] (fs::error_t err) { + if (err) { + printf("Could not mount filesystem\n"); + return; + } + + // async ls + disk->fs().ls("/", [] (fs::error_t err, auto ents) { + if (err) { + printf("Could not list '/' directory\n"); + return; + } + + // go through directory entries + for (auto& e : *ents) { + printf("%s: %s\t of size %llu bytes (CL: %llu)\n", + e.type_string().c_str(), e.name().c_str(), e.size, e.block); + + if (e.is_file()) { + printf("*** Attempting to read: %s\n", e.name().c_str()); + disk->fs().read(e, 0, e.size, [e] (fs::error_t err, fs::buffer_t buffer, size_t len) { + if (err) { + printf("Failed to read file %s!\n", + e.name().c_str()); + return; + } + + std::string contents((const char*) buffer.get(), len); + printf("[%s contents]:\n%s\nEOF\n\n", + e.name().c_str(), contents.c_str()); + }); + } + } + + INFO("Virtioblk Test", "SUCCESS"); + }); + + }); // disk->auto_detect() + + printf("*** TEST SERVICE STARTED *** \n"); + +} + +void list_partitions(decltype(disk) disk) +{ + disk->partitions([] (fs::error_t err, auto& parts) { + + CHECKSERT (not err, "Was able to fetch partition table"); + + for (auto& part : parts) + printf("[Partition] '%s' at LBA %u\n", + part.name().c_str(), part.lba()); + + }); +} diff --git a/test/virtio_block/test.py b/test/virtio_block/test.py new file mode 100644 index 0000000000..1839cb89ab --- /dev/null +++ b/test/virtio_block/test.py @@ -0,0 +1,3 @@ +from ...test import vmrunner + +print "Running VM" diff --git a/test/virtio_block/test.sh b/test/virtio_block/test.sh new file mode 100755 index 0000000000..7378f9b2ee --- /dev/null +++ b/test/virtio_block/test.sh @@ -0,0 +1,6 @@ +#!/bin/bash +source ../test_base + +make +export HDB="-drive file=./test.txt,if=virtio,media=disk" +start test_virtio_block.img diff --git a/test/virtio_block/test.txt b/test/virtio_block/test.txt new file mode 100644 index 0000000000..3ed50e9af6 --- /dev/null +++ b/test/virtio_block/test.txt @@ -0,0 +1,22 @@ + + ,----. ,-. ,----.,------. ,-. ,-.,-. ,-. + / ,-,_/ ,' | / /"P /`-, ,-',' | / // |/ / + / / __ ,' ,| | / ,---' / / ,' ,| | / // J P / + / '-' /,' ,--. |/ / / /,' ,--. |/ // /| / + `----''--' `-'`'.--""""--.--' `-'`' `' `-' + nnnnnnnnnnnnnnnn,'.n*""""*N.`.####################### + NNNNNNNNNNNNNNN/ J',n*""*n.`L \##### ### ### ### #### + : J J___/\___L L :##################### + nnnnnnnnnnnnnn{ [{ `. ,' }] }## ### ### ### ### ## + NNNNNNNNNNNNNN: T T /,'`.\ T J :##################### + \ L,`*n,,n*',J / + nnnnnnnnnnnnnnnn`. *n,,,,n* ,'nnnnnnnnnnnnnnnnnnnnnnn + NNNNNNNNNNNNNNNNNN`-..__..-'NNNNNNNNNNNNNNNNNNNNNNNNN + ,-. ,-. ,-. ,----. ,----.,-. ,----. ,-. + | `. \ `.| \\ .--`\ \"L \\ \\ .-._\ | `. o!0 + | |. `. \ \ ` L \\ __\ \ . < \ \\ \ __ | |. `. + | .--. `.\ \`-'\ \\ `---.\ \L `.\ \\ `-` \| .--. `. + `-' `--``' `-'`----' `-'`-' `' `----'`-' `--' + +####################################################### +##IncludeOS Rocks! ## diff --git a/test/virtio_block/vm.json b/test/virtio_block/vm.json new file mode 100644 index 0000000000..820312c0ff --- /dev/null +++ b/test/virtio_block/vm.json @@ -0,0 +1,4 @@ +{ + "image" : "test_STL.img", + "drive" : [{"file" : "test.txt", "type" : "virtio" }] +} From 8c89e581b7864a14fe7c9ba826b4d4e33484a6cc Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Mon, 18 Apr 2016 11:42:58 +0200 Subject: [PATCH 176/311] virtio-block test will use test.py --- test/virtio_block/test.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) mode change 100644 => 100755 test/virtio_block/test.py diff --git a/test/virtio_block/test.py b/test/virtio_block/test.py old mode 100644 new mode 100755 index 1839cb89ab..1b330254fe --- a/test/virtio_block/test.py +++ b/test/virtio_block/test.py @@ -1,3 +1,7 @@ -from ...test import vmrunner +#! /usr/bin/python -print "Running VM" +import sys +sys.path.insert(0,"..") + +import vmrunner +vmrunner.vms[0].boot() From 912f78b4c2559e86e3b9f49a9afe89dd5420e435 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Mon, 18 Apr 2016 12:00:18 +0200 Subject: [PATCH 177/311] syscalls: Silence unused param warning --- src/kernel/syscalls.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/kernel/syscalls.cpp b/src/kernel/syscalls.cpp index 78dd4c495f..59152d8201 100644 --- a/src/kernel/syscalls.cpp +++ b/src/kernel/syscalls.cpp @@ -33,12 +33,12 @@ static bool debug_syscalls {true}; caddr_t heap_end; -void _exit(int status) { +void _exit(int) { panic("Exit called"); } -int close(int UNUSED(file)) { - panic("SYSCALL CLOSE Dummy, returning -1"); +int close(int) { + panic("SYSCALL CLOSE NOT SUPPORTED"); return -1; }; @@ -158,7 +158,6 @@ void panic(const char* why) { printf("\n\t **** PANIC: ****\n %s\n", why); printf("\tHeap end: %p\n", heap_end); while(1) __asm__("cli; hlt;"); - } // No continuation from here From bebb46693d308334054ff91b6fdf9b8b5ee835a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Mon, 18 Apr 2016 16:46:07 +0200 Subject: [PATCH 178/311] tcp: work on fast recovery (new reno) rfc 6582 --- api/net/tcp.hpp | 87 +++++++++++++++++++++++++------ src/net/tcp_connection.cpp | 55 +++++++++++++++---- src/net/tcp_connection_states.cpp | 25 +++++---- 3 files changed, 130 insertions(+), 37 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index 04ac58e83c..477d57ca67 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -809,12 +809,9 @@ namespace net { ssthresh = TCP::default_window_size; }; - bool slow_start() const { - return SND.cwnd <= ssthresh; - } - - bool congestion_avoidance() const { - return !slow_start(); + void init() { + ISS = TCP::generate_iss(); + SND.recover = ISS; // [RFC 6582] } std::string to_string() const; @@ -1422,6 +1419,13 @@ namespace net { /// Congestion Control [RFC 5681] /// + bool RENO_FAST_RECOVERY = false; + // First partial ack not seen + bool RENO_FPACK_NOT_SEEN = false; + + Seq RENO_PREV_HIGHEST_ACK = 0; + Seq RENO_HIGHEST_ACK = 0; + inline void setup_congestion_control() { reno_init(); } @@ -1444,7 +1448,7 @@ namespace net { inline void reno_init_cwnd(size_t segments) { control_block.SND.cwnd = segments*SMSS(); - printf(" Cwnd initilized: %u\n", control_block.SND.cwnd); + debug2(" Cwnd initilized: %u\n", control_block.SND.cwnd); } inline void reno_init_sshtresh() @@ -1456,6 +1460,9 @@ namespace net { inline void reno_increase_cwnd(uint16_t n) { control_block.SND.cwnd += std::min(n, SMSS()); } + inline void reno_deflate_cwnd(uint16_t n) + { control_block.SND.cwnd -= (n >= SMSS()) ? n-SMSS() : n; } + inline void reno_reduce_ssthresh() { control_block.ssthresh = std::max( (flight_size() / 2), (2 * SMSS()) ); printf(" Slow start threshold reduced: %u\n", @@ -1465,7 +1472,8 @@ namespace net { inline void reno_fast_retransmit() { printf(" Fast retransmit initiated.\n"); retransmit(); - control_block.SND.cwnd = control_block.ssthresh + (3 * SMSS()); + reno_enter_fast_recovery(); + //control_block.SND.cwnd = control_block.ssthresh + (3 * SMSS()); } inline void reno_loss_detected() { @@ -1473,6 +1481,10 @@ namespace net { reno_fast_retransmit(); } + inline void reno_enter_fast_retransmit() { + reno_loss_detected(); + } + inline bool reno_is_dup_ack(TCP::Packet_ptr in) { bool is_dup_ack = flight_size() > 0 and !in->has_data() @@ -1483,15 +1495,62 @@ namespace net { return is_dup_ack; } - inline void reno_dup_ack() { + inline void reno_dup_ack(Seq ACK) { if(++DUP_ACK == 3) { printf(" Duplicate ACK - Strike 3!\n"); - reno_loss_detected(); + if(reno_should_recover(ACK)) { + reno_update_recover(); + reno_enter_fast_retransmit(); + } } else if(DUP_ACK > 3) { control_block.SND.cwnd += SMSS(); } } + inline void reno_enter_fast_recovery() { + control_block.SND.cwnd = control_block.ssthresh + (3 * SMSS()); + RENO_FAST_RECOVERY = true; + RENO_FPACK_NOT_SEEN = true; + printf(" Entered Fast Recovery - Cwnd: %u\n", control_block.SND.cwnd); + } + + inline void reno_exit_fast_recovery() { + control_block.SND.cwnd = std::min((int32_t)control_block.ssthresh, std::max(flight_size(), (int32_t)SMSS()) + SMSS()); + RENO_FAST_RECOVERY = false; + printf(" Exited Fast Recovery - Cwnd: %u\n", control_block.SND.cwnd); + } + + inline bool reno_should_recover(Seq ACK) { + return (ACK - 1 > control_block.SND.recover) or reno_heuristic_segment_loss_detected(); + } + + inline bool reno_heuristic_segment_loss_detected() { + return (congestion_window() > SMSS()) + and (RENO_HIGHEST_ACK - RENO_PREV_HIGHEST_ACK <= 4*SMSS()); + } + + inline bool reno_full_ack(Seq ACK) { + return ACK - 1 > control_block.SND.recover; + } + + inline bool reno_partial_ack(Seq ACK) { + return !reno_full_ack(ACK); + } + + inline bool reno_is_fast_recovering() { + return RENO_FAST_RECOVERY; + } + + inline void reno_update_recover() { + control_block.SND.recover = control_block.SND.NXT; + } + + void reno_update_heuristic_ack(Seq ACK) { + RENO_PREV_HIGHEST_ACK = RENO_HIGHEST_ACK; + RENO_HIGHEST_ACK = ACK; + } + + /* Generate a new ISS. */ @@ -1574,11 +1633,7 @@ namespace net { /* When retransmission times out. */ - inline void rt_timeout() { - if(rto_attempt++ == 0) - reno_reduce_ssthresh(); - retransmit(); - } + void rt_timeout(); /* @@ -1733,7 +1788,7 @@ namespace net { /* Generate a unique initial sequence number (ISS). */ - TCP::Seq generate_iss(); + static TCP::Seq generate_iss(); /* Returns a free port for outgoing connections. diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index 3ed5a3075b..68a83ec864 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -165,8 +165,8 @@ size_t Connection::send(const char* buffer, size_t remaining, size_t& packet_cou // If last packet, add PUSH. // TODO: Redefine "push" - if((!remaining or !packet_count or usable_window() < SMSS()) and PUSH) - //if(!remaining and PUSH) + //if((!remaining or !packet_count or usable_window() < SMSS()) and PUSH) + if(!remaining and PUSH) packet->set_flag(PSH); // Advance outgoing sequence number (SND.NXT) with the length of the data. @@ -177,6 +177,7 @@ size_t Connection::send(const char* buffer, size_t remaining, size_t& packet_cou debug2(" Packet Limit: %u - Written: %u" " - Remaining: %u - Packet count: %u, Window: %u\n", packet_limit, written, remaining, packet_count, usable_window()); + if(reno_is_fast_recovering()) break; } debug(" Sent %u bytes of data\n", bytes_written); return bytes_written; @@ -323,20 +324,43 @@ void Connection::acknowledge(Seq ACK) { size_t bytes_acked = ACK - control_block.SND.UNA; control_block.SND.UNA = ACK; - if(reno_slow_start()) { - reno_increase_cwnd(bytes_acked); - debug2(" Slow start - cwnd increased: %u\n", - control_block.SND.cwnd); + reno_update_heuristic_ack(ACK); + if(!reno_is_fast_recovering()) { + if(reno_slow_start()) { + reno_increase_cwnd(bytes_acked); + debug2(" Slow start - cwnd increased: %u\n", + control_block.SND.cwnd); + } + // congestion avoidance + else { + if(rttm.active) { + reno_increase_cwnd(bytes_acked); + debug2(" Congestion avoidance - cwnd increased: %u\n", + control_block.SND.cwnd); + } + } } - // congestion avoidance + // fast recovery else { - if(rttm.active) { - reno_increase_cwnd(bytes_acked); - debug2(" Congestion avoidance - cwnd increased: %u\n", - control_block.SND.cwnd); + // full acknowledgement + if(reno_full_ack(ACK)) { + reno_exit_fast_recovery(); + } + // partial acknowledgement + else { + reno_deflate_cwnd(bytes_acked); + if(RENO_FPACK_NOT_SEEN) { + printf(" #1 Partial ACK - %u, Cwnd: %u\n", ACK, control_block.SND.cwnd); + rt_restart(); + RENO_FPACK_NOT_SEEN = false; + } else { + //printf(" Partial ACK - %u, Cwnd: %u\n", ACK, control_block.SND.cwnd); + } } } + /**/ + if(rttm.active) rttm.stop(); @@ -457,6 +481,15 @@ void Connection::rt_clear() { retransq.clear(); } +void Connection::rt_timeout() { + if(rto_attempt++ == 0) + reno_reduce_ssthresh(); + reno_update_recover(); + if(reno_is_fast_recovering()) + reno_exit_fast_recovery(); + retransmit(); +} + TCP::Seq Connection::generate_iss() { return host_.generate_iss(); } diff --git a/src/net/tcp_connection_states.cpp b/src/net/tcp_connection_states.cpp index bd4bef15fe..0269b4bd72 100644 --- a/src/net/tcp_connection_states.cpp +++ b/src/net/tcp_connection_states.cpp @@ -255,7 +255,7 @@ bool Connection::State::check_ack(Connection& tcp, TCP::Packet_ptr in) { //!in->isset(FIN) and !in->isset(SYN) else if(tcp.reno_is_dup_ack(in)) { debug2(" Reno Dup ACK %u\n", in->ack()); - tcp.reno_dup_ack(); + tcp.reno_dup_ack(in->ack()); } // this is an RFC 793 DUP ACK else { @@ -342,14 +342,22 @@ void Connection::State::process_segment(Connection& tcp, TCP::Packet_ptr in) { // Receive could result in a user callback. This is used to avoid sending empty ACK reply. auto snd_nxt = tcb.SND.NXT; debug(" Received packet with DATA-LENGTH: %i. Add to receive buffer. \n", length); + if(tcp.read_request.buffer.capacity()) { auto received = tcp.receive((uint8_t*)in->data(), in->data_length(), in->isset(PSH)); assert(received == length); } tcb.RCV.NXT += length; // [RFC 5681] - tcb.SND.cwnd += std::min(length, tcp.SMSS()); + //tcb.SND.cwnd += std::min(length, tcp.SMSS()); debug2(" Advanced RCV.NXT: %u. SND.NXT = %u \n", tcb.RCV.NXT, snd_nxt); + auto packet = tcp.outgoing_packet(); + packet->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); + tcp.transmit(packet); + if(tcp.has_doable_job() and !tcp.is_queued()) { + debug2(" Usable window: %i\n", tcp.usable_window()); + tcp.write_queue_push(); + } /* WARNING/NOTE: @@ -365,7 +373,7 @@ void Connection::State::process_segment(Connection& tcp, TCP::Packet_ptr in) { */ // no data has been sent during user callback // TODO: A lot of cleanup / refactoring - this is messy. - if(snd_nxt == tcb.SND.NXT) { + /*if(snd_nxt == tcb.SND.NXT) { // Piggyback ACK with outgoing data if(tcp.has_doable_job() and !tcp.is_queued()) { debug2(" Usable window: %i\n", tcp.usable_window()); @@ -389,7 +397,7 @@ void Connection::State::process_segment(Connection& tcp, TCP::Packet_ptr in) { } else { debug2(" SND.NXT > snd_nxt, this packet has already been acknowledged. \n"); - } + }*/ } ///////////////////////////////////////////////////////////////////// @@ -504,8 +512,7 @@ void Connection::Closed::open(Connection& tcp, bool active) { // There is a remote host if(!tcp.remote().is_empty()) { auto& tcb = tcp.tcb(); - tcb.ISS = tcp.generate_iss(); - tcb.SND.recover = tcb.ISS; // [RFC 6582] + tcb.init(); auto packet = tcp.outgoing_packet(); packet->set_seq(tcb.ISS).set_flag(SYN); @@ -529,8 +536,7 @@ void Connection::Closed::open(Connection& tcp, bool active) { void Connection::Listen::open(Connection& tcp, bool) { if(!tcp.remote().is_empty()) { auto& tcb = tcp.tcb(); - tcb.ISS = tcp.generate_iss(); - tcb.SND.recover = tcb.ISS; // [RFC 6582] + tcb.init(); auto packet = tcp.outgoing_packet(); packet->set_seq(tcb.ISS).set_flag(SYN); tcb.SND.UNA = tcb.ISS; @@ -806,8 +812,7 @@ State::Result Connection::Listen::handle(Connection& tcp, TCP::Packet_ptr in) { auto& tcb = tcp.tcb(); tcb.RCV.NXT = in->seq()+1; tcb.IRS = in->seq(); - tcb.ISS = tcp.generate_iss(); - tcb.SND.recover = tcb.ISS; // [RFC 6582] + tcb.init(); tcb.SND.NXT = tcb.ISS+1; tcb.SND.UNA = tcb.ISS; debug(" Received SYN Packet: %s TCB Updated:\n %s \n", From 2744dc73b754b23366cee0b1e5c8bd68ee41dc1d Mon Sep 17 00:00:00 2001 From: RicoAntonioFelix Date: Mon, 18 Apr 2016 10:49:14 -0400 Subject: [PATCH 179/311] Minor changes to MemDisk... --- api/fs/memdisk.hpp | 6 +++--- src/fs/memdisk.cpp | 22 +++++++++++----------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/api/fs/memdisk.hpp b/api/fs/memdisk.hpp index d11b4557f3..864cf9e095 100644 --- a/api/fs/memdisk.hpp +++ b/api/fs/memdisk.hpp @@ -29,7 +29,7 @@ namespace fs { public: static constexpr size_t SECTOR_SIZE = 512; - MemDisk() noexcept; + explicit MemDisk() noexcept; virtual const char* name() const noexcept override { return "MemDisk"; } @@ -49,8 +49,8 @@ namespace fs { virtual buffer_t read_sync(block_t blk) override; private: - const char* image_start_; - const char* image_end_; + const char* const image_start_; + const char* const image_end_; }; //< class MemDisk } //< namespace fs diff --git a/src/fs/memdisk.cpp b/src/fs/memdisk.cpp index 2d5619f06e..898c99a793 100644 --- a/src/fs/memdisk.cpp +++ b/src/fs/memdisk.cpp @@ -15,10 +15,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include -#include #include +#include +#include #include #define likely(x) __builtin_expect(!!(x), 1) @@ -40,13 +40,13 @@ namespace fs { auto sector_loc = image_start_ + (blk * block_size()); // Disallow reading memory past disk image if (unlikely(sector_loc >= image_end_)) { - reader(buffer_t()); return; + reader(buffer_t{}); return; } auto buffer = new uint8_t[block_size()]; - assert( memcpy(buffer, sector_loc, block_size()) == buffer ); + Ensures( memcpy(buffer, sector_loc, block_size()) == buffer ); - reader( buffer_t(buffer, std::default_delete()) ); + reader( buffer_t{buffer, std::default_delete()} ); } void MemDisk::read(block_t blk, block_t count, on_read_func reader) { @@ -54,25 +54,25 @@ namespace fs { auto end_loc = start_loc + (count * block_size()); // Disallow reading memory past disk image if (unlikely(end_loc >= image_end_)) { - reader(buffer_t()); return; + reader(buffer_t{}); return; } auto buffer = new uint8_t[count * block_size()]; - assert( memcpy(buffer, start_loc, count * block_size()) == buffer ); + Ensures( memcpy(buffer, start_loc, count * block_size()) == buffer ); - reader( buffer_t(buffer, std::default_delete()) ); + reader( buffer_t{buffer, std::default_delete()} ); } MemDisk::buffer_t MemDisk::read_sync(block_t blk) { auto sector_loc = image_start_ + (blk * block_size()); // Disallow reading memory past disk image if (unlikely(sector_loc >= image_end_)) - return buffer_t(); + return buffer_t{}; auto buffer = new uint8_t[block_size()]; - assert( memcpy(buffer, sector_loc, block_size()) == buffer ); + Ensures( memcpy(buffer, sector_loc, block_size()) == buffer ); - return buffer_t(buffer, std::default_delete()); + return buffer_t{buffer, std::default_delete()}; } MemDisk::block_t MemDisk::size() const noexcept { From 9d927bcb1a95aef3b5dc930bd15b51b738353168 Mon Sep 17 00:00:00 2001 From: RicoAntonioFelix Date: Mon, 18 Apr 2016 11:13:21 -0400 Subject: [PATCH 180/311] Add build option to enable contracts... --- src/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index d8d8cc26ba..3d2db239be 100644 --- a/src/Makefile +++ b/src/Makefile @@ -12,7 +12,7 @@ INSTALL = $(INCLUDEOS_INSTALL) # stackrealign is needed to guarantee 16-byte stack alignment for SSE # the compiler seems to be really dumb in this regard, creating a misaligned stack left and right CAPABS_COMMON = -mstackrealign -msse3 -CAPABS = $(CAPABS_COMMON) -O2 -DNO_DEBUG=1 +CAPABS = $(CAPABS_COMMON) -O2 -DNO_DEBUG=1 -DOS_TERMINATE_ON_CONTRACT_VIOLATION WARNS = -Wall -Wextra #-pedantic DEBUG_OPTS = -ggdb3 From 5a1fe58bbdacd4dfc44f7c8fc1f1327158eb7101 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 19 Apr 2016 09:56:37 +0200 Subject: [PATCH 181/311] Fixed adding drives to VM JSONs --- test/virtio_block/vm.json | 6 ++++-- test/vm.schema.json | 3 ++- test/vmrunner.py | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/test/virtio_block/vm.json b/test/virtio_block/vm.json index 820312c0ff..07b9763598 100644 --- a/test/virtio_block/vm.json +++ b/test/virtio_block/vm.json @@ -1,4 +1,6 @@ { - "image" : "test_STL.img", - "drive" : [{"file" : "test.txt", "type" : "virtio" }] + "image" : "test_virtio_block.img", + "drives" : [{"file" : "test.txt", + "type" : "virtio", + "format": "raw" }] } diff --git a/test/vm.schema.json b/test/vm.schema.json index c2ec0e780f..a9753455ef 100644 --- a/test/vm.schema.json +++ b/test/vm.schema.json @@ -20,10 +20,11 @@ "properties" : { "file" : { "type" : "string" }, "type" : { "enum" : ["ide", "virtio"] }, + "format" : { "enum" : ["raw", "qcow2", "vdi"] }, "name" : { "type" : "string" } }, - "required" : ["file"] + "required" : ["file", "format", "type"] } }, diff --git a/test/vmrunner.py b/test/vmrunner.py index 762de4affc..3b3dda160d 100644 --- a/test/vmrunner.py +++ b/test/vmrunner.py @@ -80,7 +80,7 @@ def boot(self): disk_args = self.drive_arg(self._vm["image"], "ide") if self._vm.has_key("drives"): for disk in self._vm["drives"]: - disk_args += drive_arg(disk["file"], disk["type"], disk["format"]) + disk_args += self.drive_arg(disk["file"], disk["type"], disk["format"]) net_args = [] i = 0 @@ -159,7 +159,7 @@ def boot(self, timeout = None): try: self._hyper.boot() except Exception as err: - self._timer.cancel() + if (timeout): self._timer.cancel() raise err #self.exit(1, err) From ba28bb3c4d895df0b4262fd2ab93f2981e18f44a Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 19 Apr 2016 09:57:50 +0200 Subject: [PATCH 182/311] Changed virtio tokens to contain direction --- api/virtio/virtio.hpp | 34 ++++++++++++++++++++++++---------- src/virtio/block.cpp | 20 ++++++++------------ src/virtio/virtio_queue.cpp | 8 ++++---- src/virtio/virtionet.cpp | 30 +++++++++++++++++------------- 4 files changed, 53 insertions(+), 39 deletions(-) diff --git a/api/virtio/virtio.hpp b/api/virtio/virtio.hpp index 3166b90a5a..ca964dd7f9 100644 --- a/api/virtio/virtio.hpp +++ b/api/virtio/virtio.hpp @@ -67,10 +67,29 @@ class Virtio { public: + + /** A wrapper for buffers to be passed in to the Queue */ - struct Token { - uint8_t* data; - size_t size; + class Token { + + public: + // "Direction" of tokens + using span = gsl::span; + using size_type = span::size_type; + enum Direction { IN, OUT }; + inline Token(span buf, Direction d) : + data_{ buf.data() }, size_{ buf.size() }, dir_{ d } + {} + + inline auto data() { return data_; } + inline auto size() { return size_; } + inline auto direction() { return dir_; } + + + private: + uint8_t* data_; + size_type size_; + Direction dir_; }; // http://docs.oasis-open.org/virtio/virtio/v1.0/csprd01/virtio-v1.0-csprd01.html#x1-860005 @@ -96,10 +115,6 @@ class Virtio class Queue { - public: - // "Direction" of tokens - enum Direction { IN, OUT }; - private: /** @note Using typedefs in order to keep the standard notation. */ @@ -218,10 +233,9 @@ class Virtio virtq_desc* queue_desc() const { return _queue.desc; } /** Push data tokens onto the queue. - @param buffers : A span of buffers - @param out : true if the buffers are device readable, otherwise false + @param buffers : A span of tokens */ - int enqueue(gsl::span buffers, bool out); + int enqueue(gsl::span buffers); /** Dequeue a received packet. From SanOS */ uint8_t* dequeue(uint32_t* len); diff --git a/src/virtio/block.cpp b/src/virtio/block.cpp index 59004520d1..45103c51c8 100644 --- a/src/virtio/block.cpp +++ b/src/virtio/block.cpp @@ -172,18 +172,14 @@ void VirtioBlk::read (block_t blk, on_read_func func) printf("Enqueue handler: %p, total: %u\n", &vbr->io.handler, sizeof(request_t)); // - std::array tout; - std::array tin; - - tout[0].data = (uint8_t*) &vbr->hdr; - tout[0].size = sizeof(scsi_header_t); - tin[0].data = (uint8_t*) &vbr->io; - tin[0].size = sizeof(blk_io_t); - tin[1].data = (uint8_t*) &vbr->resp; - tin[1].size = sizeof(blk_resp_t); - - req.enqueue(tout, Virtio::Queue::Direction::OUT); - req.enqueue(tin, Virtio::Queue::Direction::IN); + + Token token1 { { (uint8_t*) &vbr->hdr, sizeof(scsi_header_t) }, Token::OUT }; + Token token2 { { (uint8_t*) &vbr->io, sizeof(blk_io_t) }, Token::IN }; + Token token3 { { (uint8_t*) &vbr->resp, sizeof(blk_resp_t) }, Token::IN }; + + std::array tokens {{ token1, token2, token3 }}; + + req.enqueue(tokens); req.kick(); } diff --git a/src/virtio/virtio_queue.cpp b/src/virtio/virtio_queue.cpp index df5da58217..94b2a03609 100644 --- a/src/virtio/virtio_queue.cpp +++ b/src/virtio/virtio_queue.cpp @@ -93,7 +93,7 @@ Virtio::Queue::Queue(uint16_t size, uint16_t q_index, uint16_t iobase) /** Ported more or less directly from SanOS. */ -int Virtio::Queue::enqueue(gsl::span buffers, bool out){ +int Virtio::Queue::enqueue(gsl::span buffers){ debug ("Enqueuing %i tokens \n", buffers.size()); Expects(_free_head >= 0); Expects(_free_head < size()); @@ -107,11 +107,11 @@ int Virtio::Queue::enqueue(gsl::span buffers, bool out){ // Set read / write flags _queue.desc[_free_head].flags = - out ? VIRTQ_DESC_F_NEXT : VIRTQ_DESC_F_NEXT | VIRTQ_DESC_F_WRITE; + buf.direction() ? VIRTQ_DESC_F_NEXT : VIRTQ_DESC_F_NEXT | VIRTQ_DESC_F_WRITE; // Assign raw buffer - _queue.desc[_free_head].addr = (uint64_t) buf.data; - _queue.desc[_free_head].len = buf.size; + _queue.desc[_free_head].addr = (uint64_t) buf.data(); + _queue.desc[_free_head].len = buf.size(); last = _free_head; _free_head ++; diff --git a/src/virtio/virtionet.cpp b/src/virtio/virtionet.cpp index f83598d198..8a98cf3585 100644 --- a/src/virtio/virtionet.cpp +++ b/src/virtio/virtionet.cpp @@ -168,13 +168,17 @@ int VirtioNet::add_receive_buffer(){ debug2(" Added receive-bufer @ 0x%x \n", (uint32_t)buf); - std::array tokens; - tokens[0].data = buf; - tokens[0].size = sizeof(virtio_net_hdr); - tokens[1].data = buf + sizeof(virtio_net_hdr); - tokens[1].size = bufsize() - sizeof(virtio_net_hdr); + Token token1 { + {buf, sizeof(virtio_net_hdr)}, + Token::IN }; - rx_q.enqueue(tokens, Virtio::Queue::Direction::IN); + Token token2 { + {buf + sizeof(virtio_net_hdr), (Token::size_type) (bufsize() - sizeof(virtio_net_hdr))}, + Token::IN }; + + std::array tokens {{ token1, token2 }}; + + rx_q.enqueue(tokens); return 0; } @@ -357,16 +361,16 @@ void VirtioNet::transmit(net::Packet_ptr pckt){ void VirtioNet::enqueue(net::Packet_ptr pckt){ - // A scatterlist for virtio-header + data - std::array tokens; // This setup requires all tokens to be pre-chained like in SanOS - tokens[0].data = (uint8_t*) &empty_header; - tokens[0].size = sizeof(virtio_net_hdr); - tokens[1].data = pckt->buffer(); - tokens[1].size = pckt->size(); + Token token1 {{(uint8_t*) &empty_header, sizeof(virtio_net_hdr)}, + Token::OUT }; + + Token token2 { {pckt->buffer(), (Token::size_type) pckt->size() }, Token::OUT }; + + std::array tokens { token1, token2 }; // Enqueue scatterlist, 2 pieces readable, 0 writable. - tx_q.enqueue(tokens, Virtio::Queue::Direction::OUT); + tx_q.enqueue(tokens); } From dd6655addb97500e04d0aa7e48f1b7aaf2693ab7 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 19 Apr 2016 10:54:42 +0200 Subject: [PATCH 183/311] Supressed unused param warning in _exit --- src/kernel/syscalls.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/kernel/syscalls.cpp b/src/kernel/syscalls.cpp index 78dd4c495f..4c8570b4f0 100644 --- a/src/kernel/syscalls.cpp +++ b/src/kernel/syscalls.cpp @@ -34,6 +34,7 @@ static bool debug_syscalls {true}; caddr_t heap_end; void _exit(int status) { + (void) status; panic("Exit called"); } From ba6f316ddaaee1c15e3f424e9b2fcb58e497d0b0 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 19 Apr 2016 10:55:10 +0200 Subject: [PATCH 184/311] Changed Virtio::Queue::dequeue to return span --- api/virtio/virtio.hpp | 4 ++-- src/virtio/block.cpp | 7 ++++++- src/virtio/virtio_queue.cpp | 9 ++++----- src/virtio/virtionet.cpp | 12 +++++++----- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/api/virtio/virtio.hpp b/api/virtio/virtio.hpp index ca964dd7f9..79bd3b5ff3 100644 --- a/api/virtio/virtio.hpp +++ b/api/virtio/virtio.hpp @@ -237,8 +237,8 @@ class Virtio */ int enqueue(gsl::span buffers); - /** Dequeue a received packet. From SanOS */ - uint8_t* dequeue(uint32_t* len); + /** Dequeue a received packet */ + gsl::span dequeue(); void disable_interrupts(); void enable_interrupts(); diff --git a/src/virtio/block.cpp b/src/virtio/block.cpp index 45103c51c8..1587782014 100644 --- a/src/virtio/block.cpp +++ b/src/virtio/block.cpp @@ -131,12 +131,16 @@ void VirtioBlk::service_RX() uint32_t received = 0; uint32_t len; request_t* hdr; + gsl::span res; - while ((hdr = (request_t*) req.dequeue(&len)) != nullptr) + while ( (res = req.dequeue()).data() != nullptr ) { + //&printf("service_RX() received %u bytes for sector %llu\n", // len, hdr->hdr.sector); // + hdr = (request_t*) res.data(); + len = res.size(); blk_resp_t* resp = &hdr->resp; printf("blk response: %u\n", resp->status); @@ -150,6 +154,7 @@ void VirtioBlk::service_RX() received++; } + if (received == 0) { //printf("service_RX() error processing requests\n"); diff --git a/src/virtio/virtio_queue.cpp b/src/virtio/virtio_queue.cpp index 94b2a03609..5f69c753b6 100644 --- a/src/virtio/virtio_queue.cpp +++ b/src/virtio/virtio_queue.cpp @@ -149,26 +149,25 @@ void Virtio::Queue::release(uint32_t head) debug2(" desc[%i].next : %i \n",_pci_index,i,_queue.desc[i].next); } -uint8_t* Virtio::Queue::dequeue(uint32_t* len){ +gsl::span Virtio::Queue::dequeue(){ // Return NULL if there are no more completed buffers in the queue if (_last_used_idx == _queue.used->idx){ debug(" Can't dequeue - no used buffers \n",_pci_index); - return NULL; + return nullptr; + } // Get next completed buffer auto* e = &_queue.used->ring[_last_used_idx % _size]; - *len = e->len; debug2(" Releasing token %li. Len: %li\n",_pci_index,e->id, e->len); - uint8_t* data = (uint8_t*)_queue.desc[e->id].addr; // Release buffer release(e->id); _last_used_idx++; - return data; + return {(char*) _queue.desc[e->id].addr, (gsl::span::size_type) e->len }; } void Virtio::Queue::set_data_handler(delegate del){ diff --git a/src/virtio/virtionet.cpp b/src/virtio/virtionet.cpp index 8a98cf3585..d037b7def9 100644 --- a/src/virtio/virtionet.cpp +++ b/src/virtio/virtionet.cpp @@ -235,12 +235,14 @@ void VirtioNet::service_queues(){ // Do one RX-packet if (rx_q.new_incoming() ){ - data = rx_q.dequeue(&len); //BUG # 102? + sizeof(virtio_net_hdr); + auto res = rx_q.dequeue(); //BUG # 102? + sizeof(virtio_net_hdr); + data = (uint8_t*) res.data(); + len += res.size(); auto pckt_ptr = std::make_shared - (data+sizeof(virtio_net_hdr), // Offset buffer (bufstore knows the offseto) + (data + sizeof(virtio_net_hdr), // Offset buffer (bufstore knows the offseto) bufsize()-sizeof(virtio_net_hdr), // Capacity - len - sizeof(virtio_net_hdr), release_buffer); // Size + res.size() - sizeof(virtio_net_hdr), release_buffer); // Size _link_out(pckt_ptr); @@ -254,7 +256,7 @@ void VirtioNet::service_queues(){ // Do one TX-packet if (tx_q.new_incoming()){ debug2(" Dequeing TX"); - tx_q.dequeue(&len); + tx_q.dequeue(); dequeued_tx++; } @@ -368,7 +370,7 @@ void VirtioNet::enqueue(net::Packet_ptr pckt){ Token token2 { {pckt->buffer(), (Token::size_type) pckt->size() }, Token::OUT }; - std::array tokens { token1, token2 }; + std::array tokens {{ token1, token2 }}; // Enqueue scatterlist, 2 pieces readable, 0 writable. tx_q.enqueue(tokens); From 3eee9861c59a19a47b454cf9c9b503b667f0339b Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Tue, 19 Apr 2016 11:04:49 +0200 Subject: [PATCH 185/311] virtioblk: Moved handler --- api/virtio/block.hpp | 9 ++++---- src/virtio/block.cpp | 52 ++++++++++++++++++++------------------------ 2 files changed, 28 insertions(+), 33 deletions(-) diff --git a/api/virtio/block.hpp b/api/virtio/block.hpp index aca86ae3ff..f552e064ad 100644 --- a/api/virtio/block.hpp +++ b/api/virtio/block.hpp @@ -87,14 +87,13 @@ class VirtioBlk : public Virtio, public hw::IDiskDevice uint32_t ioprio; uint64_t sector; }; - struct blk_resp_t - { - uint8_t status; - }; - struct blk_io_t { uint8_t sector[512]; + }; + struct blk_resp_t + { + uint8_t status; on_read_func handler; }; diff --git a/src/virtio/block.cpp b/src/virtio/block.cpp index 1587782014..77435e12d3 100644 --- a/src/virtio/block.cpp +++ b/src/virtio/block.cpp @@ -133,33 +133,29 @@ void VirtioBlk::service_RX() request_t* hdr; gsl::span res; - while ( (res = req.dequeue()).data() != nullptr ) - { - - //&printf("service_RX() received %u bytes for sector %llu\n", - // len, hdr->hdr.sector); - // - hdr = (request_t*) res.data(); - len = res.size(); - blk_resp_t* resp = &hdr->resp; - printf("blk response: %u\n", resp->status); - - uint8_t* copy = new uint8_t[SECTOR_SIZE]; - memcpy(copy, hdr->io.sector, SECTOR_SIZE); - auto buf = buffer_t(copy, std::default_delete()); - - printf("STATUS: [%u]\nCalling handler: %p\n", - resp->status, &hdr->io.handler); - hdr->io.handler(buf); - - received++; - } - + while ((res = req.dequeue()).data() != nullptr) + { + //&printf("service_RX() received %u bytes for sector %llu\n", + // len, hdr->hdr.sector); + // + hdr = (request_t*) res.data(); + len = res.size(); + blk_resp_t* resp = &hdr->resp; + printf("blk response: %u\n", resp->status); + + uint8_t* copy = new uint8_t[SECTOR_SIZE]; + memcpy(copy, hdr->io.sector, SECTOR_SIZE); + auto buf = buffer_t(copy, std::default_delete()); + + printf("STATUS: [%u]\nCalling handler: %p\n", + resp->status, &hdr->resp.handler); + hdr->resp.handler(buf); + received++; + } if (received == 0) - { - //printf("service_RX() error processing requests\n"); - } - + { + printf("service_RX() error processing requests\n"); + } req.enable_interrupts(); } @@ -171,11 +167,11 @@ void VirtioBlk::read (block_t blk, on_read_func func) vbr->hdr.type = VIRTIO_BLK_T_IN; vbr->hdr.ioprio = 0; vbr->hdr.sector = blk; - vbr->io.handler = func; vbr->resp.status = VIRTIO_BLK_S_IOERR; + vbr->resp.handler = func; printf("Enqueue handler: %p, total: %u\n", - &vbr->io.handler, sizeof(request_t)); + &vbr->resp.handler, sizeof(request_t)); // Token token1 { { (uint8_t*) &vbr->hdr, sizeof(scsi_header_t) }, Token::OUT }; From 6dfe129f9fa82cf5c8412c574b8ca8e15aff47b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Tue, 19 Apr 2016 15:40:23 +0200 Subject: [PATCH 186/311] tcp: some paddling with fast retransmit.. --- api/net/tcp.hpp | 21 +++++++++--- src/net/tcp.cpp | 6 ++-- src/net/tcp_connection.cpp | 57 ++++++++++++++++++++++++++----- src/net/tcp_connection_states.cpp | 26 +++++--------- test/tcp/vbox.sh | 2 +- 5 files changed, 78 insertions(+), 34 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index 477d57ca67..6df5ca9304 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -1308,7 +1308,7 @@ namespace net { Active try to send a buffer by asking the TCP. */ inline size_t send(WriteBuffer& buffer) { - return host_.send(shared_from_this(), buffer); + return host_.send(shared_from_this(), buffer, buffer.remaining); } /* @@ -1317,8 +1317,8 @@ namespace net { */ size_t send(const char* buffer, size_t remaining, size_t& packets, bool PUSH); - inline size_t send(WriteBuffer& buffer, size_t& packets) { - return send((char*)buffer.pos(), buffer.remaining, packets, buffer.push); + inline size_t send(WriteBuffer& buffer, size_t& packets, size_t n) { + return send((char*)buffer.pos(), n, packets, buffer.push); } /* @@ -1385,6 +1385,13 @@ namespace net { inline void drop(TCP::Packet_ptr packet) { drop(packet, "None given."); } + // RFC 3042 + void limited_tx(); + inline void try_limited_tx() { + if( (send_window() > 0) and ( (flight_size() + 2*SMSS() ) <= control_block.SND.cwnd) ) + limited_tx(); + } + /// TCB HANDLING /// /* @@ -1496,7 +1503,10 @@ namespace net { } inline void reno_dup_ack(Seq ACK) { - if(++DUP_ACK == 3) { + if(++DUP_ACK < 3) { + if(!write_queue.empty()) + try_limited_tx(); + } else if(DUP_ACK == 3) { printf(" Duplicate ACK - Strike 3!\n"); if(reno_should_recover(ACK)) { reno_update_recover(); @@ -1504,6 +1514,7 @@ namespace net { } } else if(DUP_ACK > 3) { control_block.SND.cwnd += SMSS(); + try_limited_tx(); } } @@ -1819,7 +1830,7 @@ namespace net { Ask to send a Connection's WriteBuffer. If there is no free packets, the job will be queued. */ - size_t send(Connection_ptr, Connection::WriteBuffer&); + size_t send(Connection_ptr, Connection::WriteBuffer&, size_t n); /* Force the TCP to process the it's queue with the current amount of available packets. diff --git a/src/net/tcp.cpp b/src/net/tcp.cpp index e101de5e31..1d0bd120c1 100644 --- a/src/net/tcp.cpp +++ b/src/net/tcp.cpp @@ -204,12 +204,12 @@ void TCP::process_write_queue(size_t packets) { } } -size_t TCP::send(Connection_ptr conn, Connection::WriteBuffer& buffer) { +size_t TCP::send(Connection_ptr conn, Connection::WriteBuffer& buffer, size_t n) { size_t written{0}; - if(write_queue.empty()) { + if(write_queue.empty() and inet_.transmit_queue_available()) { auto packets = inet_.transmit_queue_available(); - written = conn->send(buffer, packets); + written = conn->send(buffer, packets, n); } if(written < buffer.remaining and !conn->is_queued()) { diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index 68a83ec864..2642d860ce 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -121,10 +121,10 @@ bool Connection::offer(size_t& packets) { debug(" %s got offered [%u] packets. Usable window is %i.\n", to_string().c_str(), packets, usable_window()); - while(has_doable_job() and packets) { + while(has_doable_job() and packets and !reno_is_fast_recovering()) { auto& buf = write_queue.front().first; // segmentize the buffer into packets - auto written = send(buf, packets); + auto written = send(buf, packets, buf.remaining); // advance the buffer buf.advance(written); debug2(" Wrote %u bytes (%u remaining) with [%u] packets left and a usable window of %i.\n", @@ -140,12 +140,13 @@ bool Connection::offer(size_t& packets) { assert(packets >= 0); debug(" Finished working offer with [%u] packets left and a queue of (%u) with a usable window of %i\n", packets, write_queue.size(), usable_window()); - return !has_doable_job(); + return !has_doable_job() or reno_is_fast_recovering(); } // TODO: This is starting to get complex and ineffective, refactor.. size_t Connection::send(const char* buffer, size_t remaining, size_t& packet_count, bool PUSH) { - assert(packet_count && remaining); + assert(packet_count); + assert(remaining); size_t bytes_written{0}; while(remaining and packet_count and usable_window() >= SMSS()) { @@ -195,6 +196,17 @@ void Connection::write_queue_push() { } } +void Connection::limited_tx() { + auto& buf = write_queue.front().first; + auto written = host_.send(shared_from_this(),buf, std::min(buf.remaining, (uint32_t)RMSS())); + printf(" Limited transmit. %u written\n", written); + buf.advance(written); + if(buf.remaining) + return; + write_queue.front().second(buf.offset); + write_queue.pop(); +} + void Connection::write_queue_reset() { while(!write_queue.empty()) { auto& job = write_queue.front(); @@ -312,6 +324,34 @@ void Connection::transmit(TCP::Packet_ptr packet) { rt_start(); } +/*void Connection::acknowledge(TCP::Packet_ptr in) { + // ACK is inside + if(in->ack() <= control_block.SND.NXT) { + // new ACK + if(in->ack() > control_block.SND.UNA) { + size_t bytes_acked = in->ack() - control_block.SND.UNA; + control_block.SND.UNA = in->ack(); + if(DUP_ACK >= DUP) { + + } + } + // Duplicate ACK + else if(in->ack() == control_block.SND.UNA) { + in->has_data() and + DUP_ACK++ + } + // old ACK + else { + + } + + } + // ACK outside + else { + + } +}*/ + /* As specified in [RFC3390], the SYN/ACK and the acknowledgment of the SYN/ACK MUST NOT increase the size of the congestion window. @@ -324,6 +364,8 @@ void Connection::acknowledge(Seq ACK) { size_t bytes_acked = ACK - control_block.SND.UNA; control_block.SND.UNA = ACK; + rt_ack_queue(ACK); + reno_update_heuristic_ack(ACK); if(!reno_is_fast_recovering()) { if(reno_slow_start()) { @@ -348,6 +390,8 @@ void Connection::acknowledge(Seq ACK) { } // partial acknowledgement else { + //fast_rtx(); + retransmit(); reno_deflate_cwnd(bytes_acked); if(RENO_FPACK_NOT_SEEN) { printf(" #1 Partial ACK - %u, Cwnd: %u\n", ACK, control_block.SND.cwnd); @@ -356,15 +400,12 @@ void Connection::acknowledge(Seq ACK) { } else { //printf(" Partial ACK - %u, Cwnd: %u\n", ACK, control_block.SND.cwnd); } + try_limited_tx(); } } - /**/ - if(rttm.active) rttm.stop(); - - rt_ack_queue(ACK); } /* diff --git a/src/net/tcp_connection_states.cpp b/src/net/tcp_connection_states.cpp index 0269b4bd72..75a8bee871 100644 --- a/src/net/tcp_connection_states.cpp +++ b/src/net/tcp_connection_states.cpp @@ -221,12 +221,18 @@ bool Connection::State::check_ack(Connection& tcp, TCP::Packet_ptr in) { updated. If (SND.WL1 < SEG.SEQ or (SND.WL1 = SEG.SEQ and SND.WL2 =< SEG.ACK)), set SND.WND <- SEG.WND, set SND.WL1 <- SEG.SEQ, and set SND.WL2 <- SEG.ACK. + + Note that SND.WND is an offset from SND.UNA, that SND.WL1 + records the sequence number of the last segment used to update + SND.WND, and that SND.WL2 records the acknowledgment number of + the last segment used to update SND.WND. The check here + prevents using old segments to update the window. */ if( tcb.SND.WL1 < in->seq() or ( tcb.SND.WL1 = in->seq() and tcb.SND.WL2 <= in->ack() ) ) { tcb.SND.WND = in->win(); tcb.SND.WL1 = in->seq(); tcb.SND.WL2 = in->ack(); - debug2(" Send window updated: %u \n", tcb.SND.WND); + debug2(" Usable window slided (%i)\n", tcp.usable_window()); } // this is a NEW ACK @@ -261,27 +267,13 @@ bool Connection::State::check_ack(Connection& tcp, TCP::Packet_ptr in) { else { //printf(" RFC 793 Dup ACK %u\n", in->ack()); } - - } - // this is an ACK out of order + // this is an "old" ACK out of order else { - + printf(" ACK out of order (SND.UNA > ACK)\n"); } - - debug2(" Usable window slided (%i) %u\n", tcp.usable_window(), tcb.SND.cwnd); // tcp.signal_sent(); // return that buffer has been SENT - currently no support to receipt sent buffer. - - - /* - Note that SND.WND is an offset from SND.UNA, that SND.WL1 - records the sequence number of the last segment used to update - SND.WND, and that SND.WL2 records the acknowledgment number of - the last segment used to update SND.WND. The check here - prevents using old segments to update the window. - */ - } /* If the ACK acks something not yet sent (SEG.ACK > SND.NXT) then send an ACK, drop the segment, and return. */ else { diff --git a/test/tcp/vbox.sh b/test/tcp/vbox.sh index d51622d5f7..9d9444da8c 100755 --- a/test/tcp/vbox.sh +++ b/test/tcp/vbox.sh @@ -1,2 +1,2 @@ #!/bin/bash -../../etc/vboxrun.sh IncludeOS_TCP_Test.img TCP_test \ No newline at end of file +../../etc/vboxrun.sh test_tcp.img TCP_test From 3352b421119e92b23e82f994aee1d25ca7875a37 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 19 Apr 2016 15:40:29 +0200 Subject: [PATCH 187/311] Added missing dependencies for new Expects / Ensures --- api/common | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/api/common b/api/common index 1a61de8236..5ebb70d409 100644 --- a/api/common +++ b/api/common @@ -60,11 +60,16 @@ /* the reason for termination. */ #if defined(OS_TERMINATE_ON_CONTRACT_VIOLATION) +#include // Needed for std::exit +#include // Needed for std::err #define OS_STRINGIFY(x) #x /* Function used to set termination behaviour */ inline void expects_and_ensures_termination() { std::exit(EXIT_FAILURE); } +#undef Expects +#undef Ensures + #define Expects(cond) \ do { \ if (not (cond)) { \ From e9c27cdc5a721604f07c5f5ca0a3fe930abb34b3 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 19 Apr 2016 16:20:49 +0200 Subject: [PATCH 188/311] Fixed include of common --- src/fs/memdisk.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fs/memdisk.cpp b/src/fs/memdisk.cpp index 898c99a793..b4b5ac679f 100644 --- a/src/fs/memdisk.cpp +++ b/src/fs/memdisk.cpp @@ -18,7 +18,7 @@ #include #include -#include +#include #include #define likely(x) __builtin_expect(!!(x), 1) From fa13a2e5458f08c3b7d5fff37292c431a0d15f48 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Tue, 19 Apr 2016 17:28:20 +0200 Subject: [PATCH 189/311] link: Align ctor/dtor, disable SSE --- api/net/ip6/ip6.hpp | 39 ++++++++++++++++++++++++++------------- src/Makefile | 7 +++---- src/crt/c_abi.c | 13 ++++++++++--- src/linker.ld | 23 +++++++++++++++-------- 4 files changed, 54 insertions(+), 28 deletions(-) diff --git a/api/net/ip6/ip6.hpp b/api/net/ip6/ip6.hpp index e159208e8a..031ddd2b35 100644 --- a/api/net/ip6/ip6.hpp +++ b/api/net/ip6/ip6.hpp @@ -63,23 +63,32 @@ namespace net addr(uint16_t a1, uint16_t a2, uint16_t b1, uint16_t b2, uint16_t c1, uint16_t c2, uint16_t d1, uint16_t d2) { - i128 = _mm_set_epi16( - //d2, d1, c2, c1, b2, b1, a2, a1); - htons(d2), htons(d1), - htons(c2), htons(c1), - htons(b2), htons(b1), - htons(a2), htons(a1)); + i16[0] = a1; i16[1] = a2; + i16[2] = b1; i16[3] = b2; + i16[4] = c1; i16[5] = c2; + i16[6] = d1; i16[7] = d2; + /*i128 = _mm_set_epi16( + htons(d2), htons(d1), + htons(c2), htons(c1), + htons(b2), htons(b1), + htons(a2), htons(a1));*/ } addr(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { - i128 = _mm_set_epi32(d, c, b, a); + i32[0] = a; i32[1] = b; i32[2] = c; i32[3] = d; + //i128 = _mm_set_epi32(d, c, b, a); } addr(const addr& a) - : i128(a.i128) {} + { + for (int i = 0; i < 4; i++) + i32[i] = a.i32[i]; + } // move constructor addr& operator= (const addr& a) { - i128 = a.i128; + for (int i = 0; i < 4; i++) + i32[i] = a.i32[i]; + //i128 = a.i128; return *this; } @@ -87,8 +96,11 @@ namespace net bool operator== (const addr& a) const { // i128 == a.i128: - __m128i cmp = _mm_cmpeq_epi32(i128, a.i128); - return _mm_cvtsi128_si32(cmp); + for (int i = 0; i < 4; i++) + if (i32[i] != a.i32[i]) return false; + return true; + //__m128i cmp = _mm_cmpeq_epi32(i128, a.i128); + //return _mm_cvtsi128_si32(cmp); } bool operator!= (const addr& a) const { @@ -136,11 +148,12 @@ namespace net union { - __m128i i128; + //__m128i i128; uint32_t i32[ 4]; + uint16_t i16[ 8]; uint8_t i8[16]; }; - } __attribute__((aligned(alignof(__m128i)))); + }; #pragma pack(push, 1) class header diff --git a/src/Makefile b/src/Makefile index d8d8cc26ba..b4027f5e4e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -11,7 +11,7 @@ INSTALL = $(INCLUDEOS_INSTALL) # stackrealign is needed to guarantee 16-byte stack alignment for SSE # the compiler seems to be really dumb in this regard, creating a misaligned stack left and right -CAPABS_COMMON = -mstackrealign -msse3 +CAPABS_COMMON = -mstackrealign -mno-sse CAPABS = $(CAPABS_COMMON) -O2 -DNO_DEBUG=1 WARNS = -Wall -Wextra #-pedantic DEBUG_OPTS = -ggdb3 @@ -58,12 +58,11 @@ LDOPTS = -nostdlib -melf_i386 -N --eh-frame-hdr --script=linker.ld #-flto CXXABI = $(shell find ./crt/cxxabi -type f -name "*.cpp") CXXABI_OBJ = $(CXXABI:.cpp=.o) -OS_OBJECTS = kernel/kernel_start.o kernel/syscalls.o kernel/vga.o \ +OS_OBJECTS = kernel/kernel_start.o kernel/syscalls.o \ kernel/interrupts.o kernel/os.o kernel/cpuid.o \ kernel/irq_manager.o kernel/pci_manager.o \ kernel/terminal.o kernel/terminal_disk.o \ crt/c_abi.o crt/string.o crt/quick_exit.o crt/cxx_abi.o crt/mman.o \ - util/memstream.o \ hw/ide.o hw/pit.o hw/pic.o hw/pci_device.o hw/cpu_freq_sampling.o hw/serial.o\ virtio/virtio.o virtio/virtio_queue.o virtio/virtionet.o \ net/ethernet.o net/inet_common.o net/ip4/arp.o net/ip4/ip4.o \ @@ -74,7 +73,7 @@ OS_OBJECTS = kernel/kernel_start.o kernel/syscalls.o kernel/vga.o \ net/packet.o net/buffer_store.o \ fs/disk.o fs/filesystem.o fs/mbr.o fs/vbr.o fs/path.o \ fs/ext4.o fs/fat.o fs/fat_async.o fs/fat_sync.o fs/memdisk.o \ - virtio/block.o # virtio/console.o + virtio/block.o # virtio/console.o kernel/vga.o util/memstream.o CRTI_OBJ = crt/crti.o CRTN_OBJ = crt/crtn.o diff --git a/src/crt/c_abi.c b/src/crt/c_abi.c index 9c42bff08b..1be046d2ee 100644 --- a/src/crt/c_abi.c +++ b/src/crt/c_abi.c @@ -23,6 +23,9 @@ #include #include + +const char* _______first = "H E L L O"; + /// IMPLEMENTATION OF Newlib I/O: struct _reent newlib_reent; @@ -38,14 +41,15 @@ void _init_c_runtime() { // Initialize .bss section extern char _BSS_START_, _BSS_END_; - streamset8(&_BSS_START_, 0, &_BSS_END_ - &_BSS_START_); + //streamset8(&_BSS_START_, 0, &_BSS_END_ - &_BSS_START_); + memset(&_BSS_START_, 0, &_BSS_END_ - &_BSS_START_); // Initialize the heap before exceptions extern caddr_t heap_end; // used by SBRK: extern char _end; // Defined by the linker // Set heap to after _end (given by linker script) if needed - if (&_end > heap_end) - heap_end = &_end; + heap_end = &_end; + //heap_end += 0x80000; /// initialize newlib I/O newlib_reent = (struct _reent) _REENT_INIT(newlib_reent); @@ -65,6 +69,9 @@ void _init_c_runtime() /// call global constructors emitted by compiler extern void _init(); _init(); + + // check first string + printf("first = %s, addr = %p\n", _______first, _______first); } // global/static objects should never be destructed here, so ignore this diff --git a/src/linker.ld b/src/linker.ld index a1f9c9c021..4d9a4c7f27 100644 --- a/src/linker.ld +++ b/src/linker.ld @@ -12,22 +12,25 @@ SECTIONS _TEXT_END_ = .; } - .init : - { + .init ALIGN(0x10) : { _INIT_START_ = .; *(.init) _INIT_END_ = .; } + .fini ALIGN(0x10) : { + /* we don't want destructors taking up space */ + *(.fini) + } /* Global constructor array */ - .ctors : + .ctors ALIGN(0x10) : { _GCONSTR_START = .; *(.ctors) _GCONSTR_END = .; LONG(0); } - .dtors : + .dtors ALIGN(0x10) : { *(.dtors) LONG(0); @@ -39,9 +42,6 @@ SECTIONS *(.rodata*) *(.gnu.linkonce.r*) _RODATA_END_ = .; - - /* this will make the image bigger, but maybe give it some speed too */ - /*. = ALIGN(4096);*/ } /* For stack unwinding (Required by exception handling) */ @@ -65,6 +65,12 @@ SECTIONS _DATA_END_ = .; } + .syms : + { + *(.symtab) + *(.strtab) + } + .memdisk : { _DISK_START_ = .; @@ -82,5 +88,6 @@ SECTIONS } _includeos = .; - _end = .; + . = ALIGN(4096); + _end = .; } From 16ced3cea11a3871f523b710d8ed991514e0ed80 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Tue, 19 Apr 2016 17:32:29 +0200 Subject: [PATCH 190/311] Merge fix --- api/common | 5 +++++ api/fs/memdisk.hpp | 6 +++--- src/Makefile | 2 +- src/fs/memdisk.cpp | 22 +++++++++++----------- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/api/common b/api/common index 1a61de8236..5ebb70d409 100644 --- a/api/common +++ b/api/common @@ -60,11 +60,16 @@ /* the reason for termination. */ #if defined(OS_TERMINATE_ON_CONTRACT_VIOLATION) +#include // Needed for std::exit +#include // Needed for std::err #define OS_STRINGIFY(x) #x /* Function used to set termination behaviour */ inline void expects_and_ensures_termination() { std::exit(EXIT_FAILURE); } +#undef Expects +#undef Ensures + #define Expects(cond) \ do { \ if (not (cond)) { \ diff --git a/api/fs/memdisk.hpp b/api/fs/memdisk.hpp index d11b4557f3..864cf9e095 100644 --- a/api/fs/memdisk.hpp +++ b/api/fs/memdisk.hpp @@ -29,7 +29,7 @@ namespace fs { public: static constexpr size_t SECTOR_SIZE = 512; - MemDisk() noexcept; + explicit MemDisk() noexcept; virtual const char* name() const noexcept override { return "MemDisk"; } @@ -49,8 +49,8 @@ namespace fs { virtual buffer_t read_sync(block_t blk) override; private: - const char* image_start_; - const char* image_end_; + const char* const image_start_; + const char* const image_end_; }; //< class MemDisk } //< namespace fs diff --git a/src/Makefile b/src/Makefile index b4027f5e4e..d50bd80453 100644 --- a/src/Makefile +++ b/src/Makefile @@ -12,7 +12,7 @@ INSTALL = $(INCLUDEOS_INSTALL) # stackrealign is needed to guarantee 16-byte stack alignment for SSE # the compiler seems to be really dumb in this regard, creating a misaligned stack left and right CAPABS_COMMON = -mstackrealign -mno-sse -CAPABS = $(CAPABS_COMMON) -O2 -DNO_DEBUG=1 +CAPABS = $(CAPABS_COMMON) -O2 -DNO_DEBUG=1 -DOS_TERMINATE_ON_CONTRACT_VIOLATION WARNS = -Wall -Wextra #-pedantic DEBUG_OPTS = -ggdb3 diff --git a/src/fs/memdisk.cpp b/src/fs/memdisk.cpp index 2d5619f06e..b4b5ac679f 100644 --- a/src/fs/memdisk.cpp +++ b/src/fs/memdisk.cpp @@ -15,10 +15,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include -#include #include +#include +#include #include #define likely(x) __builtin_expect(!!(x), 1) @@ -40,13 +40,13 @@ namespace fs { auto sector_loc = image_start_ + (blk * block_size()); // Disallow reading memory past disk image if (unlikely(sector_loc >= image_end_)) { - reader(buffer_t()); return; + reader(buffer_t{}); return; } auto buffer = new uint8_t[block_size()]; - assert( memcpy(buffer, sector_loc, block_size()) == buffer ); + Ensures( memcpy(buffer, sector_loc, block_size()) == buffer ); - reader( buffer_t(buffer, std::default_delete()) ); + reader( buffer_t{buffer, std::default_delete()} ); } void MemDisk::read(block_t blk, block_t count, on_read_func reader) { @@ -54,25 +54,25 @@ namespace fs { auto end_loc = start_loc + (count * block_size()); // Disallow reading memory past disk image if (unlikely(end_loc >= image_end_)) { - reader(buffer_t()); return; + reader(buffer_t{}); return; } auto buffer = new uint8_t[count * block_size()]; - assert( memcpy(buffer, start_loc, count * block_size()) == buffer ); + Ensures( memcpy(buffer, start_loc, count * block_size()) == buffer ); - reader( buffer_t(buffer, std::default_delete()) ); + reader( buffer_t{buffer, std::default_delete()} ); } MemDisk::buffer_t MemDisk::read_sync(block_t blk) { auto sector_loc = image_start_ + (blk * block_size()); // Disallow reading memory past disk image if (unlikely(sector_loc >= image_end_)) - return buffer_t(); + return buffer_t{}; auto buffer = new uint8_t[block_size()]; - assert( memcpy(buffer, sector_loc, block_size()) == buffer ); + Ensures( memcpy(buffer, sector_loc, block_size()) == buffer ); - return buffer_t(buffer, std::default_delete()); + return buffer_t{buffer, std::default_delete()}; } MemDisk::block_t MemDisk::size() const noexcept { From fb8e5cefe1075800886f4ae8a843035fcd37a422 Mon Sep 17 00:00:00 2001 From: RicoAntonioFelix Date: Tue, 19 Apr 2016 12:15:57 -0400 Subject: [PATCH 191/311] [Ethernet] Replaced all assert statements for Expects... --- src/net/ethernet.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/net/ethernet.cpp b/src/net/ethernet.cpp index c116fc908c..6161040442 100644 --- a/src/net/ethernet.cpp +++ b/src/net/ethernet.cpp @@ -19,10 +19,12 @@ //#define DEBUG2 #include + +#include + #include #include #include -#include namespace net { @@ -53,8 +55,8 @@ namespace net { header* hdr = reinterpret_cast(pckt->buffer()); // Verify ethernet header - assert(hdr->dest.major != 0 || hdr->dest.minor !=0); - assert(hdr->type != 0); + Expects(hdr->dest.major != 0 || hdr->dest.minor !=0); + Expects(hdr->type != 0); // Add source address hdr->src = mac_; @@ -66,7 +68,7 @@ namespace net { } void Ethernet::bottom(Packet_ptr pckt) { - assert(pckt->size() > 0); + Expects(pckt->size() > 0); header* eth = reinterpret_cast(pckt->buffer()); From ac91ab7f3edb1abc5eae6f5dc3f5d370ec4f9a3f Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Wed, 20 Apr 2016 11:36:34 +0200 Subject: [PATCH 192/311] Fixed off-by-one in virtio queue --- src/virtio/virtio_queue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/virtio/virtio_queue.cpp b/src/virtio/virtio_queue.cpp index e00c5c3981..cf620cd78f 100644 --- a/src/virtio/virtio_queue.cpp +++ b/src/virtio/virtio_queue.cpp @@ -30,7 +30,7 @@ /** Virtio Queue class, nested inside Virtio. */ -#define ALIGN(x) (((x) + PAGE_SIZE) & ~PAGE_SIZE) +#define ALIGN(x) (((x) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) unsigned Virtio::Queue::virtq_size(unsigned int qsz) { return ALIGN(sizeof(virtq_desc)*qsz + sizeof(u16)*(3 + qsz)) From 263f1578dfa74cbd5f818e139c3a20f9f6349f39 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Wed, 20 Apr 2016 11:46:59 +0200 Subject: [PATCH 193/311] virtioblk: Removed debug --- api/virtio/block.hpp | 1 - src/debug/test_disk.cpp | 10 +++++++- src/virtio/block.cpp | 48 ++++++++++++++++--------------------- src/virtio/virtio_queue.cpp | 2 +- 4 files changed, 30 insertions(+), 31 deletions(-) diff --git a/api/virtio/block.hpp b/api/virtio/block.hpp index f552e064ad..d6707e06aa 100644 --- a/api/virtio/block.hpp +++ b/api/virtio/block.hpp @@ -125,7 +125,6 @@ class VirtioBlk : public Virtio, public hw::IDiskDevice // configuration as read from paravirtual PCI device virtio_blk_config_t config; - uint16_t request_counter; }; #endif diff --git a/src/debug/test_disk.cpp b/src/debug/test_disk.cpp index 7ab5d4726e..d3b08027e1 100644 --- a/src/debug/test_disk.cpp +++ b/src/debug/test_disk.cpp @@ -17,7 +17,15 @@ void Service::start() // if the disk is empty, we can't mount a filesystem anyways if (disk->empty()) panic("Oops! The disk is empty!\n"); - + + for (int i = 0; i < 32; i++) + device.read(0, + [i] (fs::buffer_t buffer) + { + printf("buffer %d is not null: %d\n", i, !!buffer); + }); + return; + // list extended partitions list_partitions(disk); diff --git a/src/virtio/block.cpp b/src/virtio/block.cpp index 77435e12d3..b80be651a4 100644 --- a/src/virtio/block.cpp +++ b/src/virtio/block.cpp @@ -29,9 +29,7 @@ #define FEAT(x) (1 << x) VirtioBlk::VirtioBlk(hw::PCI_Device& d) -: Virtio(d), - req(queue_size(0), 0, iobase()), - request_counter(0) + : Virtio(d), req(queue_size(0), 0, iobase()) { INFO("VirtioBlk", "Driver initializing"); @@ -125,36 +123,30 @@ void VirtioBlk::irq_handler() void VirtioBlk::service_RX() { - printf("VirtioBlk interrupt handler\n"); req.disable_interrupts(); - - uint32_t received = 0; - uint32_t len; - request_t* hdr; gsl::span res; while ((res = req.dequeue()).data() != nullptr) { - //&printf("service_RX() received %u bytes for sector %llu\n", - // len, hdr->hdr.sector); - // - hdr = (request_t*) res.data(); - len = res.size(); + request_t* hdr = (request_t*) res.data(); + uint32_t len = res.size(); + // check request response blk_resp_t* resp = &hdr->resp; - printf("blk response: %u\n", resp->status); - - uint8_t* copy = new uint8_t[SECTOR_SIZE]; - memcpy(copy, hdr->io.sector, SECTOR_SIZE); - auto buf = buffer_t(copy, std::default_delete()); - - printf("STATUS: [%u]\nCalling handler: %p\n", - resp->status, &hdr->resp.handler); - hdr->resp.handler(buf); - received++; - } - if (received == 0) - { - printf("service_RX() error processing requests\n"); + // only call handler with data when the request was fullfilled + if (resp->status == 0) + { + // create a shared copy of the data + uint8_t* copy = new uint8_t[SECTOR_SIZE]; + memcpy(copy, hdr->io.sector, SECTOR_SIZE); + auto buf = buffer_t(copy, std::default_delete()); + // return buffer only as size is implicit + hdr->resp.handler(buf); + } + else + { + // return empty shared ptr + hdr->resp.handler(buffer_t()); + } } req.enable_interrupts(); } @@ -176,7 +168,7 @@ void VirtioBlk::read (block_t blk, on_read_func func) Token token1 { { (uint8_t*) &vbr->hdr, sizeof(scsi_header_t) }, Token::OUT }; Token token2 { { (uint8_t*) &vbr->io, sizeof(blk_io_t) }, Token::IN }; - Token token3 { { (uint8_t*) &vbr->resp, sizeof(blk_resp_t) }, Token::IN }; + Token token3 { { (uint8_t*) &vbr->resp, 1 }, Token::IN }; std::array tokens {{ token1, token2, token3 }}; diff --git a/src/virtio/virtio_queue.cpp b/src/virtio/virtio_queue.cpp index 5f69c753b6..2f911975b8 100644 --- a/src/virtio/virtio_queue.cpp +++ b/src/virtio/virtio_queue.cpp @@ -30,7 +30,7 @@ /** Virtio Queue class, nested inside Virtio. */ -#define ALIGN(x) (((x) + PAGE_SIZE) & ~PAGE_SIZE) +#define ALIGN(x) (((x) + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1)) unsigned Virtio::Queue::virtq_size(unsigned int qsz) { return ALIGN(sizeof(virtq_desc)*qsz + sizeof(u16)*(3 + qsz)) From 57f226160ada5fffc2b87c183369c2b3bf5c8326 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Wed, 20 Apr 2016 12:08:56 +0200 Subject: [PATCH 194/311] make: Re-enable SSE --- src/Makefile | 5 +++-- src/crt/c_abi.c | 5 ++--- src/debug/test_disk.cpp | 1 + src/virtio/block.cpp | 39 +++++++++++++++++---------------------- 4 files changed, 23 insertions(+), 27 deletions(-) diff --git a/src/Makefile b/src/Makefile index 6d9e763ee7..d01ab2d761 100644 --- a/src/Makefile +++ b/src/Makefile @@ -11,7 +11,7 @@ INSTALL = $(INCLUDEOS_INSTALL) # stackrealign is needed to guarantee 16-byte stack alignment for SSE # the compiler seems to be really dumb in this regard, creating a misaligned stack left and right -CAPABS_COMMON = -mstackrealign -mno-sse +CAPABS_COMMON = -mstackrealign -mssse3 CAPABS = $(CAPABS_COMMON) -O2 -DNO_DEBUG=1 -DOS_TERMINATE_ON_CONTRACT_VIOLATION WARNS = -Wall -Wextra #-pedantic @@ -63,6 +63,7 @@ OS_OBJECTS = kernel/kernel_start.o kernel/syscalls.o \ kernel/interrupts.o kernel/os.o kernel/cpuid.o \ kernel/irq_manager.o kernel/pci_manager.o \ kernel/terminal.o kernel/terminal_disk.o \ + kernel/vga.o util/memstream.o \ crt/c_abi.o crt/string.o crt/quick_exit.o crt/cxx_abi.o crt/mman.o \ hw/ide.o hw/pit.o hw/pic.o hw/pci_device.o hw/cpu_freq_sampling.o hw/serial.o\ virtio/virtio.o virtio/virtio_queue.o virtio/virtionet.o \ @@ -74,7 +75,7 @@ OS_OBJECTS = kernel/kernel_start.o kernel/syscalls.o \ net/packet.o net/buffer_store.o \ fs/disk.o fs/filesystem.o fs/mbr.o fs/vbr.o fs/path.o \ fs/ext4.o fs/fat.o fs/fat_async.o fs/fat_sync.o fs/memdisk.o \ - virtio/block.o # virtio/console.o kernel/vga.o util/memstream.o + virtio/block.o # virtio/console.o CRTI_OBJ = crt/crti.o CRTN_OBJ = crt/crtn.o diff --git a/src/crt/c_abi.c b/src/crt/c_abi.c index 1be046d2ee..4d92bb4d09 100644 --- a/src/crt/c_abi.c +++ b/src/crt/c_abi.c @@ -41,15 +41,14 @@ void _init_c_runtime() { // Initialize .bss section extern char _BSS_START_, _BSS_END_; - //streamset8(&_BSS_START_, 0, &_BSS_END_ - &_BSS_START_); - memset(&_BSS_START_, 0, &_BSS_END_ - &_BSS_START_); + streamset8(&_BSS_START_, 0, &_BSS_END_ - &_BSS_START_); // Initialize the heap before exceptions extern caddr_t heap_end; // used by SBRK: extern char _end; // Defined by the linker // Set heap to after _end (given by linker script) if needed + // note: end should be aligned to next page by linker heap_end = &_end; - //heap_end += 0x80000; /// initialize newlib I/O newlib_reent = (struct _reent) _REENT_INIT(newlib_reent); diff --git a/src/debug/test_disk.cpp b/src/debug/test_disk.cpp index 45e724a761..1cd4336eb8 100644 --- a/src/debug/test_disk.cpp +++ b/src/debug/test_disk.cpp @@ -23,6 +23,7 @@ void Service::start() [i] (fs::buffer_t buffer) { printf("buffer %d is not null: %d\n", i, !!buffer); + assert(buffer); }); //return; diff --git a/src/virtio/block.cpp b/src/virtio/block.cpp index 30e16d763e..b2ddbb7531 100644 --- a/src/virtio/block.cpp +++ b/src/virtio/block.cpp @@ -92,8 +92,8 @@ void VirtioBlk::get_config() Virtio::get_config(&config, sizeof(virtio_blk_config_t)); } -void VirtioBlk::irq_handler() -{ +void VirtioBlk::irq_handler() { + IRQ_manager::eoi(irq()); debug2(" IRQ handler\n"); @@ -103,26 +103,23 @@ void VirtioBlk::irq_handler() unsigned char isr = hw::inp(iobase() + VIRTIO_PCI_ISR); // Step 2. A) - one of the queues have changed - if (isr & 1) - { - // This now means service RX & TX interchangeably - service_RX(); - } - + if (isr & 1) { + // This now means service RX & TX interchangeably + service_RX(); + } + // Step 2. B) - if (isr & 2) - { - debug("\t Configuration change:\n"); - - // Getting the MAC + status - //debug("\t Old status: 0x%x\n", config.status); - get_config(); - //debug("\t New status: 0x%x \n", config.status); - } + if (isr & 2) { + debug("\t Configuration change:\n"); + + // Getting the MAC + status + //debug("\t Old status: 0x%x\n", config.status); + get_config(); + //debug("\t New status: 0x%x \n", config.status); + } } -void VirtioBlk::service_RX() -{ +void VirtioBlk::service_RX() { req.disable_interrupts(); do { @@ -152,8 +149,7 @@ void VirtioBlk::service_RX() req.enable_interrupts(); } -void VirtioBlk::read (block_t blk, on_read_func func) -{ +void VirtioBlk::read (block_t blk, on_read_func func) { // Virtio Std. § 5.1.6.3 auto* vbr = new request_t; @@ -166,7 +162,6 @@ void VirtioBlk::read (block_t blk, on_read_func func) debug("Enqueue handler: %p, total: %u\n", &vbr->resp.handler, sizeof(request_t)); // - Token token1 { { (uint8_t*) &vbr->hdr, sizeof(scsi_header_t) }, Token::OUT }; Token token2 { { (uint8_t*) &vbr->io, sizeof(blk_io_t) }, Token::IN }; Token token3 { { (uint8_t*) &vbr->resp, 1 }, Token::IN }; From 4e144a4bd245b6191bd6acd3167359cb22cadf4d Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Wed, 20 Apr 2016 13:25:25 +0200 Subject: [PATCH 195/311] virtioblk: Queue requests after vring full --- api/virtio/block.hpp | 14 ++++++++++++-- src/debug/test_disk.cpp | 3 ++- src/virtio/block.cpp | 43 ++++++++++++++++++++++++++++------------- 3 files changed, 44 insertions(+), 16 deletions(-) diff --git a/api/virtio/block.hpp b/api/virtio/block.hpp index 64d2781b8f..d63854f271 100644 --- a/api/virtio/block.hpp +++ b/api/virtio/block.hpp @@ -23,7 +23,7 @@ #include #include #include "virtio.hpp" -//#include +#include /** Virtio-net device driver. */ class VirtioBlk : public Virtio, public hw::IDiskDevice @@ -120,11 +120,21 @@ class VirtioBlk : public Virtio, public hw::IDiskDevice Will look for config. changes and service RX/TX queues as necessary.*/ void irq_handler(); - + + // need at least 3 tokens free to ship a request + inline bool free_space() const noexcept + { return req.num_free() >= 3; } + + // add one request to queue and kick + void shipit(request_t*); + Virtio::Queue req; // configuration as read from paravirtual PCI device virtio_blk_config_t config; + + // queue waiting for space in vring + std::deque jobs; }; #endif diff --git a/src/debug/test_disk.cpp b/src/debug/test_disk.cpp index 1cd4336eb8..935edf1cca 100644 --- a/src/debug/test_disk.cpp +++ b/src/debug/test_disk.cpp @@ -18,7 +18,8 @@ void Service::start() // if the disk is empty, we can't mount a filesystem anyways if (disk->empty()) panic("Oops! The disk is empty!\n"); - for (int i = 0; i < 32; i++) + // create alot of jobs + for (int i = 0; i < 256; i++) device.read(0, [i] (fs::buffer_t buffer) { diff --git a/src/virtio/block.cpp b/src/virtio/block.cpp index b2ddbb7531..45fea43d41 100644 --- a/src/virtio/block.cpp +++ b/src/virtio/block.cpp @@ -131,8 +131,7 @@ void VirtioBlk::service_RX() { // check request response blk_resp_t* resp = &hdr->resp; // only call handler with data when the request was fullfilled - if (resp->status == 0) - { + if (resp->status == 0) { // create a shared copy of the data uint8_t* copy = new uint8_t[SECTOR_SIZE]; memcpy(copy, hdr->io.sector, SECTOR_SIZE); @@ -140,13 +139,34 @@ void VirtioBlk::service_RX() { // return buffer only as size is implicit hdr->resp.handler(buf); } - else - { + else { // return empty shared ptr hdr->resp.handler(buffer_t()); } + // delete request(!) + delete hdr; + } while (true); req.enable_interrupts(); + + // if we have free space and jobs, ship them now + while (free_space() && !jobs.empty()) { + auto* vbr = jobs.front(); + jobs.pop_front(); + shipit(vbr); + } +} + +void VirtioBlk::shipit(request_t* vbr) { + + Token token1 { { (uint8_t*) &vbr->hdr, sizeof(scsi_header_t) }, Token::OUT }; + Token token2 { { (uint8_t*) &vbr->io, sizeof(blk_io_t) }, Token::IN }; + Token token3 { { (uint8_t*) &vbr->resp, 1 }, Token::IN }; // 1 status byte + + std::array tokens {{ token1, token2, token3 }}; + + req.enqueue(tokens); + req.kick(); } void VirtioBlk::read (block_t blk, on_read_func func) { @@ -159,20 +179,17 @@ void VirtioBlk::read (block_t blk, on_read_func func) { vbr->resp.status = VIRTIO_BLK_S_IOERR; vbr->resp.handler = func; - debug("Enqueue handler: %p, total: %u\n", + debug("virtioblk: Enqueue handler %p, reqsize %u\n", &vbr->resp.handler, sizeof(request_t)); // - Token token1 { { (uint8_t*) &vbr->hdr, sizeof(scsi_header_t) }, Token::OUT }; - Token token2 { { (uint8_t*) &vbr->io, sizeof(blk_io_t) }, Token::IN }; - Token token3 { { (uint8_t*) &vbr->resp, 1 }, Token::IN }; - - std::array tokens {{ token1, token2, token3 }}; - - req.enqueue(tokens); - req.kick(); + if (free_space()) + shipit(vbr); + else + jobs.push_back(vbr); } VirtioBlk::buffer_t VirtioBlk::read_sync(block_t) { + // this driver won't support sync read return buffer_t(); } From 4c5559572cfe32755aafde093e83a593179385e2 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Wed, 20 Apr 2016 13:26:54 +0200 Subject: [PATCH 196/311] crt: Remove test string --- src/crt/c_abi.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/crt/c_abi.c b/src/crt/c_abi.c index 4d92bb4d09..4a3666c1da 100644 --- a/src/crt/c_abi.c +++ b/src/crt/c_abi.c @@ -23,9 +23,6 @@ #include #include - -const char* _______first = "H E L L O"; - /// IMPLEMENTATION OF Newlib I/O: struct _reent newlib_reent; @@ -68,9 +65,6 @@ void _init_c_runtime() /// call global constructors emitted by compiler extern void _init(); _init(); - - // check first string - printf("first = %s, addr = %p\n", _______first, _______first); } // global/static objects should never be destructed here, so ignore this From 8725487aea0c6353cc802b9d81a4d8a3df360b37 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Wed, 20 Apr 2016 16:42:49 +0200 Subject: [PATCH 197/311] virtio: Read cnt sequental sectors --- api/virtio/block.hpp | 16 ++++-- src/debug/test_disk.cpp | 11 +++- src/virtio/block.cpp | 122 ++++++++++++++++++++++++++++++++-------- 3 files changed, 118 insertions(+), 31 deletions(-) diff --git a/api/virtio/block.hpp b/api/virtio/block.hpp index d63854f271..aa6eb21338 100644 --- a/api/virtio/block.hpp +++ b/api/virtio/block.hpp @@ -42,13 +42,10 @@ class VirtioBlk : public Virtio, public hw::IDiskDevice { return SECTOR_SIZE; // some multiple of sector size } - + // read @blk from disk, call func with buffer when done virtual void read(block_t blk, on_read_func func) override; - - virtual void read(block_t, block_t, on_read_func cb) override - { - cb(buffer_t()); - } + // read @blk + @cnt from disk, call func with buffer when done + virtual void read(block_t blk, block_t cnt, on_read_func cb) override; virtual buffer_t read_sync(block_t blk) override; @@ -94,6 +91,7 @@ class VirtioBlk : public Virtio, public hw::IDiskDevice struct blk_resp_t { uint8_t status; + bool partial; on_read_func handler; }; @@ -102,6 +100,8 @@ class VirtioBlk : public Virtio, public hw::IDiskDevice scsi_header_t hdr; blk_io_t io; blk_resp_t resp; + + request_t(uint64_t blk, bool, on_read_func cb); }; /** Get virtio PCI config. @see Virtio::get_config.*/ @@ -125,6 +125,10 @@ class VirtioBlk : public Virtio, public hw::IDiskDevice inline bool free_space() const noexcept { return req.num_free() >= 3; } + // need many free tokens free to efficiently ship requests + inline bool lots_free_space() const noexcept + { return req.num_free() >= 32; } + // add one request to queue and kick void shipit(request_t*); diff --git a/src/debug/test_disk.cpp b/src/debug/test_disk.cpp index 935edf1cca..a53f313d60 100644 --- a/src/debug/test_disk.cpp +++ b/src/debug/test_disk.cpp @@ -18,7 +18,7 @@ void Service::start() // if the disk is empty, we can't mount a filesystem anyways if (disk->empty()) panic("Oops! The disk is empty!\n"); - // create alot of jobs + // 1. create alot of separate jobs for (int i = 0; i < 256; i++) device.read(0, [i] (fs::buffer_t buffer) @@ -26,6 +26,15 @@ void Service::start() printf("buffer %d is not null: %d\n", i, !!buffer); assert(buffer); }); + // 2. create alot of sequential jobs of 1024 sectors each + // note: if we queue more than this we will run out of RAM + for (int i = 0; i < 64; i++) + device.read(0, 1024, + [i] (fs::buffer_t buffer) + { + printf("buffer %d is not null: %d\n", i, !!buffer); + assert(buffer); + }); //return; // list extended partitions diff --git a/src/virtio/block.cpp b/src/virtio/block.cpp index 45fea43d41..06b38c0e58 100644 --- a/src/virtio/block.cpp +++ b/src/virtio/block.cpp @@ -28,6 +28,9 @@ #define FEAT(x) (1 << x) +// a deleter that does nothing +void null_deleter(uint8_t*) {}; + VirtioBlk::VirtioBlk(hw::PCI_Device& d) : Virtio(d), req(queue_size(0), 0, iobase()) { @@ -132,12 +135,20 @@ void VirtioBlk::service_RX() { blk_resp_t* resp = &hdr->resp; // only call handler with data when the request was fullfilled if (resp->status == 0) { - // create a shared copy of the data - uint8_t* copy = new uint8_t[SECTOR_SIZE]; - memcpy(copy, hdr->io.sector, SECTOR_SIZE); - auto buf = buffer_t(copy, std::default_delete()); + buffer_t buf; + // for partial results, we will just use the buffer as-is + if (resp->partial) { + buf = buffer_t(hdr->io.sector, null_deleter); + } + else { + // otherwise, create a shared copy of the data + // because we are giving this to the user + uint8_t* copy = new uint8_t[SECTOR_SIZE]; + memcpy(copy, hdr->io.sector, SECTOR_SIZE); + buf = buffer_t(copy, std::default_delete()); + } // return buffer only as size is implicit - hdr->resp.handler(buf); + resp->handler(buf); } else { // return empty shared ptr @@ -149,12 +160,22 @@ void VirtioBlk::service_RX() { } while (true); req.enable_interrupts(); - // if we have free space and jobs, ship them now - while (free_space() && !jobs.empty()) { - auto* vbr = jobs.front(); - jobs.pop_front(); - shipit(vbr); + int scnt = 0; + + if (req.num_free() > 4) { + // if we have lots of free space and jobs, ship many + bool shipped = false; + while (free_space() && !jobs.empty()) { + auto* vbr = jobs.front(); + jobs.pop_front(); + shipit(vbr); + shipped = true; + scnt++; + } + if (shipped) req.kick(); } + + printf("scnt: %d num_free: %u\n", scnt, req.num_free()); } void VirtioBlk::shipit(request_t* vbr) { @@ -164,28 +185,71 @@ void VirtioBlk::shipit(request_t* vbr) { Token token3 { { (uint8_t*) &vbr->resp, 1 }, Token::IN }; // 1 status byte std::array tokens {{ token1, token2, token3 }}; - req.enqueue(tokens); - req.kick(); } void VirtioBlk::read (block_t blk, on_read_func func) { // Virtio Std. § 5.1.6.3 - auto* vbr = new request_t; - - vbr->hdr.type = VIRTIO_BLK_T_IN; - vbr->hdr.ioprio = 0; - vbr->hdr.sector = blk; - vbr->resp.status = VIRTIO_BLK_S_IOERR; - vbr->resp.handler = func; - - debug("virtioblk: Enqueue handler %p, reqsize %u\n", - &vbr->resp.handler, sizeof(request_t)); + auto* vbr = new request_t(blk, false, func); + debug("virtioblk: Enqueue blk %llu\n", blk); // - if (free_space()) + if (free_space()) { shipit(vbr); - else + req.kick(); + } + else { jobs.push_back(vbr); + } +} +void VirtioBlk::read (block_t blk, block_t cnt, on_read_func func) { + + bool shipped = false; + //printf("Create job blk = %llu, cnt=%llu\n", blk, cnt); + // create big buffer for collecting all the disk data + uint8_t* bufdata = new uint8_t[block_size() * cnt]; + buffer_t bigbuf { bufdata, std::default_delete() }; + // (initialized) boolean array of partial jobs + auto results = std::make_shared (cnt); + + for (size_t i = 0; i < cnt; i++) + { + // create a special request where we collect all the data + auto* vbr = new request_t(blk + i, true, + [this, i, func, results, bigbuf] (buffer_t buffer) { + // if the job was already completed, return early + if (*results == 0) { + printf("Job cancelled? results == 0, blk=%u\n", i); + return; + } + // validate partial result + if (buffer) { + *results -= 1; + // copy partial block + memcpy(bigbuf.get() + i * block_size(), buffer.get(), block_size()); + // check if we have all blocks + if (*results == 0) { + // finally, call user-provided callback + func(bigbuf); + } + } + else { + // if the partial result failed, cancel all + *results = 0; + // callback with no data + func(buffer_t()); + } + }); + debug("virtioblk: Enqueue blk %llu\n", blk + i); + // + if (free_space()) { + shipit(vbr); + shipped = true; + } + else + jobs.push_back(vbr); + } + // kick when we have enqueued stuff + if (shipped) req.kick(); } VirtioBlk::buffer_t VirtioBlk::read_sync(block_t) @@ -193,3 +257,13 @@ VirtioBlk::buffer_t VirtioBlk::read_sync(block_t) // this driver won't support sync read return buffer_t(); } + +VirtioBlk::request_t::request_t(uint64_t blk, bool part, on_read_func cb) +{ + hdr.type = VIRTIO_BLK_T_IN; + hdr.ioprio = 0; // reserved + hdr.sector = blk; + resp.status = VIRTIO_BLK_S_IOERR; + resp.partial = part; + resp.handler = cb; +} From 144ccd05ef1ef01c469b016cde93f58670c313ac Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Thu, 21 Apr 2016 11:02:11 +0000 Subject: [PATCH 198/311] Updated vmrunner to check and exit with proper exit status --- test/UDP/test.py | 1 - test/vmrunner.py | 52 +++++++++++++++++++++++++++++++++++------------- 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/test/UDP/test.py b/test/UDP/test.py index 63e6c7fe47..4f79da1b60 100755 --- a/test/UDP/test.py +++ b/test/UDP/test.py @@ -35,5 +35,4 @@ def UDP_test(): vm.on_output("IncludeOS UDP test", UDP_test) # Boot the VM, taking a timeout as parameter -timeout = sys.argv[1] if len(sys.argv) > 1 else 30 vm.boot(20) diff --git a/test/vmrunner.py b/test/vmrunner.py index 3b3dda160d..5c10ebf60a 100644 --- a/test/vmrunner.py +++ b/test/vmrunner.py @@ -10,14 +10,24 @@ import validate_test +INCLUDEOS_HOME = None + +if not os.environ.has_key("INCLUDEOS_HOME"): + print "WARNING: Environment varialble INCLUDEOS_HOME is not set. Trying default" + def_home = os.environ["HOME"] + "/IncludeOS_install" + if not os.path.isdir(def_home): raise Exception("Couldn't find INCLUDEOS_HOME") + INCLUDEOS_HOME= def_home +else: + INCLUDEOS_HOME = os.environ['INCLUDEOS_HOME'] + def abstract(): raise Exception("Abstract class method called. Use a subclass") # Hypervisor base / super class # (It seems to be recommended for "new style classes" to inherit object) class hypervisor(object): - def __init__(self, vm): - self._vm = vm; + def __init__(self, config): + self._config = config; # Boot a VM, returning a hypervisor handle for reuse def boot(self): @@ -68,42 +78,42 @@ def drive_arg(self, filename, drive_type="virtio", drive_format="raw"): def net_arg(self, if_type = "virtio", if_name = "net0", mac="c0:01:0a:00:00:2a"): type_names = {"virtio" : "virtio-net"} - qemu_ifup = os.environ['INCLUDEOS_HOME']+"/etc/qemu-ifup" + qemu_ifup = INCLUDEOS_HOME+"/etc/qemu-ifup" return ["-device", type_names[if_type]+",netdev="+if_name+",mac="+mac, "-netdev", "tap,id="+if_name+",script="+qemu_ifup] def boot(self): self._out_sign = "<" + type(self).__name__ + ">" - print self._out_sign,"booting ",self._vm["image"] + print self._out_sign,"booting ",self._config["image"] - disk_args = self.drive_arg(self._vm["image"], "ide") - if self._vm.has_key("drives"): - for disk in self._vm["drives"]: + disk_args = self.drive_arg(self._config["image"], "ide") + if self._config.has_key("drives"): + for disk in self._config["drives"]: disk_args += self.drive_arg(disk["file"], disk["type"], disk["format"]) net_args = [] i = 0 - if self._vm.has_key("net"): - for net in self._vm["net"]: + if self._config.has_key("net"): + for net in self._config["net"]: net_args += self.net_arg(net["type"], "net"+str(i), net["mac"]) i+=1 - command = ["sudo", "qemu-system-x86_64", "-nographic" ] + disk_args + net_args + command = ["sudo", "qemu-system-x86_64","--enable-kvm", "-nographic" ] + disk_args + net_args print self._out_sign, "command:", command self._proc = start_process(command) def stop(self): if hasattr(self, "_proc") and self._proc.poll() == None : - print self._out_sign,"Stopping", self._vm["image"], "PID",self._proc.pid + print self._out_sign,"Stopping", self._config["image"], "PID",self._proc.pid # Kill with sudo subprocess.check_call(["sudo","kill", "-SIGTERM", str(self._proc.pid)]) # Wait for termination (avoids the need to reset the terminal) self._proc.wait() def wait(self): - print "Waiting for process to terminate" + print self._out_sign, "Waiting for process to terminate" self._proc.wait() def readline(self): @@ -132,8 +142,10 @@ def __init__(self, config, hyper = qemu): def exit(self, status, msg): self.stop() + print print msg self._exit_status = status + # sys.exit won't really do anything if called from a (timer) thread sys.exit(status) def on_output(self, output, callback): @@ -167,12 +179,24 @@ def boot(self, timeout = None): while self._hyper.poll() == None and not self._exit_status: line = self._hyper.readline() print "",line.rstrip() - # Look for event-triggers for pattern, func in self._on_output.iteritems(): if re.search(pattern, line): func() - return self + + # Now we either have an exit status from timer thread, or an exit status + # from the subprocess. + self.stop() + self.wait() + + if self._exit_status: + print " Done running VM. Exit status: ", self._exit_status + sys.exit(self._exit_status) + else: + print " Subprocess finished. Exiting with ", self._hyper.poll() + sys.exit(self._hyper.poll()) + + raise Exception("Unexpected termination") def stop(self): self._hyper.stop() From e104dc9e26c525678c643e3e7577691939251655 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Thu, 21 Apr 2016 13:30:55 +0200 Subject: [PATCH 199/311] tcp: major refactoring + rewrite of congctrl --- api/net/tcp.hpp | 165 ++++++------ src/net/tcp_connection.cpp | 430 +++++++++++++++++++++--------- src/net/tcp_connection_states.cpp | 72 ++--- test/tcp/service.cpp | 21 +- 4 files changed, 437 insertions(+), 251 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index 6df5ca9304..93bd635ab5 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -783,9 +783,6 @@ namespace net { TCP::Seq WL2; // segment acknowledgment number used for last window update uint16_t MSS; // Maximum segment size for outgoing segments. - - uint32_t cwnd; // Congestion window [RFC 5681] - Seq recover; // New Reno [RFC 6582] } SND; // << TCP::Seq ISS; // initial send sequence number @@ -800,18 +797,26 @@ namespace net { TCP::Seq IRS; // initial receive sequence number uint32_t ssthresh; // slow start threshold [RFC 5681] + uint32_t cwnd; // Congestion window [RFC 5681] + Seq recover; // New Reno [RFC 6582] TCB() { - SND = { 0, 0, TCP::default_window_size, 0, 0, 0, TCP::default_mss, 0, 0 }; - ISS = 0; + SND = { 0, 0, TCP::default_window_size, 0, 0, 0, TCP::default_mss }; + ISS = (Seq)4815162342; RCV = { 0, TCP::default_window_size, 0, 0 }; IRS = 0; ssthresh = TCP::default_window_size; + cwnd = 0; + recover = 0; }; void init() { ISS = TCP::generate_iss(); - SND.recover = ISS; // [RFC 6582] + recover = ISS; // [RFC 6582] + } + + bool slow_start() { + return cwnd < ssthresh; } std::string to_string() const; @@ -1005,7 +1010,7 @@ namespace net { TODO: Not sure if this will suffice. */ inline uint32_t bytes_transmitted() const { - return control_block.SND.NXT - control_block.ISS; + return cb.SND.NXT - cb.ISS; } /* @@ -1013,7 +1018,7 @@ namespace net { TODO: Not sure if this will suffice. */ inline uint32_t bytes_received() const { - return control_block.RCV.NXT - control_block.IRS; + return cb.RCV.NXT - cb.IRS; } /* @@ -1093,7 +1098,7 @@ namespace net { /* Keep tracks of all sequence variables. */ - TCB control_block; // 36 B + TCB cb; // 36 B /* The given read request @@ -1103,7 +1108,7 @@ namespace net { /* Queue for write requests to process */ - std::queue write_queue; + std::queue writeq; /* State if connection is in TCP write queue or not. @@ -1113,13 +1118,13 @@ namespace net { /* Retransmission queue */ - std::deque retransq; + std::deque rtx_q; struct { hw::PIT::Timer_iterator iter; bool active = false; size_t i = 0; - } rt_timer; + } rtx_timer; /* @@ -1321,6 +1326,8 @@ namespace net { return send((char*)buffer.pos(), n, packets, buffer.push); } + size_t send(const char* buffer, size_t n, Packet_ptr, bool PUSH); + /* Process the write queue with the given amount of packets. Returns true if the Connection finishes - there is no more doable jobs. @@ -1331,23 +1338,23 @@ namespace net { Returns if the connection has a doable write job. */ inline bool has_doable_job() { - return !write_queue.empty() and usable_window() >= SMSS(); + return !writeq.empty() and usable_window() >= SMSS(); } /* Try to process the current write queue. */ - void write_queue_push(); + void writeq_push(); /* Try to write (some of) queue on connected. */ - inline void write_queue_on_connect() { write_queue_push(); } + inline void writeq_on_connect() { writeq_push(); } /* Reset queue on disconnect. Clears the queue and notice every requests callback. */ - void write_queue_reset(); + void writeq_reset(); /* Returns if the TCP has the Connection in write queue @@ -1388,7 +1395,7 @@ namespace net { // RFC 3042 void limited_tx(); inline void try_limited_tx() { - if( (send_window() > 0) and ( (flight_size() + 2*SMSS() ) <= control_block.SND.cwnd) ) + if( (send_window() > 0) and ( (flight_size() + 2*SMSS() ) <= cb.cwnd) ) limited_tx(); } @@ -1397,10 +1404,10 @@ namespace net { /* Returns the TCB. */ - inline Connection::TCB& tcb() { return control_block; } + inline Connection::TCB& tcb() { return cb; } inline int32_t usable_window() const { - auto x = (int64_t)congestion_window() - (int64_t)control_block.SND.NXT; + auto x = (int64_t)congestion_window() - (int64_t)cb.SND.NXT; return (int32_t) x; } @@ -1410,11 +1417,11 @@ namespace net { Made a function due to future use when Window Scaling Option is added. */ inline int32_t send_window() const { - return (int32_t)control_block.SND.WND; + return (int32_t)cb.SND.WND; } inline int32_t congestion_window() const { - auto win = control_block.SND.UNA + std::min((int32_t)control_block.SND.cwnd, send_window()); + auto win = cb.SND.UNA + std::min((int32_t)cb.cwnd, send_window()); return win; } @@ -1424,11 +1431,24 @@ namespace net { */ void acknowledge(Seq ACK); + void handle_ack(TCP::Packet_ptr); + + void on_dup_ack(); + + inline bool can_send_one() + { return (std::min(cb.cwnd, (uint32_t)send_window()) >= SMSS()) and !writeq.empty(); } + + //void send_ack(TCP::Packet_ptr = nullptr); + /// Congestion Control [RFC 5681] /// bool RENO_FAST_RECOVERY = false; - // First partial ack not seen - bool RENO_FPACK_NOT_SEEN = false; + // First partial ack seen + bool reno_fpack_seen = false; + + size_t dup_acks_ = 0; + Seq prev_high_ack_ = 0; + Seq highest_ack_ = 0; Seq RENO_PREV_HIGHEST_ACK = 0; Seq RENO_HIGHEST_ACK = 0; @@ -1440,10 +1460,10 @@ namespace net { { return host_.MSS(); } inline uint16_t RMSS() const - { return control_block.SND.MSS; } + { return cb.SND.MSS; } inline int32_t flight_size() const - { return control_block.SND.NXT - control_block.SND.UNA; } + { return cb.SND.NXT - cb.SND.UNA; } /// Reno /// @@ -1454,85 +1474,72 @@ namespace net { inline void reno_init_cwnd(size_t segments) { - control_block.SND.cwnd = segments*SMSS(); - debug2(" Cwnd initilized: %u\n", control_block.SND.cwnd); + cb.cwnd = segments*SMSS(); + debug2(" Cwnd initilized: %u\n", cb.cwnd); } inline void reno_init_sshtresh() - { control_block.ssthresh = control_block.SND.WND; } + { cb.ssthresh = cb.SND.WND; } inline bool reno_slow_start() const - { return control_block.SND.cwnd < control_block.ssthresh; } + { return cb.cwnd < cb.ssthresh; } inline void reno_increase_cwnd(uint16_t n) - { control_block.SND.cwnd += std::min(n, SMSS()); } + { cb.cwnd += std::min(n, SMSS()); } inline void reno_deflate_cwnd(uint16_t n) - { control_block.SND.cwnd -= (n >= SMSS()) ? n-SMSS() : n; } + { cb.cwnd -= (n >= SMSS()) ? n-SMSS() : n; } - inline void reno_reduce_ssthresh() { - control_block.ssthresh = std::max( (flight_size() / 2), (2 * SMSS()) ); - printf(" Slow start threshold reduced: %u\n", - control_block.ssthresh); + inline void reduce_ssthresh() { + cb.ssthresh = std::max( (flight_size() / 2), (2 * SMSS()) ); + //printf(" Slow start threshold reduced: %u\n", + // cb.ssthresh); } - inline void reno_fast_retransmit() { - printf(" Fast retransmit initiated.\n"); + inline void fast_retransmit() { + printf(" Fast retransmit initiated.\n"); + // reduce sshtresh + reduce_ssthresh(); + // retransmit segment starting SND.UNA retransmit(); - reno_enter_fast_recovery(); - //control_block.SND.cwnd = control_block.ssthresh + (3 * SMSS()); + // inflate congestion window with the 3 packets we got dup ack on. + cb.cwnd = cb.ssthresh + 3*SMSS(); } - inline void reno_loss_detected() { - reno_reduce_ssthresh(); - reno_fast_retransmit(); + inline void finish_fast_recovery() { + dup_acks_ = 0; + reno_fpack_seen = false; + cb.cwnd = std::min((int32_t)cb.ssthresh, std::max(flight_size(), (int32_t)SMSS()) + SMSS()); + printf(" Finished Fast Recovery - Cwnd: %u\n", cb.cwnd); } - inline void reno_enter_fast_retransmit() { - reno_loss_detected(); - } inline bool reno_is_dup_ack(TCP::Packet_ptr in) { bool is_dup_ack = flight_size() > 0 and !in->has_data() and !in->isset(FIN) and !in->isset(SYN) //and ((in->flags() & (FIN | SYN)) == 0) - and in->win() == control_block.SND.WND; + and in->win() == cb.SND.WND; return is_dup_ack; } - inline void reno_dup_ack(Seq ACK) { - if(++DUP_ACK < 3) { - if(!write_queue.empty()) - try_limited_tx(); - } else if(DUP_ACK == 3) { - printf(" Duplicate ACK - Strike 3!\n"); - if(reno_should_recover(ACK)) { - reno_update_recover(); - reno_enter_fast_retransmit(); - } - } else if(DUP_ACK > 3) { - control_block.SND.cwnd += SMSS(); - try_limited_tx(); - } - } inline void reno_enter_fast_recovery() { - control_block.SND.cwnd = control_block.ssthresh + (3 * SMSS()); + cb.cwnd = cb.ssthresh + (3 * SMSS()); RENO_FAST_RECOVERY = true; - RENO_FPACK_NOT_SEEN = true; - printf(" Entered Fast Recovery - Cwnd: %u\n", control_block.SND.cwnd); + reno_fpack_seen = true; + printf(" Entered Fast Recovery - Cwnd: %u\n", cb.cwnd); } inline void reno_exit_fast_recovery() { - control_block.SND.cwnd = std::min((int32_t)control_block.ssthresh, std::max(flight_size(), (int32_t)SMSS()) + SMSS()); + cb.cwnd = std::min((int32_t)cb.ssthresh, std::max(flight_size(), (int32_t)SMSS()) + SMSS()); RENO_FAST_RECOVERY = false; - printf(" Exited Fast Recovery - Cwnd: %u\n", control_block.SND.cwnd); + printf(" Exited Fast Recovery - Cwnd: %u\n", cb.cwnd); } inline bool reno_should_recover(Seq ACK) { - return (ACK - 1 > control_block.SND.recover) or reno_heuristic_segment_loss_detected(); + return (ACK - 1 > cb.recover) or reno_heuristic_segment_loss_detected(); } inline bool reno_heuristic_segment_loss_detected() { @@ -1541,7 +1548,7 @@ namespace net { } inline bool reno_full_ack(Seq ACK) { - return ACK - 1 > control_block.SND.recover; + return ACK - 1 > cb.recover; } inline bool reno_partial_ack(Seq ACK) { @@ -1553,7 +1560,7 @@ namespace net { } inline void reno_update_recover() { - control_block.SND.recover = control_block.SND.NXT; + cb.recover = cb.SND.NXT; } void reno_update_heuristic_ack(Seq ACK) { @@ -1606,19 +1613,19 @@ namespace net { /* Start retransmission timer. */ - void rt_start(); + void rtx_start(); /* Stop retransmission timer. */ - void rt_stop(); + void rtx_stop(); /* Restart retransmission timer. */ - inline void rt_restart() { - rt_stop(); - rt_start(); + inline void rtx_reset() { + rtx_stop(); + rtx_start(); } /* @@ -1629,22 +1636,22 @@ namespace net { /* Remove all packets acknowledge by ACK in retransmission queue */ - void rt_ack_queue(Seq ack); + void rtx_ack(Seq ack); /* Flush the queue (transmit every packet in queue) */ - void rt_flush(); + void rtx_flush(); /* Delete retransmission queue */ - void rt_clear(); + void rtx_clear(); /* When retransmission times out. */ - void rt_timeout(); + void rtx_timeout(); /* @@ -1664,7 +1671,7 @@ namespace net { (Limit the size for outgoing packets) */ inline uint16_t MSDS() const { - return std::min(host_.MSS(), control_block.SND.MSS) + sizeof(TCP::Header); + return std::min(host_.MSS(), cb.SND.MSS) + sizeof(TCP::Header); } /* diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index 2642d860ce..588ab73e49 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -36,9 +36,9 @@ Connection::Connection(TCP& host, Port local_port, Socket remote) : remote_(remote), state_(&Connection::Closed::instance()), prev_state_(state_), - control_block(), + cb(), read_request(), - write_queue(), + writeq(), queued_(false), time_wait_started(0) { @@ -108,7 +108,7 @@ void Connection::write(WriteBuffer buffer, WriteCallback callback) { callback(buffer.offset); } else { - write_queue.emplace(buffer, callback); + writeq.emplace(buffer, callback); } } catch(TCPException err) { @@ -121,8 +121,8 @@ bool Connection::offer(size_t& packets) { debug(" %s got offered [%u] packets. Usable window is %i.\n", to_string().c_str(), packets, usable_window()); - while(has_doable_job() and packets and !reno_is_fast_recovering()) { - auto& buf = write_queue.front().first; + while(has_doable_job() and packets and dup_acks_ < 3) { + auto& buf = writeq.front().first; // segmentize the buffer into packets auto written = send(buf, packets, buf.remaining); // advance the buffer @@ -132,15 +132,15 @@ bool Connection::offer(size_t& packets) { // if finished if(!buf.remaining) { // callback and remove object - write_queue.front().second(buf.offset); - write_queue.pop(); + writeq.front().second(buf.offset); + writeq.pop(); debug(" Request finished.\n"); } } assert(packets >= 0); debug(" Finished working offer with [%u] packets left and a queue of (%u) with a usable window of %i\n", - packets, write_queue.size(), usable_window()); - return !has_doable_job() or reno_is_fast_recovering(); + packets, writeq.size(), usable_window()); + return !has_doable_job() or dup_acks_ >= 3; } // TODO: This is starting to get complex and ineffective, refactor.. @@ -155,7 +155,7 @@ size_t Connection::send(const char* buffer, size_t remaining, size_t& packet_cou // reduce the amount of packets available by one packet_count--; // add the seq, ack and flag - packet->set_seq(control_block.SND.NXT).set_ack(control_block.RCV.NXT).set_flag(ACK); + packet->set_seq(cb.SND.NXT).set_ack(cb.RCV.NXT).set_flag(ACK); // calculate how much the packet can be filled with auto packet_limit = std::min((uint32_t)MSDS() - packet->header_size(), (uint32_t)usable_window()); // fill the packet with data from the request @@ -171,7 +171,7 @@ size_t Connection::send(const char* buffer, size_t remaining, size_t& packet_cou packet->set_flag(PSH); // Advance outgoing sequence number (SND.NXT) with the length of the data. - control_block.SND.NXT += packet->data_length(); + cb.SND.NXT += packet->data_length(); // TODO: Replace with chaining transmit(packet); @@ -184,34 +184,44 @@ size_t Connection::send(const char* buffer, size_t remaining, size_t& packet_cou return bytes_written; } -void Connection::write_queue_push() { - while(!write_queue.empty()) { - auto& buf = write_queue.front().first; +size_t Connection::send(const char* buffer, size_t n, Packet_ptr packet, bool PUSH) { + auto written = packet->fill(buffer, n); + packet->set_seq(cb.SND.NXT).set_ack(cb.RCV.NXT).set_flag(ACK); + if(PUSH) + packet->set_flag(PSH); + cb.SND.NXT += packet->data_length(); + transmit(packet); + return written; +} + +void Connection::writeq_push() { + while(!writeq.empty()) { + auto& buf = writeq.front().first; auto written = send(buf); buf.advance(written); if(buf.remaining) return; - write_queue.front().second(buf.offset); - write_queue.pop(); + writeq.front().second(buf.offset); + writeq.pop(); } } void Connection::limited_tx() { - auto& buf = write_queue.front().first; - auto written = host_.send(shared_from_this(),buf, std::min(buf.remaining, (uint32_t)RMSS())); - printf(" Limited transmit. %u written\n", written); + auto& buf = writeq.front().first; + auto written = send((char*)buf.pos(), std::min(buf.remaining, (uint32_t)SMSS()), create_outgoing_packet(), false); + //printf(" Limited transmit. %u written\n", written); buf.advance(written); if(buf.remaining) return; - write_queue.front().second(buf.offset); - write_queue.pop(); + writeq.front().second(buf.offset); + writeq.pop(); } -void Connection::write_queue_reset() { - while(!write_queue.empty()) { - auto& job = write_queue.front(); +void Connection::writeq_reset() { + while(!writeq.empty()) { + auto& job = writeq.front(); job.second(job.first.offset); - write_queue.pop(); + writeq.pop(); } } @@ -268,7 +278,7 @@ void Connection::segment_arrived(TCP::Packet_ptr incoming) { } case State::CLOSED: { debug(" State handle finished with CLOSED. We're done, ask host() to delete the connection. \n"); - rt_clear(); + rtx_clear(); signal_close(); break; }; @@ -301,10 +311,10 @@ TCP::Packet_ptr Connection::create_outgoing_packet() { // Set Destination (remote) packet->set_destination(remote_); - packet->set_win(control_block.SND.WND); + packet->set_win(cb.SND.WND); // Set SEQ and ACK - I think this is OK.. - packet->set_seq(control_block.SND.NXT).set_ack(control_block.RCV.NXT); + packet->set_seq(cb.SND.NXT).set_ack(cb.RCV.NXT); debug(" Outgoing packet created: %s \n", packet->to_string().c_str()); return packet; @@ -319,38 +329,174 @@ void Connection::transmit(TCP::Packet_ptr packet) { host_.transmit(packet); if(packet->has_data()) - retransq.push_back(packet); - if(!rt_timer.active) - rt_start(); + rtx_q.push_back(packet); + if(!rtx_timer.active) + rtx_start(); +} +/* +void Connection::retransmit() { + printf(" \n"); } -/*void Connection::acknowledge(TCP::Packet_ptr in) { - // ACK is inside - if(in->ack() <= control_block.SND.NXT) { - // new ACK - if(in->ack() > control_block.SND.UNA) { - size_t bytes_acked = in->ack() - control_block.SND.UNA; - control_block.SND.UNA = in->ack(); - if(DUP_ACK >= DUP) { +void Connection::fast_retransmit() { + printf(" \n"); + retransmit(); - } +} + +void Connection::finish_fast_recovery() { + printf(" \n"); +} + +void Connection::on_rtx_timeout() { + printf(" \n"); +} + +void Connection::limited_tx() { + if(flight_size() <= ) +} +*/ + + +void Connection::handle_ack(TCP::Packet_ptr in) { + // new ack + if(in->ack() > cb.SND.UNA) { + // [RFC 6582] p. 8 + //prev_highest_ack_ = cb.SND.UNA; + //highest_ack_ = in->ack(); + + if( cb.SND.WL1 < in->seq() or ( cb.SND.WL1 == in->seq() and cb.SND.WL2 <= in->ack() ) ) + { + cb.SND.WND = in->win(); + cb.SND.WL1 = in->seq(); + cb.SND.WL2 = in->ack(); + debug2(" Usable window slided (%i)\n", tcp.usable_window()); } - // Duplicate ACK - else if(in->ack() == control_block.SND.UNA) { - in->has_data() and - DUP_ACK++ + + // used for cwnd calculation (Reno) + size_t bytes_acked = in->ack() - cb.SND.UNA; + cb.SND.UNA = in->ack(); + + // ack everything in rtx queue + rtx_ack(in->ack()); + + // update cwnd when congestion avoidance? + bool cong_avoid_rtt = false; + + // if measuring round trip time, stop + if(rttm.active) { + rttm.stop(); + cong_avoid_rtt = true; } - // old ACK + + // no fast recovery + if(dup_acks_ < 3) { + + dup_acks_ = 0; + + // slow start + if(cb.slow_start()) { + reno_increase_cwnd(bytes_acked); + } + + // congestion avoidance + else { + // increase cwnd once per RTT + cb.cwnd += std::max(SMSS()*SMSS()/cb.cwnd, (uint32_t)1); + //if(cong_avoid_rtt) { + /* + Not sure about this one.. + If timer is active, it means this ACK will stop the timer => one RTT. + Not sure how this works with retransmission. + */ + //reno_increase_cwnd(bytes_acked); + //} + } // < congestion avoidance + + } // < !fast recovery + + // we're in fast recovery else { - } + // partial ack + if(!reno_full_ack(in->ack())) { + reno_deflate_cwnd(bytes_acked); + //printf(" Recovery - Partial ACK\n"); + retransmit(); + + if(!reno_fpack_seen) { + rtx_reset(); + reno_fpack_seen = true; + } + + // send one segment if possible + if(can_send_one()) + limited_tx(); + } // < partial ack + + // full ack + else { + finish_fast_recovery(); + } // < full ack + + } // < fast recovery + + } // < new ack + + // dup ack + /* + 1. Same ACK as latest received + 2. outstanding data + 3. packet is empty + 4. is not an wnd update + */ + else if(in->ack() == cb.SND.UNA and flight_size() + and !in->has_data() and cb.SND.WND == in->win()) + { + dup_acks_++; + on_dup_ack(); + } // < dup ack - } // ACK outside else { } -}*/ +} + + +/* + Reno [RFC 5681] p. 9 + + What to do when received ACK is a duplicate. +*/ +void Connection::on_dup_ack() { + printf(" %u\n", dup_acks_); + // if less than 3 dup acks + if(dup_acks_ < 3) { + + // try to send one segment + if(cb.SND.WND >= SMSS() and (flight_size() <= cb.cwnd + dup_acks_*SMSS()) and !writeq.empty()) + limited_tx(); + } + + // 3 dup acks + else if(dup_acks_ == 3) { + printf(" Dup ACK == 3 - %u\n", cb.SND.UNA); + if(cb.SND.UNA - 1 > cb.recover) { + cb.recover = cb.SND.NXT; + printf(" Enter Recovery - Flight Size: %u\n", flight_size()); + fast_retransmit(); + } + } + + // > 3 dup acks + else { + cb.cwnd += SMSS(); + // send one segment if possible + if(can_send_one()) + limited_tx(); + } +} /* As specified in [RFC3390], the SYN/ACK and the acknowledgment of the @@ -359,26 +505,27 @@ void Connection::transmit(TCP::Packet_ptr packet) { sender after a correctly transmitted SYN MUST be one segment consisting of at most SMSS bytes. */ -void Connection::acknowledge(Seq ACK) { +/*void Connection::acknowledge(Seq ACK) { DUP_ACK = 0; - size_t bytes_acked = ACK - control_block.SND.UNA; - control_block.SND.UNA = ACK; + size_t bytes_acked = ACK - cb.SND.UNA; + cb.SND.UNA = ACK; + - rt_ack_queue(ACK); + rtx_ack(ACK); reno_update_heuristic_ack(ACK); if(!reno_is_fast_recovering()) { if(reno_slow_start()) { reno_increase_cwnd(bytes_acked); debug2(" Slow start - cwnd increased: %u\n", - control_block.SND.cwnd); + cb.cwnd); } // congestion avoidance else { if(rttm.active) { reno_increase_cwnd(bytes_acked); debug2(" Congestion avoidance - cwnd increased: %u\n", - control_block.SND.cwnd); + cb.cwnd); } } } @@ -394,11 +541,11 @@ void Connection::acknowledge(Seq ACK) { retransmit(); reno_deflate_cwnd(bytes_acked); if(RENO_FPACK_NOT_SEEN) { - printf(" #1 Partial ACK - %u, Cwnd: %u\n", ACK, control_block.SND.cwnd); + printf(" #1 Partial ACK - %u, Cwnd: %u\n", ACK, cb.cwnd); rt_restart(); RENO_FPACK_NOT_SEEN = false; } else { - //printf(" Partial ACK - %u, Cwnd: %u\n", ACK, control_block.SND.cwnd); + //printf(" Partial ACK - %u, Cwnd: %u\n", ACK, cb.cwnd); } try_limited_tx(); } @@ -406,7 +553,7 @@ void Connection::acknowledge(Seq ACK) { if(rttm.active) rttm.stop(); -} +}*/ /* [RFC 6298] @@ -418,11 +565,11 @@ void Connection::acknowledge(Seq ACK) { retransmission timer so that it will expire after RTO seconds (for the current value of RTO). */ -void Connection::rt_ack_queue(Seq ack) { - auto x = retransq.size(); - while(!retransq.empty()) { - if(retransq.front()->is_acked_by(ack)) - retransq.pop_front(); +void Connection::rtx_ack(const Seq ack) { + auto x = rtx_q.size(); + while(!rtx_q.empty()) { + if(rtx_q.front()->is_acked_by(ack)) + rtx_q.pop_front(); else break; } @@ -430,20 +577,71 @@ void Connection::rt_ack_queue(Seq ack) { When all outstanding data has been acknowledged, turn off the retransmission timer. */ - if(retransq.empty() and rt_timer.active) { - rt_stop(); + if(rtx_q.empty() and rtx_timer.active) { + rtx_stop(); } /* When an ACK is received that acknowledges new data, restart the retransmission timer so that it will expire after RTO seconds (for the current value of RTO). */ - else if(x - retransq.size() > 0) { + else if(x - rtx_q.size() > 0) { rto_attempt = 0; - rt_restart(); + rtx_reset(); + } + //printf(" ACK'ed %u packets. rtx_q: %u\n", + // x-rtx_q.size(), rtx_q.size()); +} + + +void Connection::retransmit() { + if(rtx_q.empty()) + return; + auto packet = rtx_q.front(); + printf(" Retransmitting: %u \n", packet->seq()); + host_.transmit(packet); + /* + Every time a packet containing data is sent (including a + retransmission), if the timer is not running, start it running + so that it will expire after RTO seconds (for the current value + of RTO). + */ + //if(!rt_timer.active) + // rt_start(); +} + +void Connection::rtx_start() { + assert(!rtx_timer.active); + auto i = rtx_timer.i; + rtx_timer.iter = hw::PIT::instance().on_timeout(rttm.RTO, + [this, i] + { + rtx_timer.active = false; + printf(" %s Timed out. rt_q: %u, i: %u rt_i: %u\n", + to_string().c_str(), rtx_q.size(), i, rtx_timer.i); + rtx_timeout(); + }); + rtx_timer.i++; + rtx_timer.active = true; +} + +void Connection::rtx_stop() { + assert(rtx_timer.active); + hw::PIT::instance().stop_timer(rtx_timer.iter); + rtx_timer.active = false; +} + +void Connection::rtx_flush() { + while(!rtx_q.empty()) { + host_.transmit(rtx_q.front()); + rtx_q.pop_front(); } - //printf(" ACK'ed %u packets. Retransq: %u\n", - // x-retransq.size(), retransq.size()); +} + +void Connection::rtx_clear() { + if(rtx_timer.active) + rtx_stop(); + rtx_q.clear(); } /* @@ -465,70 +663,52 @@ void Connection::rt_ack_queue(Seq ack) { MUST be re-initialized to 3 seconds when data transmission begins (i.e., after the three-way handshake completes). */ -void Connection::retransmit() { - if(retransq.empty()) - return; - auto packet = retransq.front(); - printf(" Retransmitting: %s \n", packet->to_string().c_str()); - host_.transmit(packet); - /* - Every time a packet containing data is sent (including a - retransmission), if the timer is not running, start it running - so that it will expire after RTO seconds (for the current value - of RTO). - */ - if(!packet->isset(SYN)) { +void Connection::rtx_timeout() { + // retransmit SND.UNA + retransmit(); + + if(!rtx_q.front()->isset(SYN)) { + // "back off" timer rttm.RTO *= 2; - } else { + } + // we never queue SYN packets since they don't carry data.. + else { rttm.RTO = 3.0; } - if(!rt_timer.active) - rt_start(); - else - rt_restart(); -} + // timer need to be restarted + rtx_start(); -void Connection::rt_start() { - assert(!rt_timer.active); - auto i = rt_timer.i; - rt_timer.iter = hw::PIT::instance().on_timeout(rttm.RTO, - [this, i] - { - rt_timer.active = false; - printf(" %s Timed out. rt_q: %u, i: %u rt_i: %u\n", - to_string().c_str(), retransq.size(), i, rt_timer.i); - rt_timeout(); - }); - rt_timer.i++; - rt_timer.active = true; -} + /* + [RFC 5681] p. 7 -void Connection::rt_stop() { - assert(rt_timer.active); - hw::PIT::instance().stop_timer(rt_timer.iter); - rt_timer.active = false; -} + When a TCP sender detects segment loss using the retransmission timer + and the given segment has not yet been resent by way of the + retransmission timer, the value of ssthresh MUST be set to no more + than the value given in equation (4): -void Connection::rt_flush() { - while(!retransq.empty()) { - host_.transmit(retransq.front()); - retransq.pop_front(); - } -} + ssthresh = max (FlightSize / 2, 2*SMSS) + */ + if(rto_attempt++ == 0) + reduce_ssthresh(); -void Connection::rt_clear() { - if(rt_timer.active) - rt_stop(); - retransq.clear(); -} + /* + [RFC 6582] p. 6 + After a retransmit timeout, record the highest sequence number + transmitted in the variable recover, and exit the fast recovery + procedure if applicable. + */ -void Connection::rt_timeout() { - if(rto_attempt++ == 0) - reno_reduce_ssthresh(); - reno_update_recover(); - if(reno_is_fast_recovering()) - reno_exit_fast_recovery(); - retransmit(); + // update recover + cb.recover = cb.SND.NXT; + + if(dup_acks_ >= 3) // not sure if this is correct + finish_fast_recovery(); + + cb.cwnd = SMSS(); + + /* + NOTE: It's unclear which one comes first, or if finish_fast_recovery includes chaining the cwnd. + */ } TCP::Seq Connection::generate_iss() { @@ -613,7 +793,7 @@ void Connection::parse_options(TCP::Packet_ptr packet) { auto* opt_mss = (Option::opt_mss*)option; uint16_t mss = ntohs(opt_mss->mss); - control_block.SND.MSS = mss; + cb.SND.MSS = mss; debug2(" MSS: %u \n", mss); opt += option->length; break; diff --git a/src/net/tcp_connection_states.cpp b/src/net/tcp_connection_states.cpp index 75a8bee871..dbb2e55321 100644 --- a/src/net/tcp_connection_states.cpp +++ b/src/net/tcp_connection_states.cpp @@ -214,32 +214,16 @@ bool Connection::State::check_ack(Connection& tcp, TCP::Packet_ptr in) { // Correction: [RFC 1122 p. 94] // ACK is inside sequence space if(in->ack() <= tcb.SND.NXT ) { + + tcp.handle_ack(in); // this is a "new" ACK - if(tcb.SND.UNA <= in->ack()) { - /* - If SND.UNA =< SEG.ACK =< SND.NXT, the send window should be - updated. If (SND.WL1 < SEG.SEQ or (SND.WL1 = SEG.SEQ and - SND.WL2 =< SEG.ACK)), set SND.WND <- SEG.WND, set - SND.WL1 <- SEG.SEQ, and set SND.WL2 <- SEG.ACK. - - Note that SND.WND is an offset from SND.UNA, that SND.WL1 - records the sequence number of the last segment used to update - SND.WND, and that SND.WL2 records the acknowledgment number of - the last segment used to update SND.WND. The check here - prevents using old segments to update the window. - */ - if( tcb.SND.WL1 < in->seq() or ( tcb.SND.WL1 = in->seq() and tcb.SND.WL2 <= in->ack() ) ) { - tcb.SND.WND = in->win(); - tcb.SND.WL1 = in->seq(); - tcb.SND.WL2 = in->ack(); - debug2(" Usable window slided (%i)\n", tcp.usable_window()); - } + //if(tcb.SND.UNA <= in->ack()) { // this is a NEW ACK - if(tcb.SND.UNA < in->ack()) - { - tcp.acknowledge(in->ack()); - } + //if(tcb.SND.UNA < in->ack()) + //{ + // tcp.acknowledge(in->ack()); + //} // [RFC 5681] /* DUPLICATE ACKNOWLEDGMENT: @@ -259,19 +243,19 @@ bool Connection::State::check_ack(Connection& tcp, TCP::Packet_ptr in) { */ // this is a RFC 5681 DUP ACK //!in->isset(FIN) and !in->isset(SYN) - else if(tcp.reno_is_dup_ack(in)) { - debug2(" Reno Dup ACK %u\n", in->ack()); - tcp.reno_dup_ack(in->ack()); - } + //else if(tcp.reno_is_dup_ack(in)) { + // debug2(" Reno Dup ACK %u\n", in->ack()); + // tcp.reno_dup_ack(in->ack()); + //} // this is an RFC 793 DUP ACK - else { + //else { //printf(" RFC 793 Dup ACK %u\n", in->ack()); - } - } + //} + //} // this is an "old" ACK out of order - else { - printf(" ACK out of order (SND.UNA > ACK)\n"); - } + //else { + // printf(" ACK out of order (SND.UNA > ACK)\n"); + //} // tcp.signal_sent(); // return that buffer has been SENT - currently no support to receipt sent buffer. } @@ -348,7 +332,7 @@ void Connection::State::process_segment(Connection& tcp, TCP::Packet_ptr in) { tcp.transmit(packet); if(tcp.has_doable_job() and !tcp.is_queued()) { debug2(" Usable window: %i\n", tcp.usable_window()); - tcp.write_queue_push(); + tcp.writeq_push(); } /* @@ -369,7 +353,7 @@ void Connection::State::process_segment(Connection& tcp, TCP::Packet_ptr in) { // Piggyback ACK with outgoing data if(tcp.has_doable_job() and !tcp.is_queued()) { debug2(" Usable window: %i\n", tcp.usable_window()); - tcp.write_queue_push(); + tcp.writeq_push(); // we tried to push data, but nothing was written, reply the sender immediately if(tcp.usable_window() == tcb.SND.WND) { auto packet = tcp.outgoing_packet(); @@ -381,7 +365,7 @@ void Connection::State::process_segment(Connection& tcp, TCP::Packet_ptr in) { // If no outgoing data right now - reply with ACK. else { debug2(" ACK. Window: %i, Queue: %u, is_queued: %s\n", - tcp.usable_window(), tcp.write_queue.size(), tcp.is_queued() ? "true" : "false"); + tcp.usable_window(), tcp.writeq.size(), tcp.is_queued() ? "true" : "false"); auto packet = tcp.outgoing_packet(); packet->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); tcp.transmit(packet); @@ -444,11 +428,11 @@ void Connection::State::process_fin(Connection& tcp, TCP::Packet_ptr in) { ///////////////////////////////////////////////////////////////////// void Connection::State::send_reset(Connection& tcp) { - tcp.write_queue_reset(); + tcp.writeq_reset(); auto packet = tcp.outgoing_packet(); packet->set_seq(tcp.tcb().SND.NXT).set_ack(0).set_flag(RST); // flush retransmission queue - tcp.rt_flush(); + tcp.rtx_flush(); tcp.transmit(packet); } ///////////////////////////////////////////////////////////////////// @@ -600,7 +584,7 @@ size_t Connection::SynReceived::send(Connection&, WriteBuffer&) { size_t Connection::Established::send(Connection& tcp, WriteBuffer& buffer) { // if nothing in queue, try to write directly - if(tcp.write_queue.empty()) + if(tcp.writeq.empty()) return tcp.send(buffer); return 0; @@ -608,7 +592,7 @@ size_t Connection::Established::send(Connection& tcp, WriteBuffer& buffer) { size_t Connection::CloseWait::send(Connection& tcp, WriteBuffer& buffer) { // if nothing in queue, try to write directly - if(tcp.write_queue.empty()) + if(tcp.writeq.empty()) return tcp.send(buffer); return 0; @@ -909,7 +893,7 @@ State::Result Connection::SynSent::handle(Connection& tcp, TCP::Packet_ptr in) { tcb.IRS = in->seq(); tcb.SND.UNA = in->ack(); - tcp.rt_ack_queue(in->ack()); + tcp.rtx_ack(in->ack()); // (our SYN has been ACKed) if(tcb.SND.UNA > tcb.ISS) { @@ -1021,7 +1005,7 @@ State::Result Connection::SynReceived::handle(Connection& tcp, TCP::Packet_ptr i tcb.SND.UNA = in->ack(); if(tcp.rttm.active) tcp.rttm.stop(); - tcp.rt_ack_queue(in->ack()); + tcp.rtx_ack(in->ack()); // 7. proccess the segment text if(in->has_data()) { @@ -1156,7 +1140,7 @@ State::Result Connection::FinWait1::handle(Connection& tcp, TCP::Packet_ptr in) if(in->ack() == tcp.tcb().SND.NXT) { // TODO: I guess or FIN is ACK'ed..? tcp.set_state(TimeWait::instance()); - tcp.rt_stop(); + tcp.rtx_stop(); tcp.start_time_wait_timeout(); } else { tcp.set_state(Closing::instance()); @@ -1202,7 +1186,7 @@ State::Result Connection::FinWait2::handle(Connection& tcp, TCP::Packet_ptr in) Start the time-wait timer, turn off the other timers. */ tcp.set_state(Connection::TimeWait::instance()); - tcp.rt_stop(); + tcp.rtx_stop(); tcp.start_time_wait_timeout(); } return OK; diff --git a/test/tcp/service.cpp b/test/tcp/service.cpp index af3bbf74ac..0089527afb 100644 --- a/test/tcp/service.cpp +++ b/test/tcp/service.cpp @@ -43,7 +43,7 @@ std::string small, big, huge; int -S{150}, B{1500}, H{15000}; +S{150}, B{1500}, H{150000}; std::string TEST_STR {"1337"}; @@ -129,8 +129,14 @@ struct Buffer { void Service::start() { for(int i = 0; i < S; i++) small += TEST_STR; + + big += "start-"; for(int i = 0; i < B; i++) big += TEST_STR; + big += "-end"; + + huge += "start-"; for(int i = 0; i < H; i++) huge += TEST_STR; + huge += "-end"; hw::Nic& eth0 = hw::Dev::eth<0,VirtioNet>(); inet = std::make_unique>(eth0); @@ -196,12 +202,19 @@ void Service::start() TEST: Send and receive huge string. */ tcp.bind(TEST3).onConnect([](Connection_ptr conn) { + conn->onPacketDropped([](TCP::Packet_ptr, std::string reason) { + //printf("Dropped: %s\n", reason.c_str()); + }); + conn->onPacketReceived([](Connection_ptr, TCP::Packet_ptr packet) { + //if(packet->has_data()) + // printf("Received: %s\n", packet->to_string().c_str()); + }); INFO("TEST", "HUGE string (%u)", huge.size()); auto temp = std::make_shared(huge.size()); conn->read(huge.size(), [temp, conn](buffer_t buffer, size_t n) { memcpy(temp->data + temp->written, buffer.get(), n); temp->written += n; - + //printf("Read: %u\n", n); // when all expected data is read if(temp->written == huge.size()) { bool OK = (temp->str() == huge); @@ -209,7 +222,9 @@ void Service::start() conn->close(); } }); - conn->write(huge.data(), huge.size()); + conn->write(huge.data(), huge.size(), [](size_t n) { + printf("Finished write request! %u bytes written\n", n); + }, true); INFO("Buffers available", "%u", inet->buffers_available()); }); From 0606cdc6cf718af2b221800d3cb1071b74550f59 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Thu, 21 Apr 2016 14:21:08 +0200 Subject: [PATCH 200/311] virtioblk: Dequeue faster, schedule inverted, inflight counter --- api/virtio/block.hpp | 3 ++ api/virtio/virtio.hpp | 8 ++-- src/debug/test_disk.cpp | 8 ++-- src/virtio/block.cpp | 77 ++++++++++++++++++++----------------- src/virtio/virtio_queue.cpp | 50 ++++++++++++++++++------ 5 files changed, 90 insertions(+), 56 deletions(-) diff --git a/api/virtio/block.hpp b/api/virtio/block.hpp index aa6eb21338..7a08d53405 100644 --- a/api/virtio/block.hpp +++ b/api/virtio/block.hpp @@ -132,6 +132,8 @@ class VirtioBlk : public Virtio, public hw::IDiskDevice // add one request to queue and kick void shipit(request_t*); + void handle(request_t*); + Virtio::Queue req; // configuration as read from paravirtual PCI device @@ -139,6 +141,7 @@ class VirtioBlk : public Virtio, public hw::IDiskDevice // queue waiting for space in vring std::deque jobs; + size_t inflight; }; #endif diff --git a/api/virtio/virtio.hpp b/api/virtio/virtio.hpp index cb3762e4b7..b4177a59c5 100644 --- a/api/virtio/virtio.hpp +++ b/api/virtio/virtio.hpp @@ -68,7 +68,7 @@ class Virtio { public: - + using data_handler_t = delegate; /** A wrapper for buffers to be passed in to the Queue */ class Token { @@ -208,7 +208,7 @@ class Virtio uint16_t _pci_index = 0; // Queue nr. /** Handler for data coming in on virtq.used. */ - delegate _data_handler; + data_handler_t _data_handler; /** Initialize the queue buffer */ void init_queue(int size, void* buf); @@ -240,11 +240,12 @@ class Virtio /** Dequeue a received packet */ Token dequeue(); + std::vector dequeue_chain(); void disable_interrupts(); void enable_interrupts(); - void set_data_handler(delegate dataHandler); + void set_data_handler(data_handler_t dataHandler); /** Release token. @param head : the token ID to release*/ void release(uint32_t head); @@ -302,7 +303,6 @@ class Virtio void negotiate_features(uint32_t features); /** Register interrupt handler & enable IRQ */ - //void enable_irq_handler(IRQ_handler::irq_delegate d); void enable_irq_handler(); /** Probe PCI device for features */ diff --git a/src/debug/test_disk.cpp b/src/debug/test_disk.cpp index a53f313d60..7c8c94e845 100644 --- a/src/debug/test_disk.cpp +++ b/src/debug/test_disk.cpp @@ -19,17 +19,17 @@ void Service::start() if (disk->empty()) panic("Oops! The disk is empty!\n"); // 1. create alot of separate jobs - for (int i = 0; i < 256; i++) + /*for (int i = 0; i < 256; i++) device.read(0, [i] (fs::buffer_t buffer) { printf("buffer %d is not null: %d\n", i, !!buffer); assert(buffer); - }); + });*/ // 2. create alot of sequential jobs of 1024 sectors each // note: if we queue more than this we will run out of RAM - for (int i = 0; i < 64; i++) - device.read(0, 1024, + for (int i = 0; i < 256; i++) + device.read(0, 22, [i] (fs::buffer_t buffer) { printf("buffer %d is not null: %d\n", i, !!buffer); diff --git a/src/virtio/block.cpp b/src/virtio/block.cpp index 06b38c0e58..3fc9a470ee 100644 --- a/src/virtio/block.cpp +++ b/src/virtio/block.cpp @@ -122,47 +122,51 @@ void VirtioBlk::irq_handler() { } } +void VirtioBlk::handle(request_t* hdr) { + // check request response + blk_resp_t* resp = &hdr->resp; + // only call handler with data when the request was fullfilled + if (resp->status == 0) { + buffer_t buf; + // for partial results, we will just use the buffer as-is + if (resp->partial) { + buf = buffer_t(hdr->io.sector, null_deleter); + } + else { + // otherwise, create a shared copy of the data + // because we are giving this to the user + uint8_t* copy = new uint8_t[SECTOR_SIZE]; + memcpy(copy, hdr->io.sector, SECTOR_SIZE); + buf = buffer_t(copy, std::default_delete()); + } + // return buffer only as size is implicit + resp->handler(buf); + } + else { + // return empty shared ptr + hdr->resp.handler(buffer_t()); + } +} + void VirtioBlk::service_RX() { - req.disable_interrupts(); + int handled = 0; + req.disable_interrupts(); do { - auto res = req.dequeue(); - if (!res.data()) break; - assert(res.size()); + auto tok = req.dequeue(); + if (!tok.data()) break; - request_t* hdr = (request_t*) res.data(); - // check request response - blk_resp_t* resp = &hdr->resp; - // only call handler with data when the request was fullfilled - if (resp->status == 0) { - buffer_t buf; - // for partial results, we will just use the buffer as-is - if (resp->partial) { - buf = buffer_t(hdr->io.sector, null_deleter); - } - else { - // otherwise, create a shared copy of the data - // because we are giving this to the user - uint8_t* copy = new uint8_t[SECTOR_SIZE]; - memcpy(copy, hdr->io.sector, SECTOR_SIZE); - buf = buffer_t(copy, std::default_delete()); - } - // return buffer only as size is implicit - resp->handler(buf); - } - else { - // return empty shared ptr - hdr->resp.handler(buffer_t()); - } + // only handle the main header of each request + auto* hdr = (request_t*) tok.data(); + handle(hdr); + inflight--; handled++; // delete request(!) delete hdr; } while (true); - req.enable_interrupts(); - int scnt = 0; - - if (req.num_free() > 4) { + // only ship more if we have nothing more queued (??) + if (inflight == 0) { // if we have lots of free space and jobs, ship many bool shipped = false; while (free_space() && !jobs.empty()) { @@ -170,12 +174,13 @@ void VirtioBlk::service_RX() { jobs.pop_front(); shipit(vbr); shipped = true; - scnt++; } if (shipped) req.kick(); } + req.enable_interrupts(); - printf("scnt: %d num_free: %u\n", scnt, req.num_free()); + //printf("inflight: %d handled: %d shipped: %d num_free: %u\n", + // inflight, handled, scnt, req.num_free()); } void VirtioBlk::shipit(request_t* vbr) { @@ -186,6 +191,7 @@ void VirtioBlk::shipit(request_t* vbr) { std::array tokens {{ token1, token2, token3 }}; req.enqueue(tokens); + inflight++; } void VirtioBlk::read (block_t blk, on_read_func func) { @@ -204,14 +210,13 @@ void VirtioBlk::read (block_t blk, on_read_func func) { void VirtioBlk::read (block_t blk, block_t cnt, on_read_func func) { bool shipped = false; - //printf("Create job blk = %llu, cnt=%llu\n", blk, cnt); // create big buffer for collecting all the disk data uint8_t* bufdata = new uint8_t[block_size() * cnt]; buffer_t bigbuf { bufdata, std::default_delete() }; // (initialized) boolean array of partial jobs auto results = std::make_shared (cnt); - for (size_t i = 0; i < cnt; i++) + for (int i = cnt-1; i >= 0; i--) { // create a special request where we collect all the data auto* vbr = new request_t(blk + i, true, diff --git a/src/virtio/virtio_queue.cpp b/src/virtio/virtio_queue.cpp index cf620cd78f..8d4063fefd 100644 --- a/src/virtio/virtio_queue.cpp +++ b/src/virtio/virtio_queue.cpp @@ -148,33 +148,59 @@ void Virtio::Queue::release(uint32_t head) debug(" desc[%i].next : %i \n",_pci_index, i ,_queue.desc[i].next); } -Virtio::Token Virtio::Queue::dequeue(){ +Virtio::Token Virtio::Queue::dequeue() { // Return NULL if there are no more completed buffers in the queue if (_last_used_idx == _queue.used->idx){ debug(" Can't dequeue - no used buffers \n",_pci_index); return {{nullptr, 0}, Token::IN}; - } - - //debug(" Dequeueing last_used index %i ",_pci_index, _last_used_idx); + debug(" Dequeueing last_used index %i ",_pci_index, _last_used_idx); // Get next completed buffer - auto* e = &_queue.used->ring[_last_used_idx % _size]; + auto& e = _queue.used->ring[_last_used_idx % _size]; + debug(" Releasing token @%p, nr. %i Len: %i\n",_pci_index, &e, e.id, e.len); - debug(" Releasing token @%p, nr. %i Len: %i\n",_pci_index, e, e->id, e->len); + // Release buffer + release(e.id); + _last_used_idx++; + // return token: + return {{(uint8_t*) _queue.desc[e.id].addr, + (gsl::span::size_type) e.len }, Token::IN}; +} +std::vector Virtio::Queue::dequeue_chain() { + + std::vector result; + + // Return NULL if there are no more completed buffers in the queue + if (_last_used_idx == _queue.used->idx){ + debug(" Can't dequeue - no used buffers \n",_pci_index); + return result; + } + debug(" Dequeueing last_used index %i ",_pci_index, _last_used_idx); + // Get next completed buffer + auto* e = &_queue.used->ring[_last_used_idx % _size]; + + auto* unchain = &_queue.desc[e->id]; + do + { + result.emplace_back( + Token::span{ (uint8_t*) unchain->addr, unchain->len }, Token::IN); + unchain = &_queue.desc[ unchain->next ]; + } + while (unchain->flags & VIRTQ_DESC_F_NEXT); + // Release buffer + debug(" Releasing token @%p, nr. %i Len: %i\n",_pci_index, e, e->id, e->len); release(e->id); _last_used_idx++; - - Token token1 {{(uint8_t*) _queue.desc[e->id].addr, (gsl::span::size_type) e->len }, Token::IN}; - - return token1; + + return result; } -void Virtio::Queue::set_data_handler(delegate del){ - _data_handler=del; +void Virtio::Queue::set_data_handler(data_handler_t del) { + _data_handler = del; } void Virtio::Queue::disable_interrupts(){ From 4196f613a367c8723c3e9fd9d86af2347a4da839 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Thu, 21 Apr 2016 14:33:41 +0200 Subject: [PATCH 201/311] test: Fix test_disk service --- src/debug/test_disk.cpp | 116 +++++++++++++++++++--------------------- 1 file changed, 56 insertions(+), 60 deletions(-) diff --git a/src/debug/test_disk.cpp b/src/debug/test_disk.cpp index 7c8c94e845..c8b61fa5bf 100644 --- a/src/debug/test_disk.cpp +++ b/src/debug/test_disk.cpp @@ -28,12 +28,17 @@ void Service::start() });*/ // 2. create alot of sequential jobs of 1024 sectors each // note: if we queue more than this we will run out of RAM + static int bufcounter = 0; + for (int i = 0; i < 256; i++) device.read(0, 22, [i] (fs::buffer_t buffer) { - printf("buffer %d is not null: %d\n", i, !!buffer); assert(buffer); + bufcounter++; + + if (bufcounter == 256) + printf("Success: All big buffers accounted for\n"); }); //return; @@ -42,69 +47,60 @@ void Service::start() // mount first valid partition (auto-detect and mount) disk->mount( - [] (fs::error_t err) - { - if (err) - { - printf("Could not mount filesystem\n"); - return; - } - - // async ls - disk->fs().ls("/", - [] (fs::error_t err, auto ents) - { - if (err) - { - printf("Could not list '/' directory\n"); - return; - } - - // go through directory entries - for (auto& e : *ents) - { - printf("%s: %s\t of size %llu bytes (CL: %llu)\n", - e.type_string().c_str(), e.name().c_str(), e.size, e.block); - - if (e.is_file()) - { - printf("*** Attempting to read: %s\n", e.name().c_str()); - disk->fs().read(e, 0, e.size, - [e] (fs::error_t err, fs::buffer_t buffer, size_t len) - { - if (err) - { - printf("Failed to read file %s!\n", - e.name().c_str()); - return; - } - - std::string contents((const char*) buffer.get(), len); - printf("[%s contents]:\n%s\nEOF\n\n", - e.name().c_str(), contents.c_str()); - }); - } - } - }); - - }); // disk->auto_detect() - + [] (fs::error_t err) { + if (err) { + printf("Could not mount filesystem\n"); + return; + } + printf("Mounted filesystem\n"); + + // async ls + disk->fs().ls("/", + [] (fs::error_t err, auto ents) { + if (err) { + printf("Could not list '/' directory\n"); + return; + } + printf("Listed filesystem root\n"); + + // go through directory entries + for (auto& e : *ents) { + printf("%s: %s\t of size %llu bytes (CL: %llu)\n", + e.type_string().c_str(), e.name().c_str(), e.size, e.block); + + if (e.is_file()) { + printf("*** Attempting to read: %s\n", e.name().c_str()); + disk->fs().read(e, 0, e.size, + [e] (fs::error_t err, fs::buffer_t buffer, size_t len) { + if (err) { + printf("Failed to read file %s!\n", + e.name().c_str()); + return; + } + + std::string contents((const char*) buffer.get(), len); + printf("[%s contents]:\n%s\nEOF\n\n", + e.name().c_str(), contents.c_str()); + }); + } + } + }); // ls + }); // disk->auto_detect() + printf("*** TEST SERVICE STARTED *** \n"); } void list_partitions(decltype(disk) disk) { disk->partitions( - [] (fs::error_t err, auto& parts) - { - if (err) - { - printf("Failed to retrieve volumes on disk\n"); - return; - } - - for (auto& part : parts) - printf("[Partition] '%s' at LBA %u\n", - part.name().c_str(), part.lba()); - }); + [] (fs::error_t err, auto& parts) { + if (err) { + printf("Failed to retrieve volumes on disk\n"); + return; + } + + for (auto& part : parts) + printf("[Partition] '%s' at LBA %u\n", + part.name().c_str(), part.lba()); + }); } From 35ed5dc2dbf05b3719d2ee80c128d23bc31da52e Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Thu, 21 Apr 2016 14:46:57 +0200 Subject: [PATCH 202/311] test: Cleanup in test_disk --- api/hw/disk_device.hpp | 1 - src/debug/test_disk.cpp | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/api/hw/disk_device.hpp b/api/hw/disk_device.hpp index 75c47419fb..e790e8c8b7 100644 --- a/api/hw/disk_device.hpp +++ b/api/hw/disk_device.hpp @@ -21,7 +21,6 @@ #include #include -#include #include namespace hw diff --git a/src/debug/test_disk.cpp b/src/debug/test_disk.cpp index c8b61fa5bf..168bf0e986 100644 --- a/src/debug/test_disk.cpp +++ b/src/debug/test_disk.cpp @@ -2,9 +2,8 @@ #include const char* service_name__ = "..."; -#include #include -std::shared_ptr disk; +fs::Disk_ptr disk; void list_partitions(decltype(disk)); @@ -69,7 +68,7 @@ void Service::start() e.type_string().c_str(), e.name().c_str(), e.size, e.block); if (e.is_file()) { - printf("*** Attempting to read: %s\n", e.name().c_str()); + printf("*** Read file %s\n", e.name().c_str()); disk->fs().read(e, 0, e.size, [e] (fs::error_t err, fs::buffer_t buffer, size_t len) { if (err) { From ead5c8130001a26e29a96d08a241ccc4e414a59d Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Thu, 21 Apr 2016 14:59:34 +0200 Subject: [PATCH 203/311] fs: Remove vbr module --- api/fs/vbr.hpp | 30 ------------------------------ src/Makefile | 2 +- src/fs/vbr.cpp | 6 ------ 3 files changed, 1 insertion(+), 37 deletions(-) delete mode 100644 api/fs/vbr.hpp delete mode 100644 src/fs/vbr.cpp diff --git a/api/fs/vbr.hpp b/api/fs/vbr.hpp deleted file mode 100644 index dbb145b7bf..0000000000 --- a/api/fs/vbr.hpp +++ /dev/null @@ -1,30 +0,0 @@ -// This file is a part of the IncludeOS unikernel - www.includeos.org -// -// Copyright 2015 Oslo and Akershus University College of Applied Sciences -// and Alfred Bratterud -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once -#ifndef FS_VBR_HPP -#define FS_VBR_HPP - -namespace fs { - - class VBR { - - }; //< class VBR - -} //< namespace fs - -#endif //< FS_VBR_HPP diff --git a/src/Makefile b/src/Makefile index d01ab2d761..49e8620b42 100644 --- a/src/Makefile +++ b/src/Makefile @@ -73,7 +73,7 @@ OS_OBJECTS = kernel/kernel_start.o kernel/syscalls.o \ net/dns/dns.o net/dns/client.o net/dhcp/dh4client.o \ net/ip6/ip6.o net/ip6/icmp6.o net/ip6/udp6.o net/ip6/ndp.o \ net/packet.o net/buffer_store.o \ - fs/disk.o fs/filesystem.o fs/mbr.o fs/vbr.o fs/path.o \ + fs/disk.o fs/filesystem.o fs/mbr.o fs/path.o \ fs/ext4.o fs/fat.o fs/fat_async.o fs/fat_sync.o fs/memdisk.o \ virtio/block.o # virtio/console.o diff --git a/src/fs/vbr.cpp b/src/fs/vbr.cpp deleted file mode 100644 index ee9eccbf52..0000000000 --- a/src/fs/vbr.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include - -namespace fs -{ - -} From 739647ee6f20aa3b397f814d63613252c69ee805 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Thu, 21 Apr 2016 17:02:25 +0200 Subject: [PATCH 204/311] test: VirtioBlk test now reads a file! --- test/virtio_block/service.cpp | 85 +++++++++++++++++------------------ test/virtio_block/test.py | 9 +++- test/virtio_block/vm.json | 2 +- 3 files changed, 50 insertions(+), 46 deletions(-) diff --git a/test/virtio_block/service.cpp b/test/virtio_block/service.cpp index f36e8829db..bfce3b43d7 100644 --- a/test/virtio_block/service.cpp +++ b/test/virtio_block/service.cpp @@ -30,61 +30,58 @@ void Service::start() // instantiate memdisk with FAT filesystem auto& device = hw::Dev::disk<1, VirtioBlk>(); disk = std::make_shared (device); - - CHECKSERT(disk,"Disk created"); - - // if the disk is empty, we can't mount a filesystem anyways + // assert that we have a disk + CHECKSERT(disk, "Disk created"); + // if the disk is empty, we can't mount a filesystem CHECKSERT(not disk->empty(), "Disk is not empty"); - disk->dev().read(1, [](auto buf){ - printf(" Sector 1: \n %s \n", buf.get()); - }); - // list extended partitions list_partitions(disk); - - - // mount first valid partition (auto-detect and mount) - disk->mount([] (fs::error_t err) { + disk->mount( + [] (fs::error_t err) { + if (err) { + printf("Could not mount filesystem\n"); + panic("mount() failed"); + } + + // async ls + disk->fs().ls("/", + [] (fs::error_t err, auto ents) { if (err) { - printf("Could not mount filesystem\n"); - return; + printf("Could not list '/' directory\n"); + panic("ls() failed"); } - // async ls - disk->fs().ls("/", [] (fs::error_t err, auto ents) { - if (err) { - printf("Could not list '/' directory\n"); - return; + // go through directory entries + for (auto& e : *ents) { + printf("%s: %s\t of size %llu bytes (CL: %llu)\n", + e.type_string().c_str(), e.name().c_str(), e.size, e.block); + + if (e.is_file()) { + printf("*** Read %s\n", e.name().c_str()); + disk->fs().read(e, 0, e.size, + [e] (fs::error_t err, fs::buffer_t buffer, size_t len) { + if (err) { + printf("Failed to read %s!\n", e.name().c_str()); + panic("read() failed"); } - // go through directory entries - for (auto& e : *ents) { - printf("%s: %s\t of size %llu bytes (CL: %llu)\n", - e.type_string().c_str(), e.name().c_str(), e.size, e.block); - - if (e.is_file()) { - printf("*** Attempting to read: %s\n", e.name().c_str()); - disk->fs().read(e, 0, e.size, [e] (fs::error_t err, fs::buffer_t buffer, size_t len) { - if (err) { - printf("Failed to read file %s!\n", - e.name().c_str()); - return; - } - - std::string contents((const char*) buffer.get(), len); - printf("[%s contents]:\n%s\nEOF\n\n", - e.name().c_str(), contents.c_str()); - }); - } - } - - INFO("Virtioblk Test", "SUCCESS"); - }); - - }); // disk->auto_detect() + std::string contents((const char*) buffer.get(), len); + printf("[%s contents]:\n%s\nEOF\n\n", + e.name().c_str(), contents.c_str()); + // --- + INFO("Virtioblk Test", "SUCCESS"); + }); + + } // is_file + + } // ents + + }); // ls + + }); // disk->auto_detect() printf("*** TEST SERVICE STARTED *** \n"); diff --git a/test/virtio_block/test.py b/test/virtio_block/test.py index 1b330254fe..7077e306b0 100755 --- a/test/virtio_block/test.py +++ b/test/virtio_block/test.py @@ -1,7 +1,14 @@ #! /usr/bin/python - import sys +import subprocess + sys.path.insert(0,"..") +subprocess.call(['./image.sh']) + +def cleanup(): + subprocess.call(['./cleanup.sh']) import vmrunner +vmrunner.on_success = cleanup +vmrunner.on_panic = cleanup vmrunner.vms[0].boot() diff --git a/test/virtio_block/vm.json b/test/virtio_block/vm.json index 07b9763598..7c10b1a08f 100644 --- a/test/virtio_block/vm.json +++ b/test/virtio_block/vm.json @@ -1,6 +1,6 @@ { "image" : "test_virtio_block.img", - "drives" : [{"file" : "test.txt", + "drives" : [{"file" : "image.img", "type" : "virtio", "format": "raw" }] } From 18a3d1141b461ba1e45457ae48ce7326cd07281e Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Thu, 21 Apr 2016 17:16:00 +0200 Subject: [PATCH 205/311] test: Add missing and connect callbacks --- test/virtio_block/cleanup.sh | 4 ++++ test/virtio_block/image.sh | 13 +++++++++++++ test/virtio_block/test.py | 12 ++++++++++-- test/vmrunner.py | 2 +- 4 files changed, 28 insertions(+), 3 deletions(-) create mode 100755 test/virtio_block/cleanup.sh create mode 100755 test/virtio_block/image.sh diff --git a/test/virtio_block/cleanup.sh b/test/virtio_block/cleanup.sh new file mode 100755 index 0000000000..0791ac7974 --- /dev/null +++ b/test/virtio_block/cleanup.sh @@ -0,0 +1,4 @@ +#!/bin/bash +echo "Cleaning up after test..." +rm image.img +echo "Done" diff --git a/test/virtio_block/image.sh b/test/virtio_block/image.sh new file mode 100755 index 0000000000..02c6de718b --- /dev/null +++ b/test/virtio_block/image.sh @@ -0,0 +1,13 @@ +#!/bin/bash +echo "Creating *huge* disk for test" +fallocate -l 400000000 image.img +mkfs.fat image.img + +mkdir -p mountpoint +sudo mount -o rw image.img mountpoint + +sudo cp service.cpp mountpoint/ + +sudo umount mountpoint +rmdir mountpoint +echo "Done" diff --git a/test/virtio_block/test.py b/test/virtio_block/test.py index 7077e306b0..e21ab8f379 100755 --- a/test/virtio_block/test.py +++ b/test/virtio_block/test.py @@ -8,7 +8,15 @@ def cleanup(): subprocess.call(['./cleanup.sh']) +def success(): + print "FGERSGERGER" + cleanup() + exit(0, " SUCCESS : All tests passed") +def failure(): + cleanup() + exit(66, " FAIL : what happen") + import vmrunner -vmrunner.on_success = cleanup -vmrunner.on_panic = cleanup +vmrunner.vms[0].on_success(success) +vmrunner.vms[0].on_panic(failure) vmrunner.vms[0].boot() diff --git a/test/vmrunner.py b/test/vmrunner.py index 5c10ebf60a..8cbfddcf81 100644 --- a/test/vmrunner.py +++ b/test/vmrunner.py @@ -154,7 +154,7 @@ def on_output(self, output, callback): def on_success(self, callback): self._on_success = callback - def on_panic(self, callack): + def on_panic(self, callback): self._on_panic = callback def on_timeout(self, callback): From 9aba95df0474c557901496e01f68d60175671acc Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Thu, 21 Apr 2016 17:40:07 +0200 Subject: [PATCH 206/311] virtioblk: Fix FAT32 detection in mount() --- src/fs/disk.cpp | 5 +++-- src/fs/fat.cpp | 20 ++++++++++++-------- test/virtio_block/image.sh | 2 +- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/fs/disk.cpp b/src/fs/disk.cpp index bfa2942fef..850bbac595 100644 --- a/src/fs/disk.cpp +++ b/src/fs/disk.cpp @@ -67,10 +67,11 @@ namespace fs { // auto-detect FAT on MBR: auto* mbr = (MBR::mbr*) data.get(); MBR::BPB* bpb = mbr->bpb(); - + if (bpb->bytes_per_sector >= 512 && bpb->fa_tables != 0 - && bpb->signature != 0) // check MBR signature too + && (bpb->signature != 0 // check MBR signature too + || bpb->large_sectors != 0)) // but its not set for FAT32 { // detected FAT on MBR filesys.reset(new FAT(device)); diff --git a/src/fs/fat.cpp b/src/fs/fat.cpp index 483851ea43..01f85911e4 100644 --- a/src/fs/fat.cpp +++ b/src/fs/fat.cpp @@ -10,13 +10,15 @@ #include // for panic() #include +//#undef debug +//#define debug(...) printf(__VA_ARGS__) #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) inline std::string trim_right_copy( - const std::string& s, - const std::string& delimiters = " \f\n\r\t\v" ) + const std::string& s, + const std::string& delimiters = " \f\n\r\t\v" ) { return s.substr( 0, s.find_last_not_of( delimiters ) + 1 ); } @@ -36,12 +38,14 @@ namespace fs MBR::BPB* bpb = mbr->bpb(); this->sector_size = bpb->bytes_per_sector; - if (unlikely(this->sector_size < 512)) - { - printf("Invalid sector size (%u) for FAT32 partition\n", sector_size); - printf("Are you mounting the correct partition?\n"); - panic("FAT32: Invalid sector size"); - } + + if (unlikely(this->sector_size < 512)) { + fprintf(stderr, + "Invalid sector size (%u) for FAT32 partition\n", sector_size); + fprintf(stderr, + "Are you mounting the correct partition?\n"); + panic("FAT32: Invalid sector size"); + } // Let's begin our incantation // To drive out the demons of old DOS we have to read some PBP values diff --git a/test/virtio_block/image.sh b/test/virtio_block/image.sh index 02c6de718b..dc399a18bc 100755 --- a/test/virtio_block/image.sh +++ b/test/virtio_block/image.sh @@ -1,6 +1,6 @@ #!/bin/bash echo "Creating *huge* disk for test" -fallocate -l 400000000 image.img +fallocate -l 4000000000 image.img mkfs.fat image.img mkdir -p mountpoint From 6d1c1b6b8c44ac6eecd1b3f5c2f34b7850e1e92e Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Fri, 22 Apr 2016 08:49:17 +0200 Subject: [PATCH 207/311] Corrected inclusion path for common --- src/net/ethernet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net/ethernet.cpp b/src/net/ethernet.cpp index 6161040442..1036ce9379 100644 --- a/src/net/ethernet.cpp +++ b/src/net/ethernet.cpp @@ -20,7 +20,7 @@ #include -#include +#include #include #include From e5f363c02fc293c5db16e2e7644427d00ae5fb37 Mon Sep 17 00:00:00 2001 From: Martin Nordsletten Date: Fri, 22 Apr 2016 10:23:09 +0200 Subject: [PATCH 208/311] Changed environment variable to INCLUDEOS_INSTALL in copy_script Used a variable called INSTALL_DIR that is not used anymore. INCLUDEOS_INSTALL is the one to use. --- etc/copy_scripts.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/etc/copy_scripts.sh b/etc/copy_scripts.sh index bdd5971ff9..86fe8fdd00 100755 --- a/etc/copy_scripts.sh +++ b/etc/copy_scripts.sh @@ -1,9 +1,9 @@ #!/bin/bash INCLUDEOS_SRC=${INCLUDEOS_SRC-$HOME/IncludeOS/} -INSTALL_DIR=${INSTALL_DIR-$HOME/IncludeOS_install} -mkdir -p $INSTALL_DIR/etc -cp $INCLUDEOS_SRC/etc/qemu-ifup $INSTALL_DIR/etc/ -cp $INCLUDEOS_SRC/etc/qemu_cmd.sh $INSTALL_DIR/etc/ -cp $INCLUDEOS_SRC/etc/run.sh $INSTALL_DIR/etc/ +INCLUDEOS_INSTALL=${INCLUDEOS_INSTALL-$HOME/IncludeOS_install} +mkdir -p $INCLUDEOS_INSTALL/etc +cp $INCLUDEOS_SRC/etc/qemu-ifup $INCLUDEOS_INSTALL/etc/ +cp $INCLUDEOS_SRC/etc/qemu_cmd.sh $INCLUDEOS_INSTALL/etc/ +cp $INCLUDEOS_SRC/etc/run.sh $INCLUDEOS_INSTALL/etc/ From 445e7657c39171f0d16530becdc17b1dee770003 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Mon, 25 Apr 2016 10:21:34 +0200 Subject: [PATCH 209/311] tcp: more work on congestion control --- api/net/tcp.hpp | 95 ++++-------- src/net/tcp.cpp | 26 +++- src/net/tcp_connection.cpp | 246 ++++++++++++++++-------------- src/net/tcp_connection_states.cpp | 11 +- 4 files changed, 193 insertions(+), 185 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index 93bd635ab5..051e1d68ad 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -387,6 +387,9 @@ namespace net { inline bool has_data() const { return data_length() > 0; } + inline uint16_t size_available() const + { return size() - all_headers_len() - data_length(); } + inline uint16_t tcp_length() const { return header_size() + data_length(); } template @@ -1394,10 +1397,6 @@ namespace net { // RFC 3042 void limited_tx(); - inline void try_limited_tx() { - if( (send_window() > 0) and ( (flight_size() + 2*SMSS() ) <= cb.cwnd) ) - limited_tx(); - } /// TCB HANDLING /// @@ -1406,9 +1405,14 @@ namespace net { */ inline Connection::TCB& tcb() { return cb; } - inline int32_t usable_window() const { - auto x = (int64_t)congestion_window() - (int64_t)cb.SND.NXT; - return (int32_t) x; + /* + + SND.UNA + SND.WND - SND.NXT + SND.UNA + WINDOW - SND.NXT + */ + inline uint32_t usable_window() const { + auto x = (int64_t)send_window() - (int64_t)flight_size(); + return (uint32_t) std::max(0ll, x); } /* @@ -1416,38 +1420,41 @@ namespace net { Note: Made a function due to future use when Window Scaling Option is added. */ - inline int32_t send_window() const { - return (int32_t)cb.SND.WND; + inline uint32_t send_window() const { + return std::min((uint32_t)cb.SND.WND, cb.cwnd); } inline int32_t congestion_window() const { - auto win = cb.SND.UNA + std::min((int32_t)cb.cwnd, send_window()); - return win; + auto win = (uint64_t)cb.SND.UNA + std::min((uint64_t)cb.cwnd, (uint64_t)send_window()); + return (int32_t)win; } /* Acknowledge a packet - TCB update, Congestion control handling, RTT calculation and RT handling. */ - void acknowledge(Seq ACK); - - void handle_ack(TCP::Packet_ptr); + bool handle_ack(TCP::Packet_ptr); void on_dup_ack(); inline bool can_send_one() - { return (std::min(cb.cwnd, (uint32_t)send_window()) >= SMSS()) and !writeq.empty(); } + { return send_window() >= SMSS() and !writeq.empty(); } + inline bool need_send() + { return rtx_q.empty(); } + + bool can_send(); + size_t send_much(); //void send_ack(TCP::Packet_ptr = nullptr); /// Congestion Control [RFC 5681] /// - bool RENO_FAST_RECOVERY = false; + bool fast_recovery = false; // First partial ack seen bool reno_fpack_seen = false; size_t dup_acks_ = 0; - Seq prev_high_ack_ = 0; + Seq prev_highest_ack_ = 0; Seq highest_ack_ = 0; Seq RENO_PREV_HIGHEST_ACK = 0; @@ -1462,8 +1469,8 @@ namespace net { inline uint16_t RMSS() const { return cb.SND.MSS; } - inline int32_t flight_size() const - { return cb.SND.NXT - cb.SND.UNA; } + inline uint32_t flight_size() const + { return (uint64_t)cb.SND.NXT - (uint64_t)cb.SND.UNA; } /// Reno /// @@ -1481,8 +1488,6 @@ namespace net { inline void reno_init_sshtresh() { cb.ssthresh = cb.SND.WND; } - inline bool reno_slow_start() const - { return cb.cwnd < cb.ssthresh; } inline void reno_increase_cwnd(uint16_t n) { cb.cwnd += std::min(n, SMSS()); } @@ -1491,9 +1496,9 @@ namespace net { { cb.cwnd -= (n >= SMSS()) ? n-SMSS() : n; } inline void reduce_ssthresh() { - cb.ssthresh = std::max( (flight_size() / 2), (2 * SMSS()) ); - //printf(" Slow start threshold reduced: %u\n", - // cb.ssthresh); + cb.ssthresh = std::max( (flight_size() / 2), (2 * (uint32_t)SMSS()) ); + printf(" Slow start threshold reduced: %u\n", + cb.ssthresh); } inline void fast_retransmit() { @@ -1504,40 +1509,16 @@ namespace net { retransmit(); // inflate congestion window with the 3 packets we got dup ack on. cb.cwnd = cb.ssthresh + 3*SMSS(); + fast_recovery = true; } inline void finish_fast_recovery() { - dup_acks_ = 0; reno_fpack_seen = false; - cb.cwnd = std::min((int32_t)cb.ssthresh, std::max(flight_size(), (int32_t)SMSS()) + SMSS()); + fast_recovery = false; + cb.cwnd = std::min(cb.ssthresh, std::max(flight_size(), (uint32_t)SMSS()) + SMSS()); printf(" Finished Fast Recovery - Cwnd: %u\n", cb.cwnd); } - - inline bool reno_is_dup_ack(TCP::Packet_ptr in) { - bool is_dup_ack = flight_size() > 0 - and !in->has_data() - and !in->isset(FIN) and !in->isset(SYN) - //and ((in->flags() & (FIN | SYN)) == 0) - and in->win() == cb.SND.WND; - - return is_dup_ack; - } - - - inline void reno_enter_fast_recovery() { - cb.cwnd = cb.ssthresh + (3 * SMSS()); - RENO_FAST_RECOVERY = true; - reno_fpack_seen = true; - printf(" Entered Fast Recovery - Cwnd: %u\n", cb.cwnd); - } - - inline void reno_exit_fast_recovery() { - cb.cwnd = std::min((int32_t)cb.ssthresh, std::max(flight_size(), (int32_t)SMSS()) + SMSS()); - RENO_FAST_RECOVERY = false; - printf(" Exited Fast Recovery - Cwnd: %u\n", cb.cwnd); - } - inline bool reno_should_recover(Seq ACK) { return (ACK - 1 > cb.recover) or reno_heuristic_segment_loss_detected(); } @@ -1551,18 +1532,6 @@ namespace net { return ACK - 1 > cb.recover; } - inline bool reno_partial_ack(Seq ACK) { - return !reno_full_ack(ACK); - } - - inline bool reno_is_fast_recovering() { - return RENO_FAST_RECOVERY; - } - - inline void reno_update_recover() { - cb.recover = cb.SND.NXT; - } - void reno_update_heuristic_ack(Seq ACK) { RENO_PREV_HIGHEST_ACK = RENO_HIGHEST_ACK; RENO_HIGHEST_ACK = ACK; diff --git a/src/net/tcp.cpp b/src/net/tcp.cpp index 1d0bd120c1..8888e0e800 100644 --- a/src/net/tcp.cpp +++ b/src/net/tcp.cpp @@ -190,6 +190,9 @@ void TCP::process_write_queue(size_t packets) { while(packets and !write_queue.empty()) { auto conn = write_queue.front(); write_queue.pop(); + conn->offer(packets); + conn->set_queued(false); + /* // try to offer if there is any doable job, and if still more to do, requeue. if(conn->has_doable_job() and !conn->offer(packets)) { debug2("TCP::process_write_queue> %s still has more to do. Re-queued.\n"); @@ -201,6 +204,7 @@ void TCP::process_write_queue(size_t packets) { debug2(" %s Removed from queue. Size is %u\n", conn->to_string().c_str(), write_queue.size()); } + */ } } @@ -215,13 +219,31 @@ size_t TCP::send(Connection_ptr conn, Connection::WriteBuffer& buffer, size_t n) if(written < buffer.remaining and !conn->is_queued()) { write_queue.push(conn); conn->set_queued(true); - printf(" %s wrote %u bytes (%u remaining) and is Re-queued.\n", + debug(" %s wrote %u bytes (%u remaining) and is Re-queued.\n", conn->to_string().c_str(), written, buffer.remaining-written); } return written; } +/* +size_t TCP::send(Connection_ptr conn, Connection::WriteBuffer& buffer, size_t n) { + size_t written{0}; + auto packets = inet_.transmit_queue_available(); + + if(packets > 0) { + conn->offer(packets); + } + // if connection still can send (means there wasn't enough packets) + if(conn->can_send()) { + writeq.push_back(conn); + conn->set_queued(true); + } + + return written; +} +*/ + /* Show all connections for TCP as a string. @@ -271,6 +293,8 @@ void TCP::transmit(TCP::Packet_ptr packet) { // Translate into a net::Packet_ptr and send away. // Generate checksum. packet->set_checksum(TCP::checksum(packet)); + //if(packet->has_data()) + // printf(" S: %u\n", packet->seq()); //packet->set_checksum(checksum(packet)); _network_layer_out(packet); } diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index 588ab73e49..dc4b424479 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -121,7 +121,7 @@ bool Connection::offer(size_t& packets) { debug(" %s got offered [%u] packets. Usable window is %i.\n", to_string().c_str(), packets, usable_window()); - while(has_doable_job() and packets and dup_acks_ < 3) { + while(has_doable_job() and packets and !fast_recovery) { auto& buf = writeq.front().first; // segmentize the buffer into packets auto written = send(buf, packets, buf.remaining); @@ -140,7 +140,7 @@ bool Connection::offer(size_t& packets) { assert(packets >= 0); debug(" Finished working offer with [%u] packets left and a queue of (%u) with a usable window of %i\n", packets, writeq.size(), usable_window()); - return !has_doable_job() or dup_acks_ >= 3; + return !has_doable_job() or fast_recovery; } // TODO: This is starting to get complex and ineffective, refactor.. @@ -178,9 +178,9 @@ size_t Connection::send(const char* buffer, size_t remaining, size_t& packet_cou debug2(" Packet Limit: %u - Written: %u" " - Remaining: %u - Packet count: %u, Window: %u\n", packet_limit, written, remaining, packet_count, usable_window()); - if(reno_is_fast_recovering()) break; + //if(reno_is_fast_recovering()) break; } - debug(" Sent %u bytes of data\n", bytes_written); + //printf(" Sent %u bytes of data\n", bytes_written); return bytes_written; } @@ -194,6 +194,50 @@ size_t Connection::send(const char* buffer, size_t n, Packet_ptr packet, bool PU return written; } +/*size_t Connection::fill(Packet_ptr packet, const char* buffer, size_t length, bool PUSH) { + Expects(!packet->has_data()); + Expects(length > 0); + + // fill packet with data from buffer + auto written = packet->fill(buffer, n); + // setup numbers + packet->set_seq(cb.SND.NXT).set_ack(cb.RCV.NXT).set_flag(ACK); + if(PUSH) + packet->set_flag(PSH); + + // advance sequence number + cb.SND.NXT += packet->data_length(); + + Ensures(written > 0); + Ensures(written == packet->data_length()); + + return written; +}*/ + +/*void Connection::pre_process(Packet_ptr packet) { + +} + +void Connection::post_process(Packet_ptr packet) { + +} + +void Connection::set_window(Packet_ptr packet) { + packet->set_win(cb.RCV.WND); +} + +void Connection::make_flight_ready(Packet_ptr packet) { + set_window(packet); + + // Set Source (local == the current connection) + packet->set_source(local()); + // Set Destination (remote) + packet->set_destination(remote_); + + // set correct sequence numbers + packet->set_seq(cb.SND.NXT).set_ack(cb.RCV.NXT); +}*/ + void Connection::writeq_push() { while(!writeq.empty()) { auto& buf = writeq.front().first; @@ -208,8 +252,8 @@ void Connection::writeq_push() { void Connection::limited_tx() { auto& buf = writeq.front().first; - auto written = send((char*)buf.pos(), std::min(buf.remaining, (uint32_t)SMSS()), create_outgoing_packet(), false); - //printf(" Limited transmit. %u written\n", written); + printf(" UW: %u CW: %u, FS: %u\n", usable_window(), cb.cwnd, flight_size()); + auto written = send((char*)buf.pos(), std::min(buf.remaining, (uint32_t)RMSS()), create_outgoing_packet(), false); buf.advance(written); if(buf.remaining) return; @@ -311,7 +355,7 @@ TCP::Packet_ptr Connection::create_outgoing_packet() { // Set Destination (remote) packet->set_destination(remote_); - packet->set_win(cb.SND.WND); + packet->set_win(cb.RCV.WND); // Set SEQ and ACK - I think this is OK.. packet->set_seq(cb.SND.NXT).set_ack(cb.RCV.NXT); @@ -326,6 +370,8 @@ void Connection::transmit(TCP::Packet_ptr packet) { //printf(" Starting RTT measurement.\n"); rttm.start(); } + if(packet->seq() + packet->data_length() < cb.SND.NXT) + printf(" Transmitting: %u \n", packet->seq() - cb.ISS); host_.transmit(packet); if(packet->has_data()) @@ -333,37 +379,61 @@ void Connection::transmit(TCP::Packet_ptr packet) { if(!rtx_timer.active) rtx_start(); } -/* -void Connection::retransmit() { - printf(" \n"); + +bool Connection::can_send() { + return (usable_window() >= RMSS()) and !writeq.empty(); } -void Connection::fast_retransmit() { - printf(" \n"); - retransmit(); +size_t Connection::send_much() { + size_t bytes_written = 0; + auto uw = usable_window(); -} + while(can_send()) { + auto& buf = writeq.front().first; + auto written = send((char*)buf.pos(), std::min(buf.remaining, (uint32_t)RMSS()), create_outgoing_packet(), false); + bytes_written += written; + buf.advance(written); + if(!buf.remaining) { + writeq.front().second(buf.offset); + writeq.pop(); + } + } + + //printf(" Prev UW: %u UW: %u CW: %u, FS: %u BW: %u\n", + // uw, usable_window(), cb.cwnd, flight_size(), bytes_written); -void Connection::finish_fast_recovery() { - printf(" \n"); + return bytes_written; } -void Connection::on_rtx_timeout() { - printf(" \n"); +/*size_t Connection::send_one() { + + } -void Connection::limited_tx() { - if(flight_size() <= ) +size_t Connection::send(const char* data, size_t n, size_t& packets) { + } */ +bool Connection::handle_ack(TCP::Packet_ptr in) { + // dup ack + /* + 1. Same ACK as latest received + 2. outstanding data + 3. packet is empty + 4. is not an wnd update + */ + if(in->ack() == cb.SND.UNA and flight_size() + and !in->has_data() and cb.SND.WND == in->win() + and !in->isset(SYN) and !in->isset(FIN)) + { + dup_acks_++; + on_dup_ack(); + return false; + } // < dup ack -void Connection::handle_ack(TCP::Packet_ptr in) { // new ack - if(in->ack() > cb.SND.UNA) { - // [RFC 6582] p. 8 - //prev_highest_ack_ = cb.SND.UNA; - //highest_ack_ = in->ack(); + else if(in->ack() >= cb.SND.UNA) { if( cb.SND.WL1 < in->seq() or ( cb.SND.WL1 == in->seq() and cb.SND.WL2 <= in->ack() ) ) { @@ -373,6 +443,10 @@ void Connection::handle_ack(TCP::Packet_ptr in) { debug2(" Usable window slided (%i)\n", tcp.usable_window()); } + // [RFC 6582] p. 8 + prev_highest_ack_ = cb.SND.UNA; + highest_ack_ = in->ack(); + // used for cwnd calculation (Reno) size_t bytes_acked = in->ack() - cb.SND.UNA; cb.SND.UNA = in->ack(); @@ -390,9 +464,10 @@ void Connection::handle_ack(TCP::Packet_ptr in) { } // no fast recovery - if(dup_acks_ < 3) { + if(!fast_recovery) { dup_acks_ = 0; + cb.recover = cb.SND.NXT; // slow start if(cb.slow_start()) { @@ -403,16 +478,16 @@ void Connection::handle_ack(TCP::Packet_ptr in) { else { // increase cwnd once per RTT cb.cwnd += std::max(SMSS()*SMSS()/cb.cwnd, (uint32_t)1); - //if(cong_avoid_rtt) { - /* - Not sure about this one.. - If timer is active, it means this ACK will stop the timer => one RTT. - Not sure how this works with retransmission. - */ - //reno_increase_cwnd(bytes_acked); - //} } // < congestion avoidance + // try to write + if(can_send()) + send_much(); + + // if data, let state continue process + if(in->has_data() or in->isset(FIN)) + return true; + } // < !fast recovery // we're in fast recovery @@ -424,6 +499,8 @@ void Connection::handle_ack(TCP::Packet_ptr in) { //printf(" Recovery - Partial ACK\n"); retransmit(); + dup_acks_ = 0; + if(!reno_fpack_seen) { rtx_reset(); reno_fpack_seen = true; @@ -432,10 +509,14 @@ void Connection::handle_ack(TCP::Packet_ptr in) { // send one segment if possible if(can_send_one()) limited_tx(); + + if(in->has_data() or in->isset(FIN)) + return true; } // < partial ack // full ack else { + dup_acks_ = 0; finish_fast_recovery(); } // < full ack @@ -443,46 +524,35 @@ void Connection::handle_ack(TCP::Packet_ptr in) { } // < new ack - // dup ack - /* - 1. Same ACK as latest received - 2. outstanding data - 3. packet is empty - 4. is not an wnd update - */ - else if(in->ack() == cb.SND.UNA and flight_size() - and !in->has_data() and cb.SND.WND == in->win()) - { - dup_acks_++; - on_dup_ack(); - } // < dup ack - // ACK outside else { - + return true; } + return false; } - /* Reno [RFC 5681] p. 9 What to do when received ACK is a duplicate. */ void Connection::on_dup_ack() { - printf(" %u\n", dup_acks_); + //printf(" %u\n", dup_acks_); // if less than 3 dup acks if(dup_acks_ < 3) { // try to send one segment - if(cb.SND.WND >= SMSS() and (flight_size() <= cb.cwnd + dup_acks_*SMSS()) and !writeq.empty()) + if(cb.SND.WND >= SMSS() and (flight_size() <= cb.cwnd + 2*SMSS()) and !writeq.empty()) limited_tx(); } // 3 dup acks else if(dup_acks_ == 3) { printf(" Dup ACK == 3 - %u\n", cb.SND.UNA); - if(cb.SND.UNA - 1 > cb.recover) { + + if(cb.SND.UNA - 1 > cb.recover + or ( congestion_window() > SMSS() and (highest_ack_ - prev_highest_ack_ <= 4*SMSS()) )) + { cb.recover = cb.SND.NXT; printf(" Enter Recovery - Flight Size: %u\n", flight_size()); fast_retransmit(); @@ -493,68 +563,11 @@ void Connection::on_dup_ack() { else { cb.cwnd += SMSS(); // send one segment if possible - if(can_send_one()) + if(can_send()) limited_tx(); } } -/* - As specified in [RFC3390], the SYN/ACK and the acknowledgment of the - SYN/ACK MUST NOT increase the size of the congestion window. - Further, if the SYN or SYN/ACK is lost, the initial window used by a - sender after a correctly transmitted SYN MUST be one segment - consisting of at most SMSS bytes. -*/ -/*void Connection::acknowledge(Seq ACK) { - DUP_ACK = 0; - size_t bytes_acked = ACK - cb.SND.UNA; - cb.SND.UNA = ACK; - - - rtx_ack(ACK); - - reno_update_heuristic_ack(ACK); - if(!reno_is_fast_recovering()) { - if(reno_slow_start()) { - reno_increase_cwnd(bytes_acked); - debug2(" Slow start - cwnd increased: %u\n", - cb.cwnd); - } - // congestion avoidance - else { - if(rttm.active) { - reno_increase_cwnd(bytes_acked); - debug2(" Congestion avoidance - cwnd increased: %u\n", - cb.cwnd); - } - } - } - // fast recovery - else { - // full acknowledgement - if(reno_full_ack(ACK)) { - reno_exit_fast_recovery(); - } - // partial acknowledgement - else { - //fast_rtx(); - retransmit(); - reno_deflate_cwnd(bytes_acked); - if(RENO_FPACK_NOT_SEEN) { - printf(" #1 Partial ACK - %u, Cwnd: %u\n", ACK, cb.cwnd); - rt_restart(); - RENO_FPACK_NOT_SEEN = false; - } else { - //printf(" Partial ACK - %u, Cwnd: %u\n", ACK, cb.cwnd); - } - try_limited_tx(); - } - } - - if(rttm.active) - rttm.stop(); -}*/ - /* [RFC 6298] @@ -598,7 +611,7 @@ void Connection::retransmit() { if(rtx_q.empty()) return; auto packet = rtx_q.front(); - printf(" Retransmitting: %u \n", packet->seq()); + //printf(" Retransmitting: %u \n", packet->seq()); host_.transmit(packet); /* Every time a packet containing data is sent (including a @@ -613,12 +626,13 @@ void Connection::retransmit() { void Connection::rtx_start() { assert(!rtx_timer.active); auto i = rtx_timer.i; + auto rto = rttm.RTO; rtx_timer.iter = hw::PIT::instance().on_timeout(rttm.RTO, - [this, i] + [this, i, rto] { rtx_timer.active = false; - printf(" %s Timed out. rt_q: %u, i: %u rt_i: %u\n", - to_string().c_str(), rtx_q.size(), i, rtx_timer.i); + printf(" %i Timed out (%f). rt_q: %u, i: %u rt_i: %u\n", + local_port_, rto, rtx_q.size(), i, rtx_timer.i); rtx_timeout(); }); rtx_timer.i++; @@ -701,7 +715,7 @@ void Connection::rtx_timeout() { // update recover cb.recover = cb.SND.NXT; - if(dup_acks_ >= 3) // not sure if this is correct + if(fast_recovery) // not sure if this is correct finish_fast_recovery(); cb.cwnd = SMSS(); diff --git a/src/net/tcp_connection_states.cpp b/src/net/tcp_connection_states.cpp index dbb2e55321..44f52f1625 100644 --- a/src/net/tcp_connection_states.cpp +++ b/src/net/tcp_connection_states.cpp @@ -215,7 +215,7 @@ bool Connection::State::check_ack(Connection& tcp, TCP::Packet_ptr in) { // ACK is inside sequence space if(in->ack() <= tcb.SND.NXT ) { - tcp.handle_ack(in); + return tcp.handle_ack(in); // this is a "new" ACK //if(tcb.SND.UNA <= in->ack()) { @@ -316,7 +316,6 @@ void Connection::State::process_segment(Connection& tcp, TCP::Packet_ptr in) { auto& tcb = tcp.tcb(); auto length = in->data_length(); // Receive could result in a user callback. This is used to avoid sending empty ACK reply. - auto snd_nxt = tcb.SND.NXT; debug(" Received packet with DATA-LENGTH: %i. Add to receive buffer. \n", length); if(tcp.read_request.buffer.capacity()) { @@ -330,10 +329,12 @@ void Connection::State::process_segment(Connection& tcp, TCP::Packet_ptr in) { auto packet = tcp.outgoing_packet(); packet->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); tcp.transmit(packet); - if(tcp.has_doable_job() and !tcp.is_queued()) { - debug2(" Usable window: %i\n", tcp.usable_window()); + if(tcp.can_send()) + tcp.send_much(); + /*if(tcp.has_doable_job() and !tcp.is_queued()) { + printf(" Usable window: %i\n", tcp.usable_window()); tcp.writeq_push(); - } + }*/ /* WARNING/NOTE: From 9d6601a695956b19a3b0c2f24d02d4e75036f3ba Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Mon, 25 Apr 2016 10:27:23 +0200 Subject: [PATCH 210/311] DHCP timeout is now 30 sec --- api/net/inet4.inc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/net/inet4.inc b/api/net/inet4.inc index 1363b60d56..d06dbcebce 100644 --- a/api/net/inet4.inc +++ b/api/net/inet4.inc @@ -84,15 +84,15 @@ namespace net INFO("Inet4","Applying DHCP client"); dhcp_ = std::make_shared(*this); // 2 second timeout for DHCP-server negotation - dhcp_->negotiate(2.0); + dhcp_->negotiate(30.0); } - + template void Inet4::on_config(delegate handler) { dhcp_->on_config(handler); } - + template void Inet4::process_sendq(size_t packets) { From 4560f40a465290dbbc2d3463d88107545ac345c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Mon, 25 Apr 2016 13:13:12 +0200 Subject: [PATCH 211/311] tcp: refactored send stream --- api/net/tcp.hpp | 26 +++-- src/net/tcp.cpp | 49 ++------- src/net/tcp_connection.cpp | 169 ++++++++++++++---------------- src/net/tcp_connection_states.cpp | 16 +-- 4 files changed, 107 insertions(+), 153 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index 051e1d68ad..4bce476afb 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -1316,26 +1316,23 @@ namespace net { Active try to send a buffer by asking the TCP. */ inline size_t send(WriteBuffer& buffer) { - return host_.send(shared_from_this(), buffer, buffer.remaining); + return host_.send(shared_from_this(), (char*)buffer.pos(), buffer.remaining); } /* Segmentize buffer into packets until either everything has been written, or all packets are used up. */ - size_t send(const char* buffer, size_t remaining, size_t& packets, bool PUSH); + size_t send(const char* buffer, size_t remaining, size_t& packets); inline size_t send(WriteBuffer& buffer, size_t& packets, size_t n) { - return send((char*)buffer.pos(), n, packets, buffer.push); + return send((char*)buffer.pos(), n, packets); } - size_t send(const char* buffer, size_t n, Packet_ptr, bool PUSH); - /* Process the write queue with the given amount of packets. - Returns true if the Connection finishes - there is no more doable jobs. */ - bool offer(size_t& packets); + void offer(size_t& packets); /* Returns if the connection has a doable write job. @@ -1444,7 +1441,9 @@ namespace net { { return rtx_q.empty(); } bool can_send(); - size_t send_much(); + void send_much(); + + size_t fill_packet(Packet_ptr, const char*, size_t); //void send_ack(TCP::Packet_ptr = nullptr); /// Congestion Control [RFC 5681] /// @@ -1758,7 +1757,7 @@ namespace net { downstream _network_layer_out; - std::queue write_queue; + std::deque writeq; /* Settings @@ -1800,19 +1799,18 @@ namespace net { /* Process the write queue with the given amount of free packets. */ - void process_write_queue(size_t packets); + void process_writeq(size_t packets); /* - Ask to send a Connection's WriteBuffer. - If there is no free packets, the job will be queued. + */ - size_t send(Connection_ptr, Connection::WriteBuffer&, size_t n); + size_t send(Connection_ptr, const char* buffer, size_t n); /* Force the TCP to process the it's queue with the current amount of available packets. */ inline void kick() { - process_write_queue(inet_.transmit_queue_available()); + process_writeq(inet_.transmit_queue_available()); } inline IP4& network() const { diff --git a/src/net/tcp.cpp b/src/net/tcp.cpp index 8888e0e800..ee3d825ea2 100644 --- a/src/net/tcp.cpp +++ b/src/net/tcp.cpp @@ -27,10 +27,10 @@ TCP::TCP(IPStack& inet) : inet_(inet), listeners_(), connections_(), - write_queue(), + writeq(), MAX_SEG_LIFETIME(30s) { - inet.on_transmit_queue_available(transmit_avail_delg::from(this)); + inet.on_transmit_queue_available(transmit_avail_delg::from(this)); } /* @@ -185,54 +185,22 @@ void TCP::bottom(net::Packet_ptr packet_ptr) { } } -void TCP::process_write_queue(size_t packets) { +void TCP::process_writeq(size_t packets) { // foreach connection who wants to write - while(packets and !write_queue.empty()) { - auto conn = write_queue.front(); - write_queue.pop(); + while(packets and !writeq.empty()) { + auto conn = writeq.front(); + writeq.pop_back(); conn->offer(packets); conn->set_queued(false); - /* - // try to offer if there is any doable job, and if still more to do, requeue. - if(conn->has_doable_job() and !conn->offer(packets)) { - debug2("TCP::process_write_queue> %s still has more to do. Re-queued.\n"); - write_queue.push(conn); - } - else { - // mark the connection as not queued. - conn->set_queued(false); - debug2(" %s Removed from queue. Size is %u\n", - conn->to_string().c_str(), write_queue.size()); - } - */ - } -} - -size_t TCP::send(Connection_ptr conn, Connection::WriteBuffer& buffer, size_t n) { - size_t written{0}; - - if(write_queue.empty() and inet_.transmit_queue_available()) { - auto packets = inet_.transmit_queue_available(); - written = conn->send(buffer, packets, n); } - - if(written < buffer.remaining and !conn->is_queued()) { - write_queue.push(conn); - conn->set_queued(true); - debug(" %s wrote %u bytes (%u remaining) and is Re-queued.\n", - conn->to_string().c_str(), written, buffer.remaining-written); - } - - return written; } -/* -size_t TCP::send(Connection_ptr conn, Connection::WriteBuffer& buffer, size_t n) { +size_t TCP::send(Connection_ptr conn, const char* buffer, size_t n) { size_t written{0}; auto packets = inet_.transmit_queue_available(); if(packets > 0) { - conn->offer(packets); + written += conn->send(buffer, n, packets); } // if connection still can send (means there wasn't enough packets) if(conn->can_send()) { @@ -242,7 +210,6 @@ size_t TCP::send(Connection_ptr conn, Connection::WriteBuffer& buffer, size_t n) return written; } -*/ /* Show all connections for TCP as a string. diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index dc4b424479..ce7a76714c 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -116,19 +116,29 @@ void Connection::write(WriteBuffer buffer, WriteCallback callback) { } } -bool Connection::offer(size_t& packets) { - assert(packets); +void Connection::offer(size_t& packets) { + Expects(packets); + debug(" %s got offered [%u] packets. Usable window is %i.\n", to_string().c_str(), packets, usable_window()); - while(has_doable_job() and packets and !fast_recovery) { + // write until we either cant send more (window closes or no more in queue), + // or we're out of packets. + while(can_send() and packets) + { + auto packet = create_outgoing_packet(); + packets--; + + // get the first buffer in queue auto& buf = writeq.front().first; - // segmentize the buffer into packets - auto written = send(buf, packets, buf.remaining); + // fill the packet with data + auto written = fill_packet(packet, (char*)buf.pos(), std::min(buf.remaining, (size_t)SMSS())); // advance the buffer buf.advance(written); + debug2(" Wrote %u bytes (%u remaining) with [%u] packets left and a usable window of %i.\n", written, buf.remaining, packets, usable_window()); + // if finished if(!buf.remaining) { // callback and remove object @@ -137,91 +147,49 @@ bool Connection::offer(size_t& packets) { debug(" Request finished.\n"); } } - assert(packets >= 0); + debug(" Finished working offer with [%u] packets left and a queue of (%u) with a usable window of %i\n", packets, writeq.size(), usable_window()); - return !has_doable_job() or fast_recovery; } -// TODO: This is starting to get complex and ineffective, refactor.. -size_t Connection::send(const char* buffer, size_t remaining, size_t& packet_count, bool PUSH) { - assert(packet_count); - assert(remaining); - size_t bytes_written{0}; +size_t Connection::send(const char* buffer, size_t remaining, size_t& packets_avail) { + + size_t bytes_written = 0; - while(remaining and packet_count and usable_window() >= SMSS()) { - // retreive a new packet + std::vector packets; + + while(remaining and usable_window() >= SMSS() and packets_avail) + { auto packet = create_outgoing_packet(); - // reduce the amount of packets available by one - packet_count--; - // add the seq, ack and flag - packet->set_seq(cb.SND.NXT).set_ack(cb.RCV.NXT).set_flag(ACK); - // calculate how much the packet can be filled with - auto packet_limit = std::min((uint32_t)MSDS() - packet->header_size(), (uint32_t)usable_window()); - // fill the packet with data from the request - size_t written = packet->fill(buffer+bytes_written, std::min(packet_limit, remaining)); - // update local variables + packets_avail--; + + auto written = fill_packet(packet, buffer, std::min(remaining, (size_t)SMSS())); + bytes_written += written; remaining -= written; - // If last packet, add PUSH. - // TODO: Redefine "push" - //if((!remaining or !packet_count or usable_window() < SMSS()) and PUSH) - if(!remaining and PUSH) - packet->set_flag(PSH); - - // Advance outgoing sequence number (SND.NXT) with the length of the data. - cb.SND.NXT += packet->data_length(); - // TODO: Replace with chaining transmit(packet); - - debug2(" Packet Limit: %u - Written: %u" - " - Remaining: %u - Packet count: %u, Window: %u\n", - packet_limit, written, remaining, packet_count, usable_window()); - //if(reno_is_fast_recovering()) break; + //packets.push_back(packet); } - //printf(" Sent %u bytes of data\n", bytes_written); - return bytes_written; -} - -size_t Connection::send(const char* buffer, size_t n, Packet_ptr packet, bool PUSH) { - auto written = packet->fill(buffer, n); - packet->set_seq(cb.SND.NXT).set_ack(cb.RCV.NXT).set_flag(ACK); - if(PUSH) - packet->set_flag(PSH); - cb.SND.NXT += packet->data_length(); - transmit(packet); - return written; -} - -/*size_t Connection::fill(Packet_ptr packet, const char* buffer, size_t length, bool PUSH) { - Expects(!packet->has_data()); - Expects(length > 0); - - // fill packet with data from buffer - auto written = packet->fill(buffer, n); - // setup numbers - packet->set_seq(cb.SND.NXT).set_ack(cb.RCV.NXT).set_flag(ACK); - if(PUSH) - packet->set_flag(PSH); - - // advance sequence number - cb.SND.NXT += packet->data_length(); - - Ensures(written > 0); - Ensures(written == packet->data_length()); - - return written; -}*/ - -/*void Connection::pre_process(Packet_ptr packet) { - -} + /*Ensures(!packets.empty()); + // get first packet + auto i = packets.begin(); + auto head = i++; + // chain packets + while(i != packets.end()) { + (*head)->chain(*i); + head = i++; + } + // set push + (*head)->set_flag(PSH); -void Connection::post_process(Packet_ptr packet) { + // transmit first packet + transmit(packets.front());*/ + return bytes_written; } +/* void Connection::set_window(Packet_ptr packet) { packet->set_win(cb.RCV.WND); } @@ -241,7 +209,7 @@ void Connection::make_flight_ready(Packet_ptr packet) { void Connection::writeq_push() { while(!writeq.empty()) { auto& buf = writeq.front().first; - auto written = send(buf); + auto written = host_.send(shared_from_this(), (char*)buf.pos(), buf.remaining); buf.advance(written); if(buf.remaining) return; @@ -250,13 +218,34 @@ void Connection::writeq_push() { } } +size_t Connection::fill_packet(Packet_ptr packet, const char* buffer, size_t n) { + Expects(!packet->has_data()); + + auto written = packet->fill(buffer, n); + + packet->set_seq(cb.SND.NXT).set_ack(cb.RCV.NXT).set_flag(ACK); + cb.SND.NXT += packet->data_length(); + + Ensures(written <= n); + + return written; +} + void Connection::limited_tx() { + + auto packet = create_outgoing_packet(); + + printf(" UW: %u CW: %u, FS: %u\n", usable_window(), cb.cwnd, flight_size()); + auto& buf = writeq.front().first; - printf(" UW: %u CW: %u, FS: %u\n", usable_window(), cb.cwnd, flight_size()); - auto written = send((char*)buf.pos(), std::min(buf.remaining, (uint32_t)RMSS()), create_outgoing_packet(), false); + auto written = fill_packet(packet, (char*)buf.pos(), std::min(buf.remaining, (uint32_t)SMSS())); + + transmit(packet); + buf.advance(written); if(buf.remaining) return; + writeq.front().second(buf.offset); writeq.pop(); } @@ -370,7 +359,7 @@ void Connection::transmit(TCP::Packet_ptr packet) { //printf(" Starting RTT measurement.\n"); rttm.start(); } - if(packet->seq() + packet->data_length() < cb.SND.NXT) + if(packet->seq() + packet->data_length() != cb.SND.NXT) printf(" Transmitting: %u \n", packet->seq() - cb.ISS); host_.transmit(packet); @@ -381,28 +370,24 @@ void Connection::transmit(TCP::Packet_ptr packet) { } bool Connection::can_send() { - return (usable_window() >= RMSS()) and !writeq.empty(); + return (usable_window() >= SMSS()) and !writeq.empty(); } -size_t Connection::send_much() { - size_t bytes_written = 0; - auto uw = usable_window(); - - while(can_send()) { +void Connection::send_much() { + writeq_push(); + /*while(can_send()) { auto& buf = writeq.front().first; - auto written = send((char*)buf.pos(), std::min(buf.remaining, (uint32_t)RMSS()), create_outgoing_packet(), false); + auto written = send((char*)buf.pos(), std::min(buf.remaining, (uint32_t)RMSS()), create_outgoing_packet()); bytes_written += written; buf.advance(written); if(!buf.remaining) { writeq.front().second(buf.offset); writeq.pop(); } - } + }*/ //printf(" Prev UW: %u UW: %u CW: %u, FS: %u BW: %u\n", // uw, usable_window(), cb.cwnd, flight_size(), bytes_written); - - return bytes_written; } /*size_t Connection::send_one() { @@ -499,7 +484,7 @@ bool Connection::handle_ack(TCP::Packet_ptr in) { //printf(" Recovery - Partial ACK\n"); retransmit(); - dup_acks_ = 0; + //dup_acks_ = 0; if(!reno_fpack_seen) { rtx_reset(); @@ -507,7 +492,7 @@ bool Connection::handle_ack(TCP::Packet_ptr in) { } // send one segment if possible - if(can_send_one()) + if(can_send()) limited_tx(); if(in->has_data() or in->isset(FIN)) @@ -683,7 +668,7 @@ void Connection::rtx_timeout() { if(!rtx_q.front()->isset(SYN)) { // "back off" timer - rttm.RTO *= 2; + rttm.RTO *= 2.0; } // we never queue SYN packets since they don't carry data.. else { diff --git a/src/net/tcp_connection_states.cpp b/src/net/tcp_connection_states.cpp index 44f52f1625..480d3e72f6 100644 --- a/src/net/tcp_connection_states.cpp +++ b/src/net/tcp_connection_states.cpp @@ -317,18 +317,22 @@ void Connection::State::process_segment(Connection& tcp, TCP::Packet_ptr in) { auto length = in->data_length(); // Receive could result in a user callback. This is used to avoid sending empty ACK reply. debug(" Received packet with DATA-LENGTH: %i. Add to receive buffer. \n", length); - + tcb.RCV.NXT += length; + auto snd_nxt = tcb.SND.NXT; if(tcp.read_request.buffer.capacity()) { auto received = tcp.receive((uint8_t*)in->data(), in->data_length(), in->isset(PSH)); - assert(received == length); + Ensures(received == length); } - tcb.RCV.NXT += length; + // [RFC 5681] //tcb.SND.cwnd += std::min(length, tcp.SMSS()); debug2(" Advanced RCV.NXT: %u. SND.NXT = %u \n", tcb.RCV.NXT, snd_nxt); - auto packet = tcp.outgoing_packet(); - packet->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); - tcp.transmit(packet); + + if(tcb.SND.NXT == snd_nxt) { + auto packet = tcp.outgoing_packet(); + packet->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); + tcp.transmit(packet); + } if(tcp.can_send()) tcp.send_much(); /*if(tcp.has_doable_job() and !tcp.is_queued()) { From ad53d50227c1b2dd8052f911861ec3122cb70ac8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Mon, 25 Apr 2016 14:49:12 +0200 Subject: [PATCH 212/311] tcp: Debugging reordering --- .editorconfig | 2 ++ api/net/tcp.hpp | 6 ------ src/net/ip4/ip4.cpp | 29 ++++++++++++++++------------- src/net/tcp_connection.cpp | 2 ++ test/tcp/test.py | 5 +++-- 5 files changed, 23 insertions(+), 21 deletions(-) diff --git a/.editorconfig b/.editorconfig index 730d51b8be..ab2a20ec8e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,6 +7,8 @@ end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true +draw_white_space = all +trim_trailing_white_space_on_save = true [Makefile] indent_style = tab diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index 4bce476afb..9c056cc6bf 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -516,12 +516,6 @@ namespace net { return length > 0; } - inline size_t add(uint8_t* data, size_t n) { - auto written = std::min(n, remaining); - memcpy(pos(), data, written); - return written; - } - inline void clear() { memset(begin(), 0, offset); remaining = capacity(); diff --git a/src/net/ip4/ip4.cpp b/src/net/ip4/ip4.cpp index 3b58782ec7..a69a4dd33f 100644 --- a/src/net/ip4/ip4.cpp +++ b/src/net/ip4/ip4.cpp @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -21,6 +21,7 @@ #include #include #include +#include namespace net { @@ -37,13 +38,13 @@ namespace net { void IP4::bottom(Packet_ptr pckt) { debug2(" got the data.\n"); - + auto data = pckt->buffer(); ip_header* hdr = &reinterpret_cast(data)->ip_hdr; - + debug2("\t Source IP: %s Dest.IP: %s\n", hdr->saddr.str().c_str(), hdr->daddr.str().c_str()); - + switch(hdr->protocol){ case IP4_ICMP: debug2("\t Type: ICMP\n"); @@ -68,36 +69,38 @@ namespace net { } void IP4::transmit(Packet_ptr pckt) { - assert(pckt->size() > sizeof(IP4::full_header)); - + assert(pckt->size() > sizeof(IP4::full_header)); + full_header* full_hdr = reinterpret_cast(pckt->buffer()); ip_header* hdr = &full_hdr->ip_hdr; - + auto ip4_pckt = std::static_pointer_cast(pckt); ip4_pckt->make_flight_ready(); - + // Create local and target subnets addr target, local; target.whole = hdr->daddr.whole & stack_.netmask().whole; local.whole = stack_.ip_addr().whole & stack_.netmask().whole; - + // Compare subnets to know where to send packet pckt->next_hop(target == local ? hdr->daddr : stack_.router()); - + debug(" Next hop for %s, (netmask %s, local IP: %s, gateway: %s) == %s\n", hdr->daddr.str().c_str(), stack_.netmask().str().c_str(), stack_.ip_addr().str().c_str(), stack_.router().str().c_str(), target == local ? "DIRECT" : "GATEWAY"); - + debug(" my ip: %s, Next hop: %s, Packet size: %i IP4-size: %i\n", stack_.ip_addr().str().c_str(), pckt->next_hop().str().c_str(), pckt->size(), ip4_pckt->ip4_segment_size() ); - + //auto tcp = std::static_pointer_cast (pckt); + //printf(" TCP SEQ: %u %u %u\n", tcp->seq(), tcp->ack(), tcp->data_length()); + linklayer_out_(pckt); } diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index ce7a76714c..66e83fdf0b 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -146,6 +146,8 @@ void Connection::offer(size_t& packets) { writeq.pop(); debug(" Request finished.\n"); } + + transmit(packet); } debug(" Finished working offer with [%u] packets left and a queue of (%u) with a usable window of %i\n", diff --git a/test/tcp/test.py b/test/tcp/test.py index 0c036b7771..6afa66a636 100644 --- a/test/tcp/test.py +++ b/test/tcp/test.py @@ -16,6 +16,7 @@ def connect(port): try: while True: data = sock.recv(1024) + print >>sys.stderr, '%s' % data if data: sock.sendall(data); else: @@ -51,11 +52,11 @@ def listen(port): else: print >>sys.stderr, 'no more data from', client_address break - + finally: connection.close() break sock.close() return -listen(8085) \ No newline at end of file +listen(8085) From 57e6f33a038a20255a58010c2986ea18e1a6309d Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Mon, 25 Apr 2016 15:07:32 +0200 Subject: [PATCH 213/311] Updated transmission test to verify packet order --- test/transmit/service.cpp | 58 +++++++++++++++++++++------------------ test/transmit/test.py | 53 +++++++++++++++++++++++++++++++++++ test/transmit/vm.json | 8 ++++++ 3 files changed, 93 insertions(+), 26 deletions(-) create mode 100755 test/transmit/test.py create mode 100644 test/transmit/vm.json diff --git a/test/transmit/service.cpp b/test/transmit/service.cpp index 746c7a9c6a..1b84c400bb 100644 --- a/test/transmit/service.cpp +++ b/test/transmit/service.cpp @@ -47,44 +47,50 @@ void Service::start() UDP::port_t port = 4242; auto& conn = inet->udp().bind(port); - conn.on_read([&] (UDP::addr_t addr, UDP::port_t port, - const char* data, int len) { - string received = std::string(data,len-1); - INFO("Test 2","Starting UDP-test (got UDP data from %s: %i: '%s')", - addr.str().c_str(), port, received.c_str()); + conn.on_read([&] (UDP::addr_t addr, UDP::port_t port, const char* data, int len) { + string received = std::string(data,len); - const int packets { 600 }; - - string first_reply {string("Received '") + received + - "'. Expect " + to_string(packets) + " packets in 1s\n" }; + if (received == "SUCCESS") { + INFO("Test 2", "Client says SUCCESS"); + return; + } - // Send the first packet, and then wait for ARP - conn.sendto(addr, port, first_reply.c_str(), first_reply.size()); + INFO("Test 2","Starting UDP-test. Got UDP data from %s: %i: %s", + addr.str().c_str(), port, received.c_str()); - timer.onTimeout(1s, [&conn, addr, port, data, len]() { - INFO("Test 2", "Trying to transmit %i UDP packets at maximum throttle", packets); - auto bufcount = inet->buffers_available(); + const int packets { 600 }; - for (int i = 0; i < packets; i++) - conn.sendto(addr, port, data, len); + string first_reply {string("Received '") + received + + "'. Expect " + to_string(packets) + " packets in 1s\n" }; - CHECK(1,"UDP-transmission didn't panic"); - auto bufcount2 = inet->buffers_available(); + // Send the first packet, and then wait for ARP + conn.sendto(addr, port, first_reply.c_str(), first_reply.size()); - CHECKSERT(bufcount2 < bufcount, - "%i buffers available after transmission (Had %i). ", - bufcount2, bufcount); + timer.onTimeout(1s, [&conn, addr, port, data, len]() { + INFO("Test 2", "Trying to transmit %i UDP packets at maximum throttle", packets); + auto bufcount = inet->buffers_available(); - INFO("Transmision tests","SUCCESS"); - }); + for (int i = 0; i < packets; i++) { + string send = "Packet " + std::to_string(i) + "\n"; + //printf(" %s", send.c_str()); + conn.sendto(addr, port, send.c_str() , send.size()); + } - }); + CHECK(1,"UDP-transmission didn't panic"); + auto bufcount2 = inet->buffers_available(); - eth0.on_transmit_queue_available([](size_t s){ - CHECKSERT(s,"There is now room for %i packets in transmit queue", s); + INFO("UDP Transmision tests","OK"); + }); }); + /* + WARNING: Subscribing to this event will overwrite the Inet delegate. So Don't + + eth0.on_transmit_queue_available([](size_t s){ + CHECKSERT(s,"There is now room for %i packets in transmit queue", s); + }); */ + timer.onTimeout(200ms,[=](){ const int packets { 600 }; INFO("Test 1", "Trying to transmit %i ethernet packets at maximum throttle", packets); diff --git a/test/transmit/test.py b/test/transmit/test.py new file mode 100755 index 0000000000..c93a207400 --- /dev/null +++ b/test/transmit/test.py @@ -0,0 +1,53 @@ +#! /usr/bin/python +import sys +sys.path.insert(0,"..") + +import vmrunner +import socket + +HOST, PORT = "10.0.0.42", 4242 +# SOCK_DGRAM is the socket type to use for UDP sockets +sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + +# Get an auto-created VM from the vmrunner +vm = vmrunner.vms[0] + + +def UDP_test(): + print " Performing UDP test 1" + + data = "Douche" + sock.sendto(data+"\n", (HOST, PORT)) + received = sock.recv(100) + + print " Sent: {}".format(data) + print " Received: {}".format(received) + + prev = -1 + OK = False + + while not vm.poll(): + received = sock.recv(1500) + nr = int(received.split(" ")[1]); + + if nr != prev + 1: + break + + print "Got packet ", nr + + prev += 1 + if nr == 599: + OK = True + break + + if OK: + print " SUCCESS - correct packet order" + sock.sendto("SUCCESS", (HOST, PORT)) + else: + print " FAILED - incorrect packet order" + +# Add custom event-handler +vm.on_output("Done. Send some UDP-data", UDP_test) + +# Boot the VM, taking a timeout as parameter +vm.boot(20) diff --git a/test/transmit/vm.json b/test/transmit/vm.json new file mode 100644 index 0000000000..24a071ca9f --- /dev/null +++ b/test/transmit/vm.json @@ -0,0 +1,8 @@ +{ + "image" : "test_transmit.img", + "net" : [{"type" : "virtio", + "mac" : "c0:01:0a:00:00:2a", + "log" : "net_result.pcap"}], + "cpu" : "host", + "mem" : 256 +} From 8700c632ecd4e0f34a6143bc2781ae520044fb40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Tue, 26 Apr 2016 12:54:41 +0200 Subject: [PATCH 214/311] tcp: debug fiesta --- src/net/ip4/ip4.cpp | 5 +-- src/net/tcp.cpp | 4 +++ src/net/tcp_connection.cpp | 52 +++++++++++++++++++++---------- src/net/tcp_connection_states.cpp | 4 +-- 4 files changed, 45 insertions(+), 20 deletions(-) diff --git a/src/net/ip4/ip4.cpp b/src/net/ip4/ip4.cpp index a69a4dd33f..e55adc943a 100644 --- a/src/net/ip4/ip4.cpp +++ b/src/net/ip4/ip4.cpp @@ -98,8 +98,9 @@ namespace net { pckt->size(), ip4_pckt->ip4_segment_size() ); - //auto tcp = std::static_pointer_cast (pckt); - //printf(" TCP SEQ: %u %u %u\n", tcp->seq(), tcp->ack(), tcp->data_length()); + auto tcp = std::static_pointer_cast (pckt); + printf(" TCP seq=%u data=%u size=%u seg=%u\n", + tcp->seq(), tcp->data_length(), pckt->size(), ip4_pckt->ip4_segment_size()); linklayer_out_(pckt); } diff --git a/src/net/tcp.cpp b/src/net/tcp.cpp index ee3d825ea2..622cd45a5e 100644 --- a/src/net/tcp.cpp +++ b/src/net/tcp.cpp @@ -186,6 +186,7 @@ void TCP::bottom(net::Packet_ptr packet_ptr) { } void TCP::process_writeq(size_t packets) { + printf(" size=%u p=%u\n", writeq.size(), packets); // foreach connection who wants to write while(packets and !writeq.empty()) { auto conn = writeq.front(); @@ -199,11 +200,14 @@ size_t TCP::send(Connection_ptr conn, const char* buffer, size_t n) { size_t written{0}; auto packets = inet_.transmit_queue_available(); + printf(" Send request for %u bytes\n", n); + if(packets > 0) { written += conn->send(buffer, n, packets); } // if connection still can send (means there wasn't enough packets) if(conn->can_send()) { + printf(" Conn queued.\n"); writeq.push_back(conn); conn->set_queued(true); } diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index 66e83fdf0b..3946c277d3 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -119,7 +119,7 @@ void Connection::write(WriteBuffer buffer, WriteCallback callback) { void Connection::offer(size_t& packets) { Expects(packets); - debug(" %s got offered [%u] packets. Usable window is %i.\n", + printf(" %s got offered [%u] packets. Usable window is %u.\n", to_string().c_str(), packets, usable_window()); // write until we either cant send more (window closes or no more in queue), @@ -136,9 +136,11 @@ void Connection::offer(size_t& packets) { // advance the buffer buf.advance(written); - debug2(" Wrote %u bytes (%u remaining) with [%u] packets left and a usable window of %i.\n", + printf(" Wrote %u bytes (%u remaining) with [%u] packets left and a usable window of %u.\n", written, buf.remaining, packets, usable_window()); + transmit(packet); + // if finished if(!buf.remaining) { // callback and remove object @@ -146,8 +148,6 @@ void Connection::offer(size_t& packets) { writeq.pop(); debug(" Request finished.\n"); } - - transmit(packet); } debug(" Finished working offer with [%u] packets left and a queue of (%u) with a usable window of %i\n", @@ -157,6 +157,8 @@ void Connection::offer(size_t& packets) { size_t Connection::send(const char* buffer, size_t remaining, size_t& packets_avail) { size_t bytes_written = 0; + printf(" Trying to send %u bytes. Starting with uw=%u packets=%u\n", + remaining, usable_window(), packets_avail); std::vector packets; @@ -188,6 +190,9 @@ size_t Connection::send(const char* buffer, size_t remaining, size_t& packets_av // transmit first packet transmit(packets.front());*/ + printf(" Sent %u bytes. Finished with uw=%u packets=%u\n", + bytes_written, usable_window(), packets_avail); + return bytes_written; } @@ -361,8 +366,9 @@ void Connection::transmit(TCP::Packet_ptr packet) { //printf(" Starting RTT measurement.\n"); rttm.start(); } - if(packet->seq() + packet->data_length() != cb.SND.NXT) - printf(" Transmitting: %u \n", packet->seq() - cb.ISS); + //if(packet->seq() + packet->data_length() != cb.SND.NXT) + printf(" rseq=%u rack=%u\n", + packet->seq() - cb.ISS, packet->ack() - cb.IRS); host_.transmit(packet); if(packet->has_data()) @@ -421,13 +427,14 @@ bool Connection::handle_ack(TCP::Packet_ptr in) { // new ack else if(in->ack() >= cb.SND.UNA) { - + printf(" New ACK: %u %s\n", + in->ack() - cb.ISS, fast_recovery ? "[RECOVERY]" : ""); if( cb.SND.WL1 < in->seq() or ( cb.SND.WL1 == in->seq() and cb.SND.WL2 <= in->ack() ) ) { cb.SND.WND = in->win(); cb.SND.WL1 = in->seq(); cb.SND.WL2 = in->ack(); - debug2(" Usable window slided (%i)\n", tcp.usable_window()); + //printf(" Window update (%u)\n", cb.SND.WND); } // [RFC 6582] p. 8 @@ -452,19 +459,23 @@ bool Connection::handle_ack(TCP::Packet_ptr in) { // no fast recovery if(!fast_recovery) { - + //printf(" Not in Recovery\n"); dup_acks_ = 0; cb.recover = cb.SND.NXT; // slow start if(cb.slow_start()) { reno_increase_cwnd(bytes_acked); + printf(" Slow start. cwnd=%u uw=%u\n", + cb.cwnd, usable_window()); } // congestion avoidance else { // increase cwnd once per RTT cb.cwnd += std::max(SMSS()*SMSS()/cb.cwnd, (uint32_t)1); + printf(" Congestion avoidance. cwnd=%u uw=%u\n", + cb.cwnd, usable_window()); } // < congestion avoidance // try to write @@ -479,9 +490,10 @@ bool Connection::handle_ack(TCP::Packet_ptr in) { // we're in fast recovery else { - + //printf(" In Recovery\n"); // partial ack if(!reno_full_ack(in->ack())) { + printf(" Partial ACK\n"); reno_deflate_cwnd(bytes_acked); //printf(" Recovery - Partial ACK\n"); retransmit(); @@ -494,8 +506,12 @@ bool Connection::handle_ack(TCP::Packet_ptr in) { } // send one segment if possible - if(can_send()) + if(can_send()) { + printf(" Sending one packet during recovery.\n"); limited_tx(); + } else { + printf(" Can't send during recovery - usable window is closed.\n"); + } if(in->has_data() or in->isset(FIN)) return true; @@ -503,6 +519,7 @@ bool Connection::handle_ack(TCP::Packet_ptr in) { // full ack else { + printf(" Full ACK.\n"); dup_acks_ = 0; finish_fast_recovery(); } // < full ack @@ -524,13 +541,14 @@ bool Connection::handle_ack(TCP::Packet_ptr in) { What to do when received ACK is a duplicate. */ void Connection::on_dup_ack() { - //printf(" %u\n", dup_acks_); + printf(" ack=%u i=%u\n", cb.SND.UNA - cb.ISS, dup_acks_); // if less than 3 dup acks if(dup_acks_ < 3) { // try to send one segment - if(cb.SND.WND >= SMSS() and (flight_size() <= cb.cwnd + 2*SMSS()) and !writeq.empty()) + if(cb.SND.WND >= SMSS() and (flight_size() <= cb.cwnd + 2*SMSS()) and !writeq.empty()) { limited_tx(); + } } // 3 dup acks @@ -550,8 +568,8 @@ void Connection::on_dup_ack() { else { cb.cwnd += SMSS(); // send one segment if possible - if(can_send()) - limited_tx(); + //if(can_send()) + // limited_tx(); } } @@ -598,7 +616,9 @@ void Connection::retransmit() { if(rtx_q.empty()) return; auto packet = rtx_q.front(); - //printf(" Retransmitting: %u \n", packet->seq()); + printf(" rseq=%u \n", packet->seq() - cb.ISS); + Ensures(packet->tail() == nullptr); + Ensures(packet->last_in_chain() == nullptr); host_.transmit(packet); /* Every time a packet containing data is sent (including a diff --git a/src/net/tcp_connection_states.cpp b/src/net/tcp_connection_states.cpp index 480d3e72f6..935d04c2af 100644 --- a/src/net/tcp_connection_states.cpp +++ b/src/net/tcp_connection_states.cpp @@ -333,8 +333,8 @@ void Connection::State::process_segment(Connection& tcp, TCP::Packet_ptr in) { packet->set_seq(tcb.SND.NXT).set_ack(tcb.RCV.NXT).set_flag(ACK); tcp.transmit(packet); } - if(tcp.can_send()) - tcp.send_much(); + //if(tcp.can_send()) + // tcp.send_much(); /*if(tcp.has_doable_job() and !tcp.is_queued()) { printf(" Usable window: %i\n", tcp.usable_window()); tcp.writeq_push(); From b48224ab13dd43ca70734b7bede5b971f71ed734 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 26 Apr 2016 13:08:34 +0200 Subject: [PATCH 215/311] Added memory barriers w.r.t. Virtio 3.2.1 --- api/virtio/virtio.hpp | 2 ++ src/virtio/virtio_queue.cpp | 14 ++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/api/virtio/virtio.hpp b/api/virtio/virtio.hpp index b4177a59c5..4e33adbdd6 100644 --- a/api/virtio/virtio.hpp +++ b/api/virtio/virtio.hpp @@ -218,6 +218,8 @@ class Virtio Update the available index */ inline void update_avail_idx () { + // Std. §3.2.1 pt. 4 + asm volatile("mfence" ::: "memory"); _queue.avail->idx += _num_added; _num_added = 0; } diff --git a/src/virtio/virtio_queue.cpp b/src/virtio/virtio_queue.cpp index 8d4063fefd..962438ffc7 100644 --- a/src/virtio/virtio_queue.cpp +++ b/src/virtio/virtio_queue.cpp @@ -165,13 +165,13 @@ Virtio::Token Virtio::Queue::dequeue() { release(e.id); _last_used_idx++; // return token: - return {{(uint8_t*) _queue.desc[e.id].addr, + return {{(uint8_t*) _queue.desc[e.id].addr, (gsl::span::size_type) e.len }, Token::IN}; } std::vector Virtio::Queue::dequeue_chain() { - + std::vector result; - + // Return NULL if there are no more completed buffers in the queue if (_last_used_idx == _queue.used->idx){ debug(" Can't dequeue - no used buffers \n",_pci_index); @@ -181,7 +181,7 @@ std::vector Virtio::Queue::dequeue_chain() { // Get next completed buffer auto* e = &_queue.used->ring[_last_used_idx % _size]; - + auto* unchain = &_queue.desc[e->id]; do { @@ -190,12 +190,12 @@ std::vector Virtio::Queue::dequeue_chain() { unchain = &_queue.desc[ unchain->next ]; } while (unchain->flags & VIRTQ_DESC_F_NEXT); - + // Release buffer debug(" Releasing token @%p, nr. %i Len: %i\n",_pci_index, e, e->id, e->len); release(e->id); _last_used_idx++; - + return result; } @@ -215,6 +215,8 @@ void Virtio::Queue::kick(){ update_avail_idx(); + // Std. §3.2.1 pt. 4 + asm volatile("mfence" ::: "memory"); if (!(_queue.used->flags & VIRTQ_USED_F_NO_NOTIFY)){ debug(" Kicking virtio. Iobase 0x%x \n", _pci_index, _iobase); From 6b2734c5aebb5866f997b4cb46ba998cbc2b3ee1 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 26 Apr 2016 13:47:12 +0200 Subject: [PATCH 216/311] Nic/virtionet event 'on_exit_to_physical' for pre-flight inspection --- api/hw/nic.hpp | 3 +++ api/virtio/virtionet.hpp | 6 ++++++ src/virtio/virtionet.cpp | 1 + 3 files changed, 10 insertions(+) diff --git a/api/hw/nic.hpp b/api/hw/nic.hpp index ec360ea64d..098e2d2929 100644 --- a/api/hw/nic.hpp +++ b/api/hw/nic.hpp @@ -76,6 +76,9 @@ namespace hw { inline size_t buffers_available() { return bufstore().buffers_available(); } + inline void on_exit_to_physical(delegate dlg) + { driver_.on_exit_to_physical(dlg); } + private: driver_t driver_; diff --git a/api/virtio/virtionet.hpp b/api/virtio/virtionet.hpp index 794ff9f6e4..65c6f63f3c 100644 --- a/api/virtio/virtionet.hpp +++ b/api/virtio/virtionet.hpp @@ -152,6 +152,10 @@ class VirtioNet : Virtio { return tx_q.num_free() / 2; }; + + inline void on_exit_to_physical(delegate dlg) + { on_exit_to_physical_ = dlg; }; + private: struct virtio_net_hdr @@ -237,6 +241,8 @@ class VirtioNet : Virtio { net::Packet_ptr transmit_queue_ {0}; + delegate on_exit_to_physical_ {}; + }; #endif diff --git a/src/virtio/virtionet.cpp b/src/virtio/virtionet.cpp index 9dd9899c35..3e35e5d821 100644 --- a/src/virtio/virtionet.cpp +++ b/src/virtio/virtionet.cpp @@ -341,6 +341,7 @@ void VirtioNet::transmit(net::Packet_ptr pckt){ // Transmit all we can directly while (tx_q.num_free() and tail) { debug("%i tokens left in TX queue \n", tx_q.num_free()); + on_exit_to_physical_(tail); enqueue(tail); tail = tail->detach_tail(); transmitted++; From 47883b079b08df626f6a4cc9796f5d76e27cb7d7 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 26 Apr 2016 16:05:26 +0200 Subject: [PATCH 217/311] Changed virtio queue to use proper token chaining --- api/virtio/virtio.hpp | 21 ++++++++++++++++----- src/virtio/virtio_queue.cpp | 26 ++++++++++++++++++-------- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/api/virtio/virtio.hpp b/api/virtio/virtio.hpp index 4e33adbdd6..9b7a30a143 100644 --- a/api/virtio/virtio.hpp +++ b/api/virtio/virtio.hpp @@ -33,9 +33,10 @@ #define VIRTIO_VIRTIO_HPP #include "../hw/pci_device.hpp" -#include +#include #include #include +#include #define PAGE_SIZE 4096 @@ -202,11 +203,14 @@ class Virtio virtq _queue; uint16_t _iobase = 0; // Device PCI location - uint16_t _free_head = 0; // First available descriptor + uint16_t _free_head = 0; // First available descriptor (_queue.desc[_free_head]) uint16_t _num_added = 0; // Entries to be added to _queue.avail->idx - uint16_t _last_used_idx = 0; // Last entry inserted by device + uint16_t _desc_in_flight = 0; // Entries in _queue_desc currently in use + uint16_t _last_used_idx = 0; // Last known value of _queue.used->idx uint16_t _pci_index = 0; // Queue nr. + delegate on_exit_to_physical_ {}; + /** Handler for data coming in on virtq.used. */ data_handler_t _data_handler; @@ -264,7 +268,10 @@ class Virtio /** Get number of free tokens in Queue */ uint16_t num_free() const noexcept - { return size() - _free_head; } + { + //Expects(size() - _free_head == size() - _desc_in_flight); + return size() - _desc_in_flight; + } // access the current index virtq_desc& current() @@ -287,6 +294,11 @@ class Virtio return _size; } + /** Inject a packet filter delegate the last possible point downstream */ + inline void on_exit_to_physical(delegate dlg) + { on_exit_to_physical_ = dlg; }; + + }; @@ -325,7 +337,6 @@ class Virtio /** Tell Virtio device if we're OK or not. Virtio Std. § 3.1.1,step 8*/ void setup_complete(bool ok); - /** Indicate which Virtio version (PCI revision ID) is supported. Currently only Legacy is supported (partially the 1.0 standard) diff --git a/src/virtio/virtio_queue.cpp b/src/virtio/virtio_queue.cpp index 962438ffc7..06dca2b987 100644 --- a/src/virtio/virtio_queue.cpp +++ b/src/virtio/virtio_queue.cpp @@ -94,9 +94,6 @@ Virtio::Queue::Queue(uint16_t size, uint16_t q_index, uint16_t iobase) /** Ported more or less directly from SanOS. */ int Virtio::Queue::enqueue(gsl::span buffers){ debug ("Enqueuing %i tokens \n", buffers.size()); - Expects(_free_head >= 0); - Expects(_free_head < size()); - Expects(_num_added + 1 > _num_added); uint16_t last = _free_head; uint16_t first = _free_head; @@ -113,39 +110,52 @@ int Virtio::Queue::enqueue(gsl::span buffers){ _queue.desc[_free_head].len = buf.size(); last = _free_head; - _free_head ++; + _free_head = _queue.desc[_free_head].next; } + _desc_in_flight += buffers.size(); + Ensures(_desc_in_flight <= size()); + // No continue on last buffer _queue.desc[last].flags &= ~VIRTQ_DESC_F_NEXT; + // Place the head of this current chain in the avail ring - uint16_t avail_index = (_queue.avail->idx + _num_added++) % _size; + uint16_t avail_index = (_queue.avail->idx + _num_added) % _size; + + // we added a token + _num_added++; + _queue.avail->ring[avail_index] = first; debug(" avail_index: %i size: %i, _free_head %i \n", _pci_index, avail_index, size(), _free_head ); - Ensures(_free_head <= size()); + debug ("Free tokens: %i \n", num_free()); + return buffers.size(); } void Virtio::Queue::release(uint32_t head) { + // Mark queue element "head" as free (the whole token chain) uint32_t i = head; + _desc_in_flight --; + while (_queue.desc[i].flags & VIRTQ_DESC_F_NEXT) { i = _queue.desc[i].next; + _desc_in_flight --; } // Add buffers back to free list _queue.desc[i].next = _free_head; _free_head = head; - // What happens here? - debug(" desc[%i].next : %i \n",_pci_index, i ,_queue.desc[i].next); + debug("Descriptors in flight: %i \n", _desc_in_flight); + } Virtio::Token Virtio::Queue::dequeue() { From 48ff05212945c39c92603ddaf9a462d89414d502 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Tue, 26 Apr 2016 16:49:54 +0200 Subject: [PATCH 218/311] tcp: searching for needle.. --- api/net/tcp.hpp | 12 +++++++++--- src/net/tcp_connection.cpp | 25 +++++++++++++++++++------ test/tcp/service.cpp | 19 +++++++++++++++++++ 3 files changed, 47 insertions(+), 9 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index 9c056cc6bf..53ac9fe642 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -1428,8 +1428,7 @@ namespace net { void on_dup_ack(); - inline bool can_send_one() - { return send_window() >= SMSS() and !writeq.empty(); } + bool can_send_one(); inline bool need_send() { return rtx_q.empty(); } @@ -1446,6 +1445,8 @@ namespace net { // First partial ack seen bool reno_fpack_seen = false; + bool limited_tx_ = true; + size_t dup_acks_ = 0; Seq prev_highest_ack_ = 0; Seq highest_ack_ = 0; @@ -1489,7 +1490,12 @@ namespace net { { cb.cwnd -= (n >= SMSS()) ? n-SMSS() : n; } inline void reduce_ssthresh() { - cb.ssthresh = std::max( (flight_size() / 2), (2 * (uint32_t)SMSS()) ); + auto fs = flight_size(); + + if(limited_tx_) + fs -= 2*(uint32_t)SMSS(); + + cb.ssthresh = std::max( (fs / 2), (2 * (uint32_t)SMSS()) ); printf(" Slow start threshold reduced: %u\n", cb.ssthresh); } diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index 3946c277d3..9ea00de950 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -172,6 +172,9 @@ size_t Connection::send(const char* buffer, size_t remaining, size_t& packets_av bytes_written += written; remaining -= written; + if(!remaining or usable_window() < SMSS() or !packets_avail) + packet->set_flag(PSH); + transmit(packet); //packets.push_back(packet); } @@ -367,8 +370,9 @@ void Connection::transmit(TCP::Packet_ptr packet) { rttm.start(); } //if(packet->seq() + packet->data_length() != cb.SND.NXT) - printf(" rseq=%u rack=%u\n", - packet->seq() - cb.ISS, packet->ack() - cb.IRS); + //printf(" rseq=%u rack=%u\n", + // packet->seq() - cb.ISS, packet->ack() - cb.IRS); + printf(" TX %s\n", packet->to_string().c_str()); host_.transmit(packet); if(packet->has_data()) @@ -376,6 +380,9 @@ void Connection::transmit(TCP::Packet_ptr packet) { if(!rtx_timer.active) rtx_start(); } +bool Connection::can_send_one() { + return send_window() >= SMSS() and !writeq.empty(); +} bool Connection::can_send() { return (usable_window() >= SMSS()) and !writeq.empty(); @@ -545,9 +552,11 @@ void Connection::on_dup_ack() { // if less than 3 dup acks if(dup_acks_ < 3) { - // try to send one segment - if(cb.SND.WND >= SMSS() and (flight_size() <= cb.cwnd + 2*SMSS()) and !writeq.empty()) { - limited_tx(); + if(limited_tx_) { + // try to send one segment + if(cb.SND.WND >= SMSS() and (flight_size() <= cb.cwnd + 2*SMSS()) and !writeq.empty()) { + limited_tx(); + } } } @@ -616,7 +625,8 @@ void Connection::retransmit() { if(rtx_q.empty()) return; auto packet = rtx_q.front(); - printf(" rseq=%u \n", packet->seq() - cb.ISS); + //printf(" rseq=%u \n", packet->seq() - cb.ISS); + printf(" RT %s\n", packet->to_string().c_str()); Ensures(packet->tail() == nullptr); Ensures(packet->last_in_chain() == nullptr); host_.transmit(packet); @@ -687,6 +697,9 @@ void Connection::rtx_clear() { void Connection::rtx_timeout() { // retransmit SND.UNA retransmit(); + auto hax = ++rtx_q.begin(); + for(auto i = 0; i < 2 and hax != rtx_q.end(); i++) + host_.transmit(*hax++); if(!rtx_q.front()->isset(SYN)) { // "back off" timer diff --git a/test/tcp/service.cpp b/test/tcp/service.cpp index 0089527afb..9c11217863 100644 --- a/test/tcp/service.cpp +++ b/test/tcp/service.cpp @@ -112,6 +112,23 @@ void OUTGOING_TEST(TCP::Socket outgoing) { }); } +/*void outgoing_packet(net::Packet_ptr p) { + + auto* eth = reinterpret_cast(p->buffer()); + + if (eth->type == net::Ethernet::ETH_IP4) { + + auto ip4 = net::view_packet_as(p); + auto& hdr = reinterpret_cast(p->buffer())->ip_hdr; + + if (hdr.protocol == net::IP4::IP4_TCP) { + auto tcp = net::view_packet_as(p); + printf("%s\n", tcp->to_string().c_str()); + } + } + +}*/ + // Used to send big data struct Buffer { size_t written, read; @@ -139,8 +156,10 @@ void Service::start() huge += "-end"; hw::Nic& eth0 = hw::Dev::eth<0,VirtioNet>(); + //eth0.on_exit_to_physical(outgoing_packet); inet = std::make_unique>(eth0); + inet->network_config( {{ 10,0,0,42 }}, // IP {{ 255,255,255,0 }}, // Netmask {{ 10,0,0,1 }}, // Gateway From 02e2efd13d54e95738f164bb7a24b0df3b0c8032 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 26 Apr 2016 17:48:36 +0200 Subject: [PATCH 219/311] Updated to clang 3.8 (We have Ubuntu 16.04 now) --- etc/install_from_bundle.sh | 25 +++++++++++-------------- install.sh | 18 +++++++++--------- src/Makefile | 6 +++--- src/seed/Makefile | 4 ++-- 4 files changed, 25 insertions(+), 28 deletions(-) diff --git a/etc/install_from_bundle.sh b/etc/install_from_bundle.sh index 2d9bcb9eea..5d14f79160 100755 --- a/etc/install_from_bundle.sh +++ b/etc/install_from_bundle.sh @@ -2,22 +2,22 @@ # Install the IncludeOS libraries (i.e. IncludeOS_home) from binary bundle # ...as opposed to building them all from scratch, which takes a long time -# # -# OPTIONS: +# +# OPTIONS: # # Location of the IncludeOS repo: # $ export INCLUDEOS_SRC=your/github/cloned/IncludeOS # # Parent directory of where you want the IncludeOS libraries (i.e. IncludeOS_home) -# $ export INCLUDEOS_INSTALL_LOC=parent/folder/for/IncludeOS/libraries i.e. +# $ export INCLUDEOS_INSTALL_LOC=parent/folder/for/IncludeOS/libraries i.e. [ ! -v INCLUDEOS_SRC ] && export INCLUDEOS_SRC=$(readlink -f "$(dirname "$0")/..") [ ! -v INCLUDEOS_INSTALL_LOC ] && export INCLUDEOS_INSTALL_LOC=$HOME export INCLUDEOS_HOME=$INCLUDEOS_INSTALL_LOC/IncludeOS_install # Install dependencies -DEPENDENCIES="curl make clang-3.6 nasm bridge-utils qemu" +DEPENDENCIES="curl make clang-3.8 nasm bridge-utils qemu" echo ">>> Installing dependencies (requires sudo):" echo " Packages: $DEPENDENCIES" sudo apt-get update @@ -29,19 +29,19 @@ echo ">>> Updating git-tags " pushd $INCLUDEOS_SRC git pull --tags tag=`git describe --abbrev=0` -popd +popd filename_tag=`echo $tag | tr . -` filename="IncludeOS_install_"$filename_tag".tar.gz" -# If the tarball exists, use that -if [ -e $filename ] +# If the tarball exists, use that +if [ -e $filename ] then echo -e "\n\n>>> IncludeOS tarball exists - extracting to $INCLUDEOS_INSTALL_LOC" tar -C $INCLUDEOS_INSTALL_LOC -xzf $filename -else +else echo -e "\n\n>>> Downloading IncludeOS release tarball from GitHub" - # Download from GitHub API + # Download from GitHub API if [ "$1" = "-oauthToken" ] then oauthToken=$2 @@ -61,9 +61,9 @@ else else curl -H "Accept: application/octet-stream" -L -o $filename $ASSET_URL fi - + echo -e "\n\n>>> Fetched tarball - extracting to $INCLUDEOS_INSTALL_LOC" - tar -C $INCLUDEOS_INSTALL_LOC -xzf $filename + tar -C $INCLUDEOS_INSTALL_LOC -xzf $filename fi echo -e "\n\n>>> Installing submodules" @@ -90,6 +90,3 @@ sudo $INCLUDEOS_SRC/etc/create_bridge.sh $INCLUDEOS_SRC/etc/copy_scripts.sh echo -e "\n\n>>> Done! Test your installation with ./test.sh" - - - diff --git a/install.sh b/install.sh index 61b531a85c..67807af646 100755 --- a/install.sh +++ b/install.sh @@ -19,7 +19,7 @@ export INCLUDEOS_SRC=`pwd` export newlib_inc=$TEMP_INSTALL_DIR/i686-elf/include export llvm_src=llvm export llvm_build=build_llvm -export clang_version=3.6 +export clang_version=3.8 export gcc_version=5.1.0 export binutils_version=2.25 @@ -79,34 +79,34 @@ git submodule update popd if [ ! -z $do_includeos ]; then - # Build and install the vmbuilder + # Build and install the vmbuilder echo -e "\n >>> Installing vmbuilder" pushd $INCLUDEOS_SRC/vmbuild - make + make cp vmbuild $INSTALL_DIR/ popd - + echo -e "\n >>> Building IncludeOS" pushd $INCLUDEOS_SRC/src make $num_jobs - + echo -e "\n >>> Linking IncludeOS test-service" make test - + echo -e "\n >>> Installing IncludeOS" make install popd - + # RUNNING IncludeOS PREREQS_RUN="bridge-utils qemu-kvm" echo -e "\n\n >>> Trying to install prerequisites for *running* IncludeOS" echo -e " Packages: $PREREQS_RUN \n" sudo apt-get install -y $PREREQS_RUN - + # Set up the IncludeOS network bridge echo -e "\n\n >>> Create IncludeOS network bridge *Requires sudo* \n" sudo $INCLUDEOS_SRC/etc/create_bridge.sh - + # Copy qemu-ifup til install loc. $INCLUDEOS_SRC/etc/copy_scripts.sh fi diff --git a/src/Makefile b/src/Makefile index 49e8620b42..73b754f8e8 100644 --- a/src/Makefile +++ b/src/Makefile @@ -11,7 +11,7 @@ INSTALL = $(INCLUDEOS_INSTALL) # stackrealign is needed to guarantee 16-byte stack alignment for SSE # the compiler seems to be really dumb in this regard, creating a misaligned stack left and right -CAPABS_COMMON = -mstackrealign -mssse3 +CAPABS_COMMON = -mstackrealign -msse3 CAPABS = $(CAPABS_COMMON) -O2 -DNO_DEBUG=1 -DOS_TERMINATE_ON_CONTRACT_VIOLATION WARNS = -Wall -Wextra #-pedantic @@ -32,8 +32,8 @@ INC_NEWLIB=$(INSTALL)/newlib/include # Compiler/Linker ################################################### -CC = clang-3.6 -CPP = clang++-3.6 +CC = clang-3.8 +CPP = clang++-3.8 # Set defaults if not defined ifndef LD_INC LD_INC = ld diff --git a/src/seed/Makefile b/src/seed/Makefile index 71a8852abd..8f8a231826 100644 --- a/src/seed/Makefile +++ b/src/seed/Makefile @@ -35,8 +35,8 @@ LIBCXX = $(INSTALL)/libcxx/libc++.a $(INSTALL)/libcxx/libc++abi.a INC_NEWLIB=$(INSTALL)/newlib/include INC_LIBCXX=$(INSTALL)/libcxx/include -CC = clang-3.6 -target i686-elf -CPP = clang++-3.6 -target i686-elf +CC = clang-3.8 -target i686-elf +CPP = clang++-3.8 -target i686-elf ifndef LD_INC LD_INC = ld endif From 6e11ac4d05ca618a78713e20e03b58ade9263f1d Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 26 Apr 2016 17:49:23 +0200 Subject: [PATCH 220/311] vmrunner now checks for KVM presence --- test/vmrunner.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/test/vmrunner.py b/test/vmrunner.py index 8cbfddcf81..ac1b8ca963 100644 --- a/test/vmrunner.py +++ b/test/vmrunner.py @@ -82,6 +82,13 @@ def net_arg(self, if_type = "virtio", if_name = "net0", mac="c0:01:0a:00:00:2a") return ["-device", type_names[if_type]+",netdev="+if_name+",mac="+mac, "-netdev", "tap,id="+if_name+",script="+qemu_ifup] + def kvm_present(self): + if subprocess.call("kvm") > 0: + print " KVM OFF" + return False + else: + print " KVM ON" + return True def boot(self): self._out_sign = "<" + type(self).__name__ + ">" @@ -99,7 +106,11 @@ def boot(self): net_args += self.net_arg(net["type"], "net"+str(i), net["mac"]) i+=1 - command = ["sudo", "qemu-system-x86_64","--enable-kvm", "-nographic" ] + disk_args + net_args + command = ["sudo", "qemu-system-x86_64"] + if self.kvm_present(): command.append("--enable-kvm") + + command += ["-nographic" ] + disk_args + net_args + print self._out_sign, "command:", command self._proc = start_process(command) @@ -191,7 +202,7 @@ def boot(self, timeout = None): if self._exit_status: print " Done running VM. Exit status: ", self._exit_status - sys.exit(self._exit_status) + sys.exit(self._exit_status) else: print " Subprocess finished. Exiting with ", self._hyper.poll() sys.exit(self._hyper.poll()) @@ -211,6 +222,10 @@ def wait(self): return self._exit_status + def poll(self): + return self._hyper.poll() + + print print "", "Validating test" From 45109d86955ced0855f03123b29d620fb107b992 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 26 Apr 2016 18:29:05 +0200 Subject: [PATCH 221/311] Fixed kvm verification command --- test/vmrunner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/vmrunner.py b/test/vmrunner.py index ac1b8ca963..be7f369fb5 100644 --- a/test/vmrunner.py +++ b/test/vmrunner.py @@ -83,7 +83,7 @@ def net_arg(self, if_type = "virtio", if_name = "net0", mac="c0:01:0a:00:00:2a") "-netdev", "tap,id="+if_name+",script="+qemu_ifup] def kvm_present(self): - if subprocess.call("kvm") > 0: + if not subprocess.check_output("egrep -m 1 '^flags.*(vmx|svm)' /proc/cpuinfo", shell = True): print " KVM OFF" return False else: From c952216277d63663284b99e3befca63ddc892700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Tue, 26 Apr 2016 18:38:32 +0200 Subject: [PATCH 222/311] tcp: bugfix --- src/net/tcp_connection.cpp | 23 ++++++++++++----------- test/tcp/service.cpp | 4 ++-- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index 9ea00de950..820cb721c9 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -167,7 +167,7 @@ size_t Connection::send(const char* buffer, size_t remaining, size_t& packets_av auto packet = create_outgoing_packet(); packets_avail--; - auto written = fill_packet(packet, buffer, std::min(remaining, (size_t)SMSS())); + auto written = fill_packet(packet, buffer+bytes_written, std::min(remaining, (size_t)SMSS())); bytes_written += written; remaining -= written; @@ -249,10 +249,11 @@ void Connection::limited_tx() { auto& buf = writeq.front().first; auto written = fill_packet(packet, (char*)buf.pos(), std::min(buf.remaining, (uint32_t)SMSS())); + + buf.advance(written); transmit(packet); - buf.advance(written); if(buf.remaining) return; @@ -434,8 +435,8 @@ bool Connection::handle_ack(TCP::Packet_ptr in) { // new ack else if(in->ack() >= cb.SND.UNA) { - printf(" New ACK: %u %s\n", - in->ack() - cb.ISS, fast_recovery ? "[RECOVERY]" : ""); + printf(" New ACK: %u FS: %u %s\n", + in->ack() - cb.ISS, flight_size(), fast_recovery ? "[RECOVERY]" : ""); if( cb.SND.WL1 < in->seq() or ( cb.SND.WL1 == in->seq() and cb.SND.WL2 <= in->ack() ) ) { cb.SND.WND = in->win(); @@ -555,7 +556,7 @@ void Connection::on_dup_ack() { if(limited_tx_) { // try to send one segment if(cb.SND.WND >= SMSS() and (flight_size() <= cb.cwnd + 2*SMSS()) and !writeq.empty()) { - limited_tx(); + //limited_tx(); } } } @@ -577,8 +578,8 @@ void Connection::on_dup_ack() { else { cb.cwnd += SMSS(); // send one segment if possible - //if(can_send()) - // limited_tx(); + if(can_send()) + limited_tx(); } } @@ -697,9 +698,9 @@ void Connection::rtx_clear() { void Connection::rtx_timeout() { // retransmit SND.UNA retransmit(); - auto hax = ++rtx_q.begin(); - for(auto i = 0; i < 2 and hax != rtx_q.end(); i++) - host_.transmit(*hax++); + //auto hax = ++rtx_q.begin(); + //for(auto i = 0; i < 2 and hax != rtx_q.end(); i++) + // host_.transmit(*hax++); if(!rtx_q.front()->isset(SYN)) { // "back off" timer @@ -741,7 +742,7 @@ void Connection::rtx_timeout() { cb.cwnd = SMSS(); /* - NOTE: It's unclear which one comes first, or if finish_fast_recovery includes chaining the cwnd. + NOTE: It's unclear which one comes first, or if finish_fast_recovery includes changing the cwnd. */ } diff --git a/test/tcp/service.cpp b/test/tcp/service.cpp index 9c11217863..0d406b254b 100644 --- a/test/tcp/service.cpp +++ b/test/tcp/service.cpp @@ -46,7 +46,7 @@ int S{150}, B{1500}, H{150000}; std::string -TEST_STR {"1337"}; +TEST_STR {"Kappa!"}; size_t buffers_available{0}; @@ -151,7 +151,7 @@ void Service::start() for(int i = 0; i < B; i++) big += TEST_STR; big += "-end"; - huge += "start-"; + huge = "start-"; for(int i = 0; i < H; i++) huge += TEST_STR; huge += "-end"; From 2af7cbb725f38071b7a106cec0b561fe5200548c Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 26 Apr 2016 22:24:34 +0200 Subject: [PATCH 223/311] Updated transmission test to detect packet loss / reorder --- test/transmit/service.cpp | 10 ++++++--- test/transmit/test.py | 47 ++++++++++++++++++++++++++------------- test/vmrunner.py | 30 ++++++++++++++++++++----- 3 files changed, 63 insertions(+), 24 deletions(-) diff --git a/test/transmit/service.cpp b/test/transmit/service.cpp index 1b84c400bb..be057a7b29 100644 --- a/test/transmit/service.cpp +++ b/test/transmit/service.cpp @@ -67,12 +67,16 @@ void Service::start() conn.sendto(addr, port, first_reply.c_str(), first_reply.size()); timer.onTimeout(1s, [&conn, addr, port, data, len]() { - INFO("Test 2", "Trying to transmit %i UDP packets at maximum throttle", packets); + auto bufcount = inet->buffers_available(); + size_t packetsize = inet->ip_obj().MDDS() - sizeof(UDP::udp_header); + INFO("Test 2", "Trying to transmit %i UDP packets of size %i at maximum throttle", + packets, packetsize); for (int i = 0; i < packets; i++) { - string send = "Packet " + std::to_string(i) + "\n"; - //printf(" %s", send.c_str()); + char c = (char)('A' + (i % 26)); + string send (packetsize, c); + printf(" %i nr. of %c \n", send.size(), c); conn.sendto(addr, port, send.c_str() , send.size()); } diff --git a/test/transmit/test.py b/test/transmit/test.py index c93a207400..a2b636efcd 100755 --- a/test/transmit/test.py +++ b/test/transmit/test.py @@ -13,6 +13,20 @@ vm = vmrunner.vms[0] +packet_content = True +def assert_packet_content(test): + if not test: + packet_content = False + print " FAIL: Packet content is wrong" + return test + +packet_order = True +def assert_packet_order(test): + if not test: + packet_order = False + print " FAIL: Packet order is wrong" + return test + def UDP_test(): print " Performing UDP test 1" @@ -23,28 +37,31 @@ def UDP_test(): print " Sent: {}".format(data) print " Received: {}".format(received) - prev = -1 + expect = "A" OK = False - + i = 1 + bytes_received = 0; while not vm.poll(): - received = sock.recv(1500) - nr = int(received.split(" ")[1]); + received = sock.recv(65000) + bytes_received += len(received) + first_char = received[0] + last_char = received[len(received)-1] + print "Packet",i,len(received),"bytes, (",bytes_received," total)",first_char, " - ", last_char - if nr != prev + 1: - break + if not assert_packet_content(first_char == last_char): return False + if not assert_packet_order(ord(first_char) == ord(expect)): return False - print "Got packet ", nr + # Make sure the chars in this packets were incremented or wrapped around + if first_char == 'Z' : expect = "A" + else : expect = chr(ord(first_char) + 1) + i += 1 - prev += 1 - if nr == 599: - OK = True + if (bytes_received >= 600 * 1472): break - if OK: - print " SUCCESS - correct packet order" - sock.sendto("SUCCESS", (HOST, PORT)) - else: - print " FAILED - incorrect packet order" + + return packet_order and packet_content + # Add custom event-handler vm.on_output("Done. Send some UDP-data", UDP_test) diff --git a/test/vmrunner.py b/test/vmrunner.py index be7f369fb5..9df9752427 100644 --- a/test/vmrunner.py +++ b/test/vmrunner.py @@ -20,6 +20,14 @@ else: INCLUDEOS_HOME = os.environ['INCLUDEOS_HOME'] +# Exit codes used by this program +exit_codes = {"SUCCESS" : 0, + "PROGRAM_FAILURE" : 1, + "TIMEOUT" : 66, + "VM_FAIL" : 67, + "OUTSIDE_FAIL" : 68 } + + def abstract(): raise Exception("Abstract class method called. Use a subclass") # Hypervisor base / super class @@ -83,7 +91,8 @@ def net_arg(self, if_type = "virtio", if_name = "net0", mac="c0:01:0a:00:00:2a") "-netdev", "tap,id="+if_name+",script="+qemu_ifup] def kvm_present(self): - if not subprocess.check_output("egrep -m 1 '^flags.*(vmx|svm)' /proc/cpuinfo", shell = True): + command = "egrep -m 1 '^flags.*(vmx|svm)' /proc/cpuinfo" + if not subprocess.check_output(command, shell = True): print " KVM OFF" return False else: @@ -122,6 +131,7 @@ def stop(self): subprocess.check_call(["sudo","kill", "-SIGTERM", str(self._proc.pid)]) # Wait for termination (avoids the need to reset the terminal) self._proc.wait() + return self def wait(self): print self._out_sign, "Waiting for process to terminate" @@ -138,12 +148,13 @@ def poll(self): # VM class class vm: + def __init__(self, config, hyper = qemu): self._exit_status = 0 self._config = config - self._on_success = lambda : self.exit(0, " SUCCESS : All tests passed") - self._on_panic = lambda : self.exit(66, " FAIL : " + self._hyper.readline()) - self._on_timeout = lambda : self.exit(67, " TIMEOUT: Test timed out") + self._on_success = lambda : self.exit(exit_codes["SUCCESS"], " SUCCESS : All tests passed") + self._on_panic = lambda : self.exit(exit_codes["VM_FAIL"], " FAIL : " + self._hyper.readline()) + self._on_timeout = lambda : self.exit(exit_codes["TIMEOUT"], " TIMEOUT: Test timed out") self._on_output = { "PANIC" : self._on_panic, "SUCCESS" : self._on_success } @@ -193,7 +204,14 @@ def boot(self, timeout = None): # Look for event-triggers for pattern, func in self._on_output.iteritems(): if re.search(pattern, line): - func() + res = func() + #NOTE: It can be 'None' without problem + if res == False: + self._exit_status = exit_codes["OUTSIDE_FAIL"] + self.exit(self._exit_status, " External test failed") + print " VM-external test failed" + + # Now we either have an exit status from timer thread, or an exit status # from the subprocess. @@ -213,7 +231,7 @@ def stop(self): self._hyper.stop() if hasattr(self, "_timer") and self._timer: self._timer.cancel() - + return self def wait(self): if hasattr(self, "_timer") and self._timer: From b3fdb79389eae85085da9a394c24fcfdd664d7e5 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 26 Apr 2016 22:51:52 +0200 Subject: [PATCH 224/311] Updated UDP to use correct MDDS + (chain packets WIP) --- api/net/ip4/udp.hpp | 5 ++++ src/net/ip4/udp.cpp | 64 +++++++++++++++++++++++++++++---------------- 2 files changed, 46 insertions(+), 23 deletions(-) diff --git a/api/net/ip4/udp.hpp b/api/net/ip4/udp.hpp index 4356d219b2..cec1ec59a0 100644 --- a/api/net/ip4/udp.hpp +++ b/api/net/ip4/udp.hpp @@ -124,9 +124,14 @@ namespace net { // send as much as possible from sendq void flush(); + // create and transmit @num packets from sendq void process_sendq(size_t num); + inline constexpr uint16_t max_datagram_size() noexcept { + return stack().ip_obj().MDDS() - sizeof(udp_header); + } + private: downstream network_layer_out_; diff --git a/src/net/ip4/udp.cpp b/src/net/ip4/udp.cpp index cfea2c4868..5533c735c9 100644 --- a/src/net/ip4/udp.cpp +++ b/src/net/ip4/udp.cpp @@ -100,6 +100,8 @@ namespace net { { size_t packets = stack_.transmit_queue_available(); if (packets) process_sendq(packets); + //else debug(" Transmit queue full. Waiting for offer"); + } void UDP::process_sendq(size_t num) @@ -131,9 +133,9 @@ namespace net { { int r = remaining(); // whole packets - size_t P = r / udp.stack().MTU(); + size_t P = r / udp.max_datagram_size(); // one packet for remainder - if (r % udp.stack().MTU()) P++; + if (r % udp.max_datagram_size()) P++; return P; } UDP::WriteBuffer::WriteBuffer( @@ -152,35 +154,51 @@ namespace net { void UDP::WriteBuffer::write() { - const size_t MTU = udp.stack().MTU(); - // the maximum we can write per packet: - const size_t WRITE_MAX = MTU - PacketUDP::HEADERS_SIZE; // the bytes remaining to be written - size_t total = remaining(); - total = (total > WRITE_MAX) ? WRITE_MAX : total; + UDP::Packet_ptr chain_head{}; + + debug(" %i bytes to write, need %i packets \n", + remaining(), remaining() / udp.max_datagram_size() + (remaining() % udp.max_datagram_size() ? 1 : 0)); + + int i = 0; + + do { + debug("\tCreating packet %i \n", i++); + size_t total = remaining(); + total = (total > udp.max_datagram_size()) ? udp.max_datagram_size() : total; - // create some packet p (and convert it to PacketUDP) - auto p = udp.stack().createPacket(MTU); - // fill buffer (at payload position) - memcpy(p->buffer() + PacketUDP::HEADERS_SIZE, - buf.get() + this->offset, total); + // create some packet p (and convert it to PacketUDP) + auto p = udp.stack().createPacket(0); + // fill buffer (at payload position) + memcpy(p->buffer() + PacketUDP::HEADERS_SIZE, + buf.get() + this->offset, total); - // initialize packet with several infos - auto p2 = std::static_pointer_cast(p); + // initialize packet with several infos + auto p2 = std::static_pointer_cast(p); - p2->init(); - p2->header().sport = htons(l_port); - p2->header().dport = htons(d_port); - p2->set_src(l_addr); - p2->set_dst(d_addr); - p2->set_length(total); + p2->init(); + p2->header().sport = htons(l_port); + p2->header().dport = htons(d_port); + p2->set_src(l_addr); + p2->set_dst(d_addr); + p2->set_length(total); + + // Attach packet to chain + if (!chain_head) + chain_head = p2; + else + chain_head->chain(p2); + + // next position in buffer + this->offset += total; + + } while ( remaining() ); // ship the packet - udp.transmit(p2); + udp.transmit(chain_head); + - // next position in buffer - this->offset += total; } } //< namespace net From 6492de28e493d68ce9f7c34b63081cbb45aa86d8 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 26 Apr 2016 21:09:08 +0000 Subject: [PATCH 225/311] Transmission test properly signals SUCCESS --- test/transmit/test.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/transmit/test.py b/test/transmit/test.py index a2b636efcd..4dce022f10 100755 --- a/test/transmit/test.py +++ b/test/transmit/test.py @@ -58,7 +58,9 @@ def UDP_test(): if (bytes_received >= 600 * 1472): break - + + if packet_order and packet_content: + sock.sendto("SUCCESS", (HOST, PORT)) return packet_order and packet_content From 47a4b043d908d9212722aeec7ff957d82ae5d958 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Wed, 27 Apr 2016 07:17:53 +0000 Subject: [PATCH 226/311] Added timing to the transmission test --- test/transmit/service.cpp | 4 ++-- test/transmit/test.py | 17 ++++++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/test/transmit/service.cpp b/test/transmit/service.cpp index be057a7b29..eacbd38ffa 100644 --- a/test/transmit/service.cpp +++ b/test/transmit/service.cpp @@ -58,7 +58,7 @@ void Service::start() INFO("Test 2","Starting UDP-test. Got UDP data from %s: %i: %s", addr.str().c_str(), port, received.c_str()); - const int packets { 600 }; + const int packets { 2400 }; string first_reply {string("Received '") + received + "'. Expect " + to_string(packets) + " packets in 1s\n" }; @@ -76,7 +76,7 @@ void Service::start() for (int i = 0; i < packets; i++) { char c = (char)('A' + (i % 26)); string send (packetsize, c); - printf(" %i nr. of %c \n", send.size(), c); + //printf(" %i nr. of %c \n", send.size(), c); conn.sendto(addr, port, send.c_str() , send.size()); } diff --git a/test/transmit/test.py b/test/transmit/test.py index 4dce022f10..c0d8038d2d 100755 --- a/test/transmit/test.py +++ b/test/transmit/test.py @@ -4,6 +4,7 @@ import vmrunner import socket +import time HOST, PORT = "10.0.0.42", 4242 # SOCK_DGRAM is the socket type to use for UDP sockets @@ -38,15 +39,22 @@ def UDP_test(): print " Received: {}".format(received) expect = "A" + + packet_size = 1472 + packet_count = 2400 + OK = False i = 1 bytes_received = 0; + + t1 = time.clock() + while not vm.poll(): received = sock.recv(65000) bytes_received += len(received) first_char = received[0] last_char = received[len(received)-1] - print "Packet",i,len(received),"bytes, (",bytes_received," total)",first_char, " - ", last_char + #print "Packet",i,len(received),"bytes, (",bytes_received," total)",first_char, " - ", last_char if not assert_packet_content(first_char == last_char): return False if not assert_packet_order(ord(first_char) == ord(expect)): return False @@ -56,9 +64,12 @@ def UDP_test(): else : expect = chr(ord(first_char) + 1) i += 1 - if (bytes_received >= 600 * 1472): + if (bytes_received >= packet_count * packet_size): break - + + time_taken = time.clock() - t1 + print " Transmission finished in ", time_taken + if packet_order and packet_content: sock.sendto("SUCCESS", (HOST, PORT)) From c4f448c445e7c69d9c6a109b6be75280d8d4b7e9 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Wed, 27 Apr 2016 12:08:57 +0200 Subject: [PATCH 227/311] Added getter for number of arrived incoming packets --- api/hw/nic.hpp | 4 ++++ api/virtio/virtionet.hpp | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/api/hw/nic.hpp b/api/hw/nic.hpp index 098e2d2929..4e670ac535 100644 --- a/api/hw/nic.hpp +++ b/api/hw/nic.hpp @@ -73,6 +73,10 @@ namespace hw { inline size_t transmit_queue_available() { return driver_.transmit_queue_available(); } + inline size_t receive_queue_waiting(){ + return driver_.receive_queue_waiting(); + }; + inline size_t buffers_available() { return bufstore().buffers_available(); } diff --git a/api/virtio/virtionet.hpp b/api/virtio/virtionet.hpp index 65c6f63f3c..d1494feea8 100644 --- a/api/virtio/virtionet.hpp +++ b/api/virtio/virtionet.hpp @@ -152,6 +152,11 @@ class VirtioNet : Virtio { return tx_q.num_free() / 2; }; + /** Number of incoming packets waiting in the RX-queue */ + inline size_t receive_queue_waiting(){ + return rx_q.new_incoming() / 2; + }; + inline void on_exit_to_physical(delegate dlg) { on_exit_to_physical_ = dlg; }; From 71691e53e7b03f3bcbf86181e1c5a03d4310e26e Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Wed, 27 Apr 2016 12:11:22 +0200 Subject: [PATCH 228/311] Merge? --- api/hw/pit.hpp | 5 +++-- api/net/inet4.hpp | 9 +++------ api/net/inet4.inc | 30 ++++++++++++++---------------- src/Makefile | 6 +++--- src/debug/test_disk.cpp | 2 +- src/seed/Makefile | 4 ++-- test/tcp/service.cpp | 9 +++++++++ test/tcp/test.py | 0 8 files changed, 35 insertions(+), 30 deletions(-) mode change 100644 => 100755 test/tcp/test.py diff --git a/api/hw/pit.hpp b/api/hw/pit.hpp index a730f50eed..d3bf92a157 100644 --- a/api/hw/pit.hpp +++ b/api/hw/pit.hpp @@ -83,8 +83,9 @@ namespace hw { @param handler: A delegate or function to be called on timeout. */ Timer_iterator onTimeout(std::chrono::milliseconds ms, timeout_handler handler); - Timer_iterator on_timeout(double sec, timeout_handler handler) - { return onTimeout(std::chrono::milliseconds((unsigned)(sec * 1000)), handler); } + static Timer_iterator on_timeout(double sec, timeout_handler handler) { + return instance().onTimeout(std::chrono::milliseconds((unsigned)(sec * 1000)), handler); + } /** Create a repeating timer. @param ms: Expiration time. Compatible with all std::chrono durations. diff --git a/api/net/inet4.hpp b/api/net/inet4.hpp index 79d1fe27cb..977f11f675 100644 --- a/api/net/inet4.hpp +++ b/api/net/inet4.hpp @@ -74,7 +74,7 @@ namespace net { @todo make_shared will allocate with new. This is fast in IncludeOS, (no context switch for sbrk) but consider overloading operator new. */ - inline Packet_ptr createPacket(size_t size) override { + virtual Packet_ptr createPacket(size_t size) override { // Create a release delegate, for returning buffers auto release = BufferStore::release_del::from (nic_.bufstore()); @@ -84,12 +84,9 @@ namespace net { } // We have to ask the Nic for the MTU - virtual inline uint16_t MTU() const override + virtual uint16_t MTU() const override { return nic_.MTU(); } - inline auto available_capacity() - { return bufstore_.capacity(); } - /** * @func a delegate that provides a hostname and its address, which is 0 if the * name @hostname was not found. Note: Test with INADDR_ANY for a 0-address. @@ -142,7 +139,7 @@ namespace net { return nic_.transmit_queue_available(); } - inline virtual size_t buffers_available() override { + virtual size_t buffers_available() override { return nic_.buffers_available(); } diff --git a/api/net/inet4.inc b/api/net/inet4.inc index d06dbcebce..21b969e3a6 100644 --- a/api/net/inet4.inc +++ b/api/net/inet4.inc @@ -5,7 +5,7 @@ namespace net { - template + template inline Inet4::Inet4(hw::Nic& nic, IP4::addr ip, IP4::addr netmask) : ip4_addr_(ip), netmask_(netmask), router_(IP4::INADDR_ANY), nic_(nic), eth_(nic.mac()), arp_(*this), ip4_(*this), @@ -77,25 +77,24 @@ namespace net eth_.set_physical_out(phys_top); } - template + template inline Inet4::Inet4(hw::Nic& nic) : Inet4(nic, IP4::INADDR_ANY, IP4::INADDR_ANY) { - INFO("Inet4","Applying DHCP client"); + INFO("Inet4", "Trying DHCP..."); dhcp_ = std::make_shared(*this); // 2 second timeout for DHCP-server negotation dhcp_->negotiate(30.0); } - template - void Inet4::on_config(delegate handler) - { + template inline + void Inet4::on_config(delegate handler) { dhcp_->on_config(handler); } - template - void Inet4::process_sendq(size_t packets) - { + template inline + void Inet4::process_sendq(size_t packets) { + //////////////////////////////////////////// // divide up fairly size_t div = packets / tqa.size(); @@ -105,13 +104,12 @@ namespace net tqa[i](div); // hand out remaining - for (size_t i = 0; i < tqa.size(); i++) - { - div = transmit_queue_available(); - if (!div) break; - // give as much as possible - tqa[i](div); - } + for (size_t i = 0; i < tqa.size(); i++) { + div = transmit_queue_available(); + if (!div) break; + // give as much as possible + tqa[i](div); + } //////////////////////////////////////////// /* diff --git a/src/Makefile b/src/Makefile index 49e8620b42..73b754f8e8 100644 --- a/src/Makefile +++ b/src/Makefile @@ -11,7 +11,7 @@ INSTALL = $(INCLUDEOS_INSTALL) # stackrealign is needed to guarantee 16-byte stack alignment for SSE # the compiler seems to be really dumb in this regard, creating a misaligned stack left and right -CAPABS_COMMON = -mstackrealign -mssse3 +CAPABS_COMMON = -mstackrealign -msse3 CAPABS = $(CAPABS_COMMON) -O2 -DNO_DEBUG=1 -DOS_TERMINATE_ON_CONTRACT_VIOLATION WARNS = -Wall -Wextra #-pedantic @@ -32,8 +32,8 @@ INC_NEWLIB=$(INSTALL)/newlib/include # Compiler/Linker ################################################### -CC = clang-3.6 -CPP = clang++-3.6 +CC = clang-3.8 +CPP = clang++-3.8 # Set defaults if not defined ifndef LD_INC LD_INC = ld diff --git a/src/debug/test_disk.cpp b/src/debug/test_disk.cpp index 168bf0e986..d2b0fe2248 100644 --- a/src/debug/test_disk.cpp +++ b/src/debug/test_disk.cpp @@ -13,7 +13,7 @@ void Service::start() auto& device = hw::Dev::disk<1, VirtioBlk>(); disk = std::make_shared (device); assert(disk); - + // if the disk is empty, we can't mount a filesystem anyways if (disk->empty()) panic("Oops! The disk is empty!\n"); diff --git a/src/seed/Makefile b/src/seed/Makefile index 71a8852abd..8f8a231826 100644 --- a/src/seed/Makefile +++ b/src/seed/Makefile @@ -35,8 +35,8 @@ LIBCXX = $(INSTALL)/libcxx/libc++.a $(INSTALL)/libcxx/libc++abi.a INC_NEWLIB=$(INSTALL)/newlib/include INC_LIBCXX=$(INSTALL)/libcxx/include -CC = clang-3.6 -target i686-elf -CPP = clang++-3.6 -target i686-elf +CC = clang-3.8 -target i686-elf +CPP = clang++-3.8 -target i686-elf ifndef LD_INC LD_INC = ld endif diff --git a/test/tcp/service.cpp b/test/tcp/service.cpp index 0d406b254b..2ee4671769 100644 --- a/test/tcp/service.cpp +++ b/test/tcp/service.cpp @@ -143,8 +143,17 @@ struct Buffer { std::string str() { return {data, size};} }; +void print_stuff() +{ + printf("TIMER: Buffers avail: %u / %u Transmit avail: %u\n", + inet->buffers_available(), buffers_available, inet->transmit_queue_available()); + hw::PIT::on_timeout(5.0, print_stuff); +} + void Service::start() { + hw::PIT::on_timeout(5.0, print_stuff); + for(int i = 0; i < S; i++) small += TEST_STR; big += "start-"; diff --git a/test/tcp/test.py b/test/tcp/test.py old mode 100644 new mode 100755 From 98af6a39d7484e8af89cfd00a53aa9c5f1697646 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Wed, 27 Apr 2016 12:13:18 +0200 Subject: [PATCH 229/311] udp: Remove unused integer --- src/net/ip4/udp.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/net/ip4/udp.cpp b/src/net/ip4/udp.cpp index 5533c735c9..95a0d2026e 100644 --- a/src/net/ip4/udp.cpp +++ b/src/net/ip4/udp.cpp @@ -161,10 +161,7 @@ namespace net { debug(" %i bytes to write, need %i packets \n", remaining(), remaining() / udp.max_datagram_size() + (remaining() % udp.max_datagram_size() ? 1 : 0)); - int i = 0; - do { - debug("\tCreating packet %i \n", i++); size_t total = remaining(); total = (total > udp.max_datagram_size()) ? udp.max_datagram_size() : total; From 7eaeed61650c608943e2f4ad2302ce734c936cad Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Wed, 27 Apr 2016 15:49:07 +0200 Subject: [PATCH 230/311] TCP checksum now adds in any carry bit --- src/net/tcp.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/net/tcp.cpp b/src/net/tcp.cpp index 622cd45a5e..d10d20b1a0 100644 --- a/src/net/tcp.cpp +++ b/src/net/tcp.cpp @@ -109,7 +109,7 @@ uint16_t TCP::checksum(TCP::Packet_ptr packet) { pseudo_hdr.proto = IP4::IP4_TCP; pseudo_hdr.tcp_length = htons(tcp_length); - union { + union Sum{ uint32_t whole; uint16_t part[2]; } sum; @@ -139,7 +139,12 @@ uint16_t TCP::checksum(TCP::Packet_ptr packet) { debug2(" Date: Wed, 27 Apr 2016 16:26:46 +0200 Subject: [PATCH 231/311] ip: Refactor IP4 addr to struct --- api/net/dns/dns.hpp | 2 +- api/net/inet4.inc | 1 + api/net/ip4/ip4.hpp | 42 ++++++++++++++++++++++---------------- api/net/ip4/packet_ip4.hpp | 3 ++- src/net/dns/dns.cpp | 22 ++++++++------------ src/net/ip4/ip4.cpp | 22 ++++++++------------ test/tcp/service.cpp | 24 +++++++++++++++------- 7 files changed, 62 insertions(+), 54 deletions(-) diff --git a/api/net/dns/dns.hpp b/api/net/dns/dns.hpp index ea55d0f43b..8b2bd9f2d5 100644 --- a/api/net/dns/dns.hpp +++ b/api/net/dns/dns.hpp @@ -159,7 +159,7 @@ namespace net } IP4::addr getFirstIP4() const { - IP4::addr result{{0}}; + IP4::addr result(0); if (answers.size()) result = answers[0].getIP4(); return result; diff --git a/api/net/inet4.inc b/api/net/inet4.inc index 21b969e3a6..dca96f1549 100644 --- a/api/net/inet4.inc +++ b/api/net/inet4.inc @@ -14,6 +14,7 @@ namespace net { debug(" Constructor. TCP @ %p has %i open ports. \n", &tcp_, tcp_.openPorts()); INFO("Inet4","Bringing up the IP stack"); + Ensures(sizeof(IP4::addr) == 4); /** Upstream delegates */ auto eth_bottom(upstream::from(eth_)); diff --git a/api/net/ip4/ip4.hpp b/api/net/ip4/ip4.hpp index 0009be70f0..42dcd5d8a7 100644 --- a/api/net/ip4/ip4.hpp +++ b/api/net/ip4/ip4.hpp @@ -40,53 +40,59 @@ namespace net { enum proto { IP4_ICMP=1, IP4_UDP=17, IP4_TCP=6 }; /** IP4 address representation */ - union __attribute__((packed)) addr { - uint8_t part[4]; + struct addr { uint32_t whole; - - /** - * NOTE: Constructors - * Can't have them - removes the packed-attribute - */ - + + addr() : whole(0) {} // uninitialized + addr(uint32_t ipaddr) + : whole(ipaddr) {} + addr(uint8_t p1, uint8_t p2, uint8_t p3, uint8_t p4) + : whole(p1 | (p2 << 8) | (p3 << 16) | (p4 << 24)) {} + inline addr& operator=(addr cpy) noexcept { whole = cpy.whole; return *this; } /** Standard comparison operators */ - inline bool operator==(addr rhs) const noexcept + bool operator==(addr rhs) const noexcept { return whole == rhs.whole; } - inline bool operator==(const uint32_t rhs) const noexcept + bool operator==(const uint32_t rhs) const noexcept { return whole == rhs; } - inline bool operator<(const addr rhs) const noexcept + bool operator<(const addr rhs) const noexcept { return whole < rhs.whole; } - inline bool operator<(const uint32_t rhs) const noexcept + bool operator<(const uint32_t rhs) const noexcept { return whole < rhs; } - inline bool operator>(const addr rhs) const noexcept + bool operator>(const addr rhs) const noexcept { return whole > rhs.whole; } - inline bool operator>(const uint32_t rhs) const noexcept + bool operator>(const uint32_t rhs) const noexcept { return whole > rhs; } - inline bool operator!=(const addr rhs) const noexcept + bool operator!=(const addr rhs) const noexcept { return whole != rhs.whole; } - inline bool operator!=(const uint32_t rhs) const noexcept + bool operator!=(const uint32_t rhs) const noexcept { return whole != rhs; } + addr operator & (addr rhs) const noexcept + { return addr(whole & rhs.whole); } + /** x.x.x.x string representation */ std::string str() const { char ip_addr[16]; sprintf(ip_addr, "%1i.%1i.%1i.%1i", - part[0], part[1], part[2], part[3]); + (whole >> 0) & 0xFF, + (whole >> 8) & 0xFF, + (whole >> 16) & 0xFF, + (whole >> 24) & 0xFF); return ip_addr; } - }; //< union addr + } __attribute__((packed)); //< IP4::addr static const addr INADDR_ANY; static const addr INADDR_BCAST; diff --git a/api/net/ip4/packet_ip4.hpp b/api/net/ip4/packet_ip4.hpp index 34e016d3ed..d7a4d5e580 100644 --- a/api/net/ip4/packet_ip4.hpp +++ b/api/net/ip4/packet_ip4.hpp @@ -87,7 +87,8 @@ namespace net { hdr.check = 0; hdr.check = net::checksum(&hdr, sizeof(IP4::ip_header)); } - + + friend class IP4; }; //< class PacketIP4 } //< namespace net diff --git a/src/net/dns/dns.cpp b/src/net/dns/dns.cpp index c8b6131b7c..a671c60ad4 100644 --- a/src/net/dns/dns.cpp +++ b/src/net/dns/dns.cpp @@ -278,18 +278,14 @@ namespace net IP4::addr DNS::Request::rr_t::getIP4() const { - switch (ntohs(resource.type)) - { - case DNS_TYPE_A: - { - IP4::addr* addr = (IP4::addr*) rdata.c_str(); - return *addr; - } - case DNS_TYPE_ALIAS: - case DNS_TYPE_NS: - default: - return IP4::addr{{0}}; - } + switch (ntohs(resource.type)) { + case DNS_TYPE_A: + return *(IP4::addr*) rdata.data(); + case DNS_TYPE_ALIAS: + case DNS_TYPE_NS: + default: + return IP4::INADDR_ANY; + } } void DNS::Request::rr_t::print() { @@ -298,7 +294,7 @@ namespace net { case DNS_TYPE_A: { - IP4::addr* addr = (IP4::addr*) rdata.c_str(); + auto* addr = (IP4::addr*) rdata.data(); printf("has IPv4 address: %s", addr->str().c_str()); } break; diff --git a/src/net/ip4/ip4.cpp b/src/net/ip4/ip4.cpp index e55adc943a..e81a3b869c 100644 --- a/src/net/ip4/ip4.cpp +++ b/src/net/ip4/ip4.cpp @@ -25,8 +25,8 @@ namespace net { - const IP4::addr IP4::INADDR_ANY {{0,0,0,0}}; - const IP4::addr IP4::INADDR_BCAST {{0xff,0xff,0xff,0xff}}; + const IP4::addr IP4::INADDR_ANY(0); + const IP4::addr IP4::INADDR_BCAST(0xff,0xff,0xff,0xff); IP4::IP4(Inet& inet) noexcept: stack_{inet} @@ -71,22 +71,19 @@ namespace net { void IP4::transmit(Packet_ptr pckt) { assert(pckt->size() > sizeof(IP4::full_header)); - full_header* full_hdr = reinterpret_cast(pckt->buffer()); - ip_header* hdr = &full_hdr->ip_hdr; - auto ip4_pckt = std::static_pointer_cast(pckt); ip4_pckt->make_flight_ready(); + IP4::ip_header& hdr = ip4_pckt->ip4_header(); // Create local and target subnets - addr target, local; - target.whole = hdr->daddr.whole & stack_.netmask().whole; - local.whole = stack_.ip_addr().whole & stack_.netmask().whole; - + addr target = hdr.daddr & stack_.netmask(); + addr local = stack_.ip_addr() & stack_.netmask(); + // Compare subnets to know where to send packet - pckt->next_hop(target == local ? hdr->daddr : stack_.router()); + pckt->next_hop(target == local ? hdr.daddr : stack_.router()); debug(" Next hop for %s, (netmask %s, local IP: %s, gateway: %s) == %s\n", - hdr->daddr.str().c_str(), + hdr.daddr.str().c_str(), stack_.netmask().str().c_str(), stack_.ip_addr().str().c_str(), stack_.router().str().c_str(), @@ -98,9 +95,6 @@ namespace net { pckt->size(), ip4_pckt->ip4_segment_size() ); - auto tcp = std::static_pointer_cast (pckt); - printf(" TCP seq=%u data=%u size=%u seg=%u\n", - tcp->seq(), tcp->data_length(), pckt->size(), ip4_pckt->ip4_segment_size()); linklayer_out_(pckt); } diff --git a/test/tcp/service.cpp b/test/tcp/service.cpp index 2ee4671769..64f0da73fe 100644 --- a/test/tcp/service.cpp +++ b/test/tcp/service.cpp @@ -154,6 +154,18 @@ void Service::start() { hw::PIT::on_timeout(5.0, print_stuff); + IP4::addr A1 (255, 255, 255, 255); + IP4::addr B1 ( 0, 255, 255, 255); + IP4::addr C1 ( 0, 0, 255, 255); + IP4::addr D1 ( 0, 0, 0, 255); + IP4::addr E1 ( 0, 0, 0, 0); + printf("A: %s\n", A1.str().c_str()); + printf("B: %s\n", B1.str().c_str()); + printf("C: %s\n", C1.str().c_str()); + printf("D: %s\n", D1.str().c_str()); + printf("E: %s\n", E1.str().c_str()); + printf("D & A: %s\n", (D1 & A1).str().c_str()); + for(int i = 0; i < S; i++) small += TEST_STR; big += "start-"; @@ -167,13 +179,11 @@ void Service::start() hw::Nic& eth0 = hw::Dev::eth<0,VirtioNet>(); //eth0.on_exit_to_physical(outgoing_packet); inet = std::make_unique>(eth0); - - - inet->network_config( {{ 10,0,0,42 }}, // IP - {{ 255,255,255,0 }}, // Netmask - {{ 10,0,0,1 }}, // Gateway - {{ 8,8,8,8 }} ); // DNS - + inet->network_config( { 10, 0, 0, 42 }, // IP + { 255,255,255, 0 }, // Netmask + { 10, 0, 0, 1 }, // Gateway + { 8, 8, 8, 8 } );// DNS + buffers_available = inet->buffers_available(); INFO("Buffers available", "%u", inet->buffers_available()); auto& tcp = inet->tcp(); From dd543c5c0fc6bd1cc7e687470433c6fa0f5c908f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Thu, 28 Apr 2016 10:28:50 +0200 Subject: [PATCH 232/311] tcp: minor changes --- api/net/tcp.hpp | 1 + src/net/tcp_connection.cpp | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index 53ac9fe642..0318ed015b 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -1450,6 +1450,7 @@ namespace net { size_t dup_acks_ = 0; Seq prev_highest_ack_ = 0; Seq highest_ack_ = 0; + size_t acks_rcvd_ = 0; Seq RENO_PREV_HIGHEST_ACK = 0; Seq RENO_HIGHEST_ACK = 0; diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index 820cb721c9..70fc1c3b66 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -435,8 +435,7 @@ bool Connection::handle_ack(TCP::Packet_ptr in) { // new ack else if(in->ack() >= cb.SND.UNA) { - printf(" New ACK: %u FS: %u %s\n", - in->ack() - cb.ISS, flight_size(), fast_recovery ? "[RECOVERY]" : ""); + if( cb.SND.WL1 < in->seq() or ( cb.SND.WL1 == in->seq() and cb.SND.WL2 <= in->ack() ) ) { cb.SND.WND = in->win(); @@ -445,6 +444,11 @@ bool Connection::handle_ack(TCP::Packet_ptr in) { //printf(" Window update (%u)\n", cb.SND.WND); } + acks_rcvd_++; + + printf(" New ACK#%u: %u FS: %u %s\n", acks_rcvd_, + in->ack() - cb.ISS, flight_size(), fast_recovery ? "[RECOVERY]" : ""); + // [RFC 6582] p. 8 prev_highest_ack_ = cb.SND.UNA; highest_ack_ = in->ack(); @@ -487,6 +491,7 @@ bool Connection::handle_ack(TCP::Packet_ptr in) { } // < congestion avoidance // try to write + //if(can_send() and acks_rcvd_ % 2 == 1) if(can_send()) send_much(); @@ -556,7 +561,7 @@ void Connection::on_dup_ack() { if(limited_tx_) { // try to send one segment if(cb.SND.WND >= SMSS() and (flight_size() <= cb.cwnd + 2*SMSS()) and !writeq.empty()) { - //limited_tx(); + limited_tx(); } } } @@ -626,6 +631,7 @@ void Connection::retransmit() { if(rtx_q.empty()) return; auto packet = rtx_q.front(); + packet->clear_flag(PSH); //printf(" rseq=%u \n", packet->seq() - cb.ISS); printf(" RT %s\n", packet->to_string().c_str()); Ensures(packet->tail() == nullptr); From e9411c0e043fc80719930da082a5bf79982458de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Thu, 28 Apr 2016 10:43:22 +0200 Subject: [PATCH 233/311] tcp: silenced debug output --- src/net/ip4/ip4.cpp | 4 ---- src/net/tcp.cpp | 6 ++--- src/net/tcp_connection.cpp | 47 +++++++++++++++----------------------- test/tcp/service.cpp | 7 ------ test/tcp/test.py | 2 +- 5 files changed, 22 insertions(+), 44 deletions(-) diff --git a/src/net/ip4/ip4.cpp b/src/net/ip4/ip4.cpp index e55adc943a..98d5266fdd 100644 --- a/src/net/ip4/ip4.cpp +++ b/src/net/ip4/ip4.cpp @@ -21,7 +21,6 @@ #include #include #include -#include namespace net { @@ -98,9 +97,6 @@ namespace net { pckt->size(), ip4_pckt->ip4_segment_size() ); - auto tcp = std::static_pointer_cast (pckt); - printf(" TCP seq=%u data=%u size=%u seg=%u\n", - tcp->seq(), tcp->data_length(), pckt->size(), ip4_pckt->ip4_segment_size()); linklayer_out_(pckt); } diff --git a/src/net/tcp.cpp b/src/net/tcp.cpp index d10d20b1a0..1a7884b59a 100644 --- a/src/net/tcp.cpp +++ b/src/net/tcp.cpp @@ -191,7 +191,7 @@ void TCP::bottom(net::Packet_ptr packet_ptr) { } void TCP::process_writeq(size_t packets) { - printf(" size=%u p=%u\n", writeq.size(), packets); + debug2(" size=%u p=%u\n", writeq.size(), packets); // foreach connection who wants to write while(packets and !writeq.empty()) { auto conn = writeq.front(); @@ -205,14 +205,14 @@ size_t TCP::send(Connection_ptr conn, const char* buffer, size_t n) { size_t written{0}; auto packets = inet_.transmit_queue_available(); - printf(" Send request for %u bytes\n", n); + debug2(" Send request for %u bytes\n", n); if(packets > 0) { written += conn->send(buffer, n, packets); } // if connection still can send (means there wasn't enough packets) if(conn->can_send()) { - printf(" Conn queued.\n"); + debug2(" Conn queued.\n"); writeq.push_back(conn); conn->set_queued(true); } diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index 70fc1c3b66..5c47a9e2a1 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -119,7 +119,7 @@ void Connection::write(WriteBuffer buffer, WriteCallback callback) { void Connection::offer(size_t& packets) { Expects(packets); - printf(" %s got offered [%u] packets. Usable window is %u.\n", + debug(" %s got offered [%u] packets. Usable window is %u.\n", to_string().c_str(), packets, usable_window()); // write until we either cant send more (window closes or no more in queue), @@ -136,7 +136,7 @@ void Connection::offer(size_t& packets) { // advance the buffer buf.advance(written); - printf(" Wrote %u bytes (%u remaining) with [%u] packets left and a usable window of %u.\n", + debug2(" Wrote %u bytes (%u remaining) with [%u] packets left and a usable window of %u.\n", written, buf.remaining, packets, usable_window()); transmit(packet); @@ -157,7 +157,7 @@ void Connection::offer(size_t& packets) { size_t Connection::send(const char* buffer, size_t remaining, size_t& packets_avail) { size_t bytes_written = 0; - printf(" Trying to send %u bytes. Starting with uw=%u packets=%u\n", + debug(" Trying to send %u bytes. Starting with uw=%u packets=%u\n", remaining, usable_window(), packets_avail); std::vector packets; @@ -193,7 +193,7 @@ size_t Connection::send(const char* buffer, size_t remaining, size_t& packets_av // transmit first packet transmit(packets.front());*/ - printf(" Sent %u bytes. Finished with uw=%u packets=%u\n", + debug(" Sent %u bytes. Finished with uw=%u packets=%u\n", bytes_written, usable_window(), packets_avail); return bytes_written; @@ -245,7 +245,7 @@ void Connection::limited_tx() { auto packet = create_outgoing_packet(); - printf(" UW: %u CW: %u, FS: %u\n", usable_window(), cb.cwnd, flight_size()); + debug(" UW: %u CW: %u, FS: %u\n", usable_window(), cb.cwnd, flight_size()); auto& buf = writeq.front().first; auto written = fill_packet(packet, (char*)buf.pos(), std::min(buf.remaining, (uint32_t)SMSS())); @@ -365,7 +365,6 @@ TCP::Packet_ptr Connection::create_outgoing_packet() { } void Connection::transmit(TCP::Packet_ptr packet) { - debug(" Transmitting: %s \n", packet->to_string().c_str()); if(!rttm.active) { //printf(" Starting RTT measurement.\n"); rttm.start(); @@ -373,7 +372,7 @@ void Connection::transmit(TCP::Packet_ptr packet) { //if(packet->seq() + packet->data_length() != cb.SND.NXT) //printf(" rseq=%u rack=%u\n", // packet->seq() - cb.ISS, packet->ack() - cb.IRS); - printf(" TX %s\n", packet->to_string().c_str()); + debug2(" TX %s\n", packet->to_string().c_str()); host_.transmit(packet); if(packet->has_data()) @@ -406,16 +405,6 @@ void Connection::send_much() { // uw, usable_window(), cb.cwnd, flight_size(), bytes_written); } -/*size_t Connection::send_one() { - - -} - -size_t Connection::send(const char* data, size_t n, size_t& packets) { - -} -*/ - bool Connection::handle_ack(TCP::Packet_ptr in) { // dup ack /* @@ -446,7 +435,7 @@ bool Connection::handle_ack(TCP::Packet_ptr in) { acks_rcvd_++; - printf(" New ACK#%u: %u FS: %u %s\n", acks_rcvd_, + debug2(" New ACK#%u: %u FS: %u %s\n", acks_rcvd_, in->ack() - cb.ISS, flight_size(), fast_recovery ? "[RECOVERY]" : ""); // [RFC 6582] p. 8 @@ -478,7 +467,7 @@ bool Connection::handle_ack(TCP::Packet_ptr in) { // slow start if(cb.slow_start()) { reno_increase_cwnd(bytes_acked); - printf(" Slow start. cwnd=%u uw=%u\n", + debug2(" Slow start. cwnd=%u uw=%u\n", cb.cwnd, usable_window()); } @@ -486,7 +475,7 @@ bool Connection::handle_ack(TCP::Packet_ptr in) { else { // increase cwnd once per RTT cb.cwnd += std::max(SMSS()*SMSS()/cb.cwnd, (uint32_t)1); - printf(" Congestion avoidance. cwnd=%u uw=%u\n", + debug2(" Congestion avoidance. cwnd=%u uw=%u\n", cb.cwnd, usable_window()); } // < congestion avoidance @@ -506,7 +495,7 @@ bool Connection::handle_ack(TCP::Packet_ptr in) { //printf(" In Recovery\n"); // partial ack if(!reno_full_ack(in->ack())) { - printf(" Partial ACK\n"); + debug(" Partial ACK\n"); reno_deflate_cwnd(bytes_acked); //printf(" Recovery - Partial ACK\n"); retransmit(); @@ -520,10 +509,10 @@ bool Connection::handle_ack(TCP::Packet_ptr in) { // send one segment if possible if(can_send()) { - printf(" Sending one packet during recovery.\n"); + debug(" Sending one packet during recovery.\n"); limited_tx(); } else { - printf(" Can't send during recovery - usable window is closed.\n"); + debug(" Can't send during recovery - usable window is closed.\n"); } if(in->has_data() or in->isset(FIN)) @@ -532,7 +521,7 @@ bool Connection::handle_ack(TCP::Packet_ptr in) { // full ack else { - printf(" Full ACK.\n"); + debug(" Full ACK.\n"); dup_acks_ = 0; finish_fast_recovery(); } // < full ack @@ -554,7 +543,7 @@ bool Connection::handle_ack(TCP::Packet_ptr in) { What to do when received ACK is a duplicate. */ void Connection::on_dup_ack() { - printf(" ack=%u i=%u\n", cb.SND.UNA - cb.ISS, dup_acks_); + debug2(" rack=%u i=%u\n", cb.SND.UNA - cb.ISS, dup_acks_); // if less than 3 dup acks if(dup_acks_ < 3) { @@ -568,13 +557,13 @@ void Connection::on_dup_ack() { // 3 dup acks else if(dup_acks_ == 3) { - printf(" Dup ACK == 3 - %u\n", cb.SND.UNA); + debug(" Dup ACK == 3 - %u\n", cb.SND.UNA); if(cb.SND.UNA - 1 > cb.recover or ( congestion_window() > SMSS() and (highest_ack_ - prev_highest_ack_ <= 4*SMSS()) )) { cb.recover = cb.SND.NXT; - printf(" Enter Recovery - Flight Size: %u\n", flight_size()); + debug(" Enter Recovery - Flight Size: %u\n", flight_size()); fast_retransmit(); } } @@ -633,7 +622,7 @@ void Connection::retransmit() { auto packet = rtx_q.front(); packet->clear_flag(PSH); //printf(" rseq=%u \n", packet->seq() - cb.ISS); - printf(" RT %s\n", packet->to_string().c_str()); + debug(" RT %s\n", packet->to_string().c_str()); Ensures(packet->tail() == nullptr); Ensures(packet->last_in_chain() == nullptr); host_.transmit(packet); @@ -655,7 +644,7 @@ void Connection::rtx_start() { [this, i, rto] { rtx_timer.active = false; - printf(" %i Timed out (%f). rt_q: %u, i: %u rt_i: %u\n", + debug(" %i Timed out (%f). rt_q: %u, i: %u rt_i: %u\n", local_port_, rto, rtx_q.size(), i, rtx_timer.i); rtx_timeout(); }); diff --git a/test/tcp/service.cpp b/test/tcp/service.cpp index 2ee4671769..d62f96a3d8 100644 --- a/test/tcp/service.cpp +++ b/test/tcp/service.cpp @@ -230,13 +230,6 @@ void Service::start() TEST: Send and receive huge string. */ tcp.bind(TEST3).onConnect([](Connection_ptr conn) { - conn->onPacketDropped([](TCP::Packet_ptr, std::string reason) { - //printf("Dropped: %s\n", reason.c_str()); - }); - conn->onPacketReceived([](Connection_ptr, TCP::Packet_ptr packet) { - //if(packet->has_data()) - // printf("Received: %s\n", packet->to_string().c_str()); - }); INFO("TEST", "HUGE string (%u)", huge.size()); auto temp = std::make_shared(huge.size()); conn->read(huge.size(), [temp, conn](buffer_t buffer, size_t n) { diff --git a/test/tcp/test.py b/test/tcp/test.py index 6afa66a636..2dad4b670e 100755 --- a/test/tcp/test.py +++ b/test/tcp/test.py @@ -16,7 +16,7 @@ def connect(port): try: while True: data = sock.recv(1024) - print >>sys.stderr, '%s' % data + #print >>sys.stderr, '%s' % data if data: sock.sendall(data); else: From 01b169ecebebbee3ba4a588293fb17c47fe10707 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Thu, 28 Apr 2016 13:23:25 +0200 Subject: [PATCH 234/311] fs: Add sync_read(blk, cnt) --- api/fs/filesystem.hpp | 16 +++++----- api/fs/memdisk.hpp | 9 ++++-- api/hw/disk.hpp | 12 ++++---- api/hw/disk_device.hpp | 3 +- api/hw/ide.hpp | 3 +- api/virtio/block.hpp | 20 +++++++----- src/debug/test_service.cpp | 8 ++--- src/fs/fat_sync.cpp | 63 ++++++++++---------------------------- src/fs/memdisk.cpp | 45 ++++++++++----------------- src/hw/ide.cpp | 8 ++++- src/virtio/block.cpp | 8 +---- 11 files changed, 82 insertions(+), 113 deletions(-) diff --git a/api/fs/filesystem.hpp b/api/fs/filesystem.hpp index 14898b7ce9..a519b41e6d 100644 --- a/api/fs/filesystem.hpp +++ b/api/fs/filesystem.hpp @@ -101,14 +101,6 @@ namespace fs { timestamp {0} {} - Enttype ftype; - std::string fname; - uint64_t block; - uint64_t parent; //< Parent's block# - uint64_t size; - uint32_t attrib; - int64_t timestamp; - Enttype type() const noexcept { return ftype; } @@ -143,6 +135,14 @@ namespace fs { return "Unknown type"; } //< switch (type) } + + Enttype ftype; + std::string fname; + uint64_t block; + uint64_t parent; //< Parent's block# + uint64_t size; + uint32_t attrib; + int64_t timestamp; }; //< struct Dirent /** Mount this filesystem with LBA at @base_sector */ diff --git a/api/fs/memdisk.hpp b/api/fs/memdisk.hpp index 864cf9e095..f2e84244ea 100644 --- a/api/fs/memdisk.hpp +++ b/api/fs/memdisk.hpp @@ -41,12 +41,17 @@ namespace fs { { return SECTOR_SIZE; } virtual void - read(block_t blk, on_read_func reader) override; + read(block_t blk, on_read_func reader) override { + reader( read_sync(blk) ); + } virtual void - read(block_t start, block_t cnt, on_read_func reader) override; + read(block_t blk, size_t cnt, on_read_func reader) override { + reader( read_sync(blk, cnt) ); + } virtual buffer_t read_sync(block_t blk) override; + virtual buffer_t read_sync(block_t blk, size_t cnt) override; private: const char* const image_start_; diff --git a/api/hw/disk.hpp b/api/hw/disk.hpp index 548fc8ca94..8583ba7869 100644 --- a/api/hw/disk.hpp +++ b/api/hw/disk.hpp @@ -37,20 +37,20 @@ namespace hw { } virtual void - read(block_t blk, on_read_func del) override - { + read(block_t blk, on_read_func del) override { driver.read(blk, del); } virtual void - read(block_t blk, block_t count, on_read_func del) override - { + read(block_t blk, size_t count, on_read_func del) override { driver.read(blk, count, del); } - virtual buffer_t read_sync(block_t blk) override - { + virtual buffer_t read_sync(block_t blk) override { return driver.read_sync(blk); } + virtual buffer_t read_sync(block_t blk, size_t cnt) override { + return driver.read_sync(blk, cnt); + } virtual block_t size() const noexcept override { diff --git a/api/hw/disk_device.hpp b/api/hw/disk_device.hpp index e790e8c8b7..a4a7472a07 100644 --- a/api/hw/disk_device.hpp +++ b/api/hw/disk_device.hpp @@ -51,10 +51,11 @@ namespace hw * error("Device failed to read sector"); **/ virtual void read(block_t blk, on_read_func func) = 0; - virtual void read(block_t blk, block_t count, on_read_func) = 0; + virtual void read(block_t blk, size_t count, on_read_func) = 0; /** read synchronously the block @blk */ virtual buffer_t read_sync(block_t blk) = 0; + virtual buffer_t read_sync(block_t blk, size_t count) = 0; /** Default destructor */ virtual ~IDiskDevice() noexcept = default; diff --git a/api/hw/ide.hpp b/api/hw/ide.hpp index 7c78e298d1..03610f88c1 100644 --- a/api/hw/ide.hpp +++ b/api/hw/ide.hpp @@ -51,10 +51,11 @@ namespace hw { { return 512; } virtual void read(block_t blk, on_read_func reader) override; - virtual void read(block_t blk, block_t count, on_read_func reader) override; + virtual void read(block_t blk, size_t cnt, on_read_func cb) override; /** read synchronously from IDE disk */ virtual buffer_t read_sync(block_t blk) override; + virtual buffer_t read_sync(block_t blk, size_t cnt) override; virtual block_t size() const noexcept override { return _nb_blk; } diff --git a/api/virtio/block.hpp b/api/virtio/block.hpp index 7a08d53405..1f5d7f227a 100644 --- a/api/virtio/block.hpp +++ b/api/virtio/block.hpp @@ -32,25 +32,29 @@ class VirtioBlk : public Virtio, public hw::IDiskDevice static constexpr size_t SECTOR_SIZE = 512; /** Human readable name. */ - virtual const char* name() const noexcept override - { + virtual const char* name() const noexcept override { return "VirtioBlk"; } // returns the optimal block size for this device - virtual block_t block_size() const noexcept override - { + virtual block_t block_size() const noexcept override { return SECTOR_SIZE; // some multiple of sector size } + // read @blk from disk, call func with buffer when done virtual void read(block_t blk, on_read_func func) override; // read @blk + @cnt from disk, call func with buffer when done - virtual void read(block_t blk, block_t cnt, on_read_func cb) override; + virtual void read(block_t blk, size_t cnt, on_read_func cb) override; - virtual buffer_t read_sync(block_t blk) override; + // unsupported sync reads + virtual buffer_t read_sync(block_t) override { + return buffer_t(); + } + virtual buffer_t read_sync(block_t, size_t) override { + return buffer_t(); + } - virtual block_t size() const noexcept override - { + virtual block_t size() const noexcept override { return config.capacity; } diff --git a/src/debug/test_service.cpp b/src/debug/test_service.cpp index 28d632c938..d6206cf0d3 100644 --- a/src/debug/test_service.cpp +++ b/src/debug/test_service.cpp @@ -30,10 +30,10 @@ void Service::start() hw::Nic& eth0 = hw::Dev::eth<0,VirtioNet>(); inet = std::make_unique >(eth0); inet->network_config( - {{ 10,0,0,42 }}, // IP - {{ 255,255,255,0 }}, // Netmask - {{ 10,0,0,1 }}, // Gateway - {{ 8,8,8,8 }} ); // DNS + { 10,0,0,42 }, // IP + { 255,255,255,0 }, // Netmask + { 10,0,0,1 }, // Gateway + { 8,8,8,8 } ); // DNS /* auto& tcp = inet->tcp(); diff --git a/src/fs/fat_sync.cpp b/src/fs/fat_sync.cpp index 5efc2bb2ec..e0dd51c87f 100644 --- a/src/fs/fat_sync.cpp +++ b/src/fs/fat_sync.cpp @@ -12,6 +12,11 @@ #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) +inline size_t roundup(size_t n, size_t multiple) +{ + return ((n + multiple - 1) / multiple) * multiple; +} + namespace fs { typedef FileSystem::Buffer Buffer; @@ -20,52 +25,19 @@ namespace fs { // cluster -> sector + position -> sector uint32_t sector = this->cl_to_sector(ent.block) + pos / this->sector_size; + uint32_t nsect = sector - roundup(pos + n, sector_size) / sector_size; // the resulting buffer uint8_t* result = new uint8_t[n]; - // in all cases, read the first sector - buffer_t data = device.read_sync(sector); - + // read @nsect sectors ahead + buffer_t data = device.read_sync(sector, nsect); + // where to start copying from the device result uint32_t internal_ofs = pos % device.block_size(); - // keep track of total bytes - uint64_t total = n; - // calculate bytes to read before moving on to next sector - uint32_t rest = device.block_size() - internal_ofs; - - // if what we want to read is larger than the rest, exit early - if (rest > n) - { - memcpy(result, data.get() + internal_ofs, n); - - return Buffer(no_error, buffer_t(result), n); - } - // otherwise, read to the sector border - uint8_t* ptr = result; - memcpy(ptr, data.get() + internal_ofs, rest); - ptr += rest; - n -= rest; - sector += 1; - - // copy entire sectors - while (n > device.block_size()) - { - data = device.read_sync(sector); - - memcpy(ptr, data.get(), device.block_size()); - ptr += device.block_size(); - n -= device.block_size(); - sector += 1; - } - - // copy remainder - if (likely(n > 0)) - { - data = device.read_sync(sector); - memcpy(ptr, data.get(), n); - } + // copy data to result buffer + memcpy(result, data.get() + internal_ofs, n); - return Buffer(no_error, buffer_t(result), total); + return Buffer(no_error, buffer_t(result), n); } Buffer FAT::readFile(const std::string& strpath) @@ -89,13 +61,10 @@ namespace fs // find the matching filename in directory for (auto& e : *dirents) - { - if (unlikely(e.name() == filename)) - { - // read this file - return read(e, 0, e.size); - } - } + if (unlikely(e.name() == filename)) { + // read this file + return read(e, 0, e.size); + } // entry not found return Buffer(true, buffer_t(), 0); } // readFile() diff --git a/src/fs/memdisk.cpp b/src/fs/memdisk.cpp index b4b5ac679f..b620da2156 100644 --- a/src/fs/memdisk.cpp +++ b/src/fs/memdisk.cpp @@ -36,47 +36,36 @@ namespace fs { image_end_ { &_DISK_END_ } {} - void MemDisk::read(block_t blk, on_read_func reader) { - auto sector_loc = image_start_ + (blk * block_size()); + MemDisk::buffer_t MemDisk::read_sync(block_t blk) { + auto sector_loc = image_start_ + blk * block_size(); // Disallow reading memory past disk image - if (unlikely(sector_loc >= image_end_)) { - reader(buffer_t{}); return; - } + if (unlikely(sector_loc >= image_end_)) + return buffer_t{}; auto buffer = new uint8_t[block_size()]; - Ensures( memcpy(buffer, sector_loc, block_size()) == buffer ); - - reader( buffer_t{buffer, std::default_delete()} ); - } - - void MemDisk::read(block_t blk, block_t count, on_read_func reader) { - auto start_loc = image_start_ + (blk * block_size()); - auto end_loc = start_loc + (count * block_size()); - // Disallow reading memory past disk image - if (unlikely(end_loc >= image_end_)) { - reader(buffer_t{}); return; - } + memcpy(buffer, sector_loc, block_size()); - auto buffer = new uint8_t[count * block_size()]; - Ensures( memcpy(buffer, start_loc, count * block_size()) == buffer ); - - reader( buffer_t{buffer, std::default_delete()} ); + return buffer_t{buffer, std::default_delete()}; } - - MemDisk::buffer_t MemDisk::read_sync(block_t blk) { - auto sector_loc = image_start_ + (blk * block_size()); + + MemDisk::buffer_t MemDisk::read_sync(block_t blk, size_t cnt) { + auto start_loc = image_start_ + blk * block_size(); + auto end_loc = start_loc + cnt * block_size(); + // Disallow reading memory past disk image - if (unlikely(sector_loc >= image_end_)) + if (unlikely(end_loc >= image_end_)) return buffer_t{}; - auto buffer = new uint8_t[block_size()]; - Ensures( memcpy(buffer, sector_loc, block_size()) == buffer ); + auto buffer = new uint8_t[cnt * block_size()]; + memcpy(buffer, start_loc, cnt * block_size()); return buffer_t{buffer, std::default_delete()}; } MemDisk::block_t MemDisk::size() const noexcept { - return (image_end_ - image_start_) / SECTOR_SIZE; + // we are NOT going to round up to "support" unevenly sized + // disks that are not created as multiples of sectors + return (image_end_ - image_start_) / block_size(); } } //< namespace fs diff --git a/src/hw/ide.cpp b/src/hw/ide.cpp index 1da37c1ff2..3bbfcc54f5 100644 --- a/src/hw/ide.cpp +++ b/src/hw/ide.cpp @@ -137,7 +137,7 @@ namespace hw { _nb_irqs = 1; } - void IDE::read(block_t blk, block_t count, on_read_func callback) + void IDE::read(block_t blk, size_t count, on_read_func callback) { if (blk + count >= _nb_blk) { // avoid reading past the disk boundaries @@ -180,6 +180,12 @@ namespace hw { // return a shared_ptr wrapper for the buffer return buffer_t(buffer, std::default_delete()); } + IDE::buffer_t IDE::read_sync(block_t blk, size_t cnt) { + (void) blk; + (void) cnt; + // not yet implemented + return buffer_t(); + } void IDE::wait_status_busy() noexcept { uint8_t ret; diff --git a/src/virtio/block.cpp b/src/virtio/block.cpp index 3fc9a470ee..9de14f193e 100644 --- a/src/virtio/block.cpp +++ b/src/virtio/block.cpp @@ -207,7 +207,7 @@ void VirtioBlk::read (block_t blk, on_read_func func) { jobs.push_back(vbr); } } -void VirtioBlk::read (block_t blk, block_t cnt, on_read_func func) { +void VirtioBlk::read (block_t blk, size_t cnt, on_read_func func) { bool shipped = false; // create big buffer for collecting all the disk data @@ -257,12 +257,6 @@ void VirtioBlk::read (block_t blk, block_t cnt, on_read_func func) { if (shipped) req.kick(); } -VirtioBlk::buffer_t VirtioBlk::read_sync(block_t) -{ - // this driver won't support sync read - return buffer_t(); -} - VirtioBlk::request_t::request_t(uint64_t blk, bool part, on_read_func cb) { hdr.type = VIRTIO_BLK_T_IN; From ff4567fbb0c7ddb77fd397f8dc688460105e4dd9 Mon Sep 17 00:00:00 2001 From: Martin Nordsletten Date: Thu, 28 Apr 2016 13:49:15 +0200 Subject: [PATCH 235/311] Updated TCP test to work with jenkins Changed the test.py file to now use vmrunner, and modified the service.cpp to initialize the tests. --- test/tcp/service.cpp | 4 +- test/tcp/test.py | 103 ++++++++++++++++++++++++------------------- 2 files changed, 60 insertions(+), 47 deletions(-) diff --git a/test/tcp/service.cpp b/test/tcp/service.cpp index d62f96a3d8..843457b143 100644 --- a/test/tcp/service.cpp +++ b/test/tcp/service.cpp @@ -65,7 +65,7 @@ void FINISH_TEST() { CHECK(inet->buffers_available() == buffers_available, "inet->buffers_available() == buffers_available"); INFO("Buffers available", "%u", inet->buffers_available()); - printf("# TEST DONE #\n"); + printf("# TEST SUCCESS #\n"); }); } @@ -284,5 +284,5 @@ void Service::start() hw::PIT::instance().onTimeout(5s, [] { FINISH_TEST(); }); }); - +printf ("IncludeOS TCP test\n"); } diff --git a/test/tcp/test.py b/test/tcp/test.py index 2dad4b670e..ea185b60ee 100755 --- a/test/tcp/test.py +++ b/test/tcp/test.py @@ -2,61 +2,74 @@ import socket import sys +sys.path.insert(0,"..") + +import vmrunner # Usage: python test.py $GUEST_IP $HOST_IP GUEST = '10.0.0.42' if (len(sys.argv) < 2) else sys.argv[1] HOST = '10.0.0.1' if (len(sys.argv) < 3) else sys.argv[2] -def connect(port): - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - server_address = (GUEST, port) - print >>sys.stderr, 'connecting to %s port %s' % server_address - sock.connect(server_address) +def TCP_test(): + def connect(port): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + server_address = (GUEST, port) + print >>sys.stderr, 'connecting to %s port %s' % server_address + sock.connect(server_address) - try: - while True: - data = sock.recv(1024) - #print >>sys.stderr, '%s' % data - if data: - sock.sendall(data); - else: - break - finally: - print >>sys.stderr, 'closing socket' - sock.close() - return - -connect(8081) -connect(8082) -connect(8083) -connect(8084) - -def listen(port): - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - server_address = (HOST, port) - print >>sys.stderr, 'starting up on %s port %s' % server_address - sock.bind(server_address) - sock.listen(1) - - while True: - connection, client_address = sock.accept() try: - print >>sys.stderr, 'connection from', client_address while True: - data = connection.recv(1024) + data = sock.recv(1024) + #print >>sys.stderr, '%s' % data if data: - print >>sys.stderr, 'received data, sending data back to the client' - connection.sendall(data) - print >>sys.stderr, 'close connection to client' - connection.close() + sock.sendall(data); else: - print >>sys.stderr, 'no more data from', client_address break - finally: - connection.close() - break - sock.close() - return + print >>sys.stderr, 'closing socket' + sock.close() + return + + connect(8081) + connect(8082) + connect(8083) + connect(8084) + + def listen(port): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + server_address = (HOST, port) + print >>sys.stderr, 'starting up on %s port %s' % server_address + sock.bind(server_address) + sock.listen(1) + + while True: + connection, client_address = sock.accept() + try: + print >>sys.stderr, 'connection from', client_address + while True: + data = connection.recv(1024) + if data: + print >>sys.stderr, 'received data, sending data back to the client' + connection.sendall(data) + print >>sys.stderr, 'close connection to client' + connection.close() + else: + print >>sys.stderr, 'no more data from', client_address + break + + finally: + connection.close() + break + sock.close() + return + + listen(8085) + +# Get an auto-created VM from the vmrunner +vm = vmrunner.vms[0] + +# Add custom event-handler +vm.on_output("IncludeOS TCP test", TCP_test) -listen(8085) +# Boot the VM, taking a timeout as parameter +vm.boot(40) \ No newline at end of file From f3b8e64ca3c17bdcb01516659a43a7cbbd68afce Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Thu, 28 Apr 2016 13:58:56 +0200 Subject: [PATCH 236/311] fs: FAT read() now uses read(blk, cnt) --- src/fs/fat_async.cpp | 292 ++++++++++++++++++------------------------- src/fs/fat_sync.cpp | 5 +- 2 files changed, 125 insertions(+), 172 deletions(-) diff --git a/src/fs/fat_async.cpp b/src/fs/fat_async.cpp index d8c47858d4..6ccca5c3cb 100644 --- a/src/fs/fat_async.cpp +++ b/src/fs/fat_async.cpp @@ -12,46 +12,46 @@ #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) +inline size_t roundup(size_t n, size_t multiple) +{ + return ((n + multiple - 1) / multiple) * multiple; +} + namespace fs { void FAT::int_ls( - uint32_t sector, - dirvec_t dirents, - on_internal_ls_func callback) + uint32_t sector, + dirvec_t dirents, + on_internal_ls_func callback) { // list contents of meme sector by sector typedef std::function next_func_t; auto next = std::make_shared (); *next = - [this, sector, callback, dirents, next] (uint32_t sector) - { - debug("int_ls: sec=%u\n", sector); - device.read(sector, - [this, sector, callback, dirents, next] (buffer_t data) - { - if (!data) - { - // could not read sector - callback(true, dirents); - return; - } + [this, sector, callback, dirents, next] (uint32_t sector) + { + debug("int_ls: sec=%u\n", sector); + device.read(sector, + [this, sector, callback, dirents, next] (buffer_t data) { + + if (!data) { + // could not read sector + callback(true, dirents); + return; + } // parse entries in sector bool done = int_dirent(sector, data.get(), dirents); if (done) - { - // execute callback - callback(no_error, dirents); - } + // execute callback + callback(no_error, dirents); else - { - // go to next sector - (*next)(sector+1); - } + // go to next sector + (*next)(sector+1); }); // read root dir - }; + }; // start reading sectors asynchronously (*next)(sector); @@ -65,197 +65,149 @@ namespace fs // asynch stack traversal auto next = std::make_shared (); *next = - [this, path, next, callback] (uint32_t cluster) - { - if (path->empty()) - { - // attempt to read directory - uint32_t S = this->cl_to_sector(cluster); - - // result allocated on heap - auto dirents = std::make_shared> (); - - int_ls(S, dirents, - [callback] (error_t error, dirvec_t ents) - { - callback(error, ents); - }); - return; - } - - // retrieve next name - std::string name = path->front(); - path->pop_front(); + [this, path, next, callback] (uint32_t cluster) { + if (path->empty()) { + // attempt to read directory uint32_t S = this->cl_to_sector(cluster); - debug("Current target: %s on cluster %u (sector %u)\n", name.c_str(), cluster, S); - + // result allocated on heap auto dirents = std::make_shared> (); - - // list directory contents + int_ls(S, dirents, - [name, dirents, next, callback] (error_t error, dirvec_t ents) - { - if (unlikely(error)) - { - debug("Could not find: %s\n", name.c_str()); - callback(true, dirents); - return; - } + [callback] (error_t error, dirvec_t ents) { + callback(error, ents); + }); + return; + } + + // retrieve next name + std::string name = path->front(); + path->pop_front(); + + uint32_t S = this->cl_to_sector(cluster); + debug("Current target: %s on cluster %u (sector %u)\n", name.c_str(), cluster, S); + + // result allocated on heap + auto dirents = std::make_shared> (); + + // list directory contents + int_ls(S, dirents, + [name, dirents, next, callback] (error_t err, dirvec_t ents) { + + if (unlikely(err)) { + debug("Could not find: %s\n", name.c_str()); + callback(true, dirents); + return; + } // look for name in directory - for (auto& e : *ents) - { - if (unlikely(e.name() == name)) - { - // go to this directory, unless its the last name - debug("Found match for %s", name.c_str()); - // enter the matching directory - debug("\t\t cluster: %llu\n", e.block); - // only follow directories - if (e.type() == DIR) - (*next)(e.block); - else - callback(true, dirents); - return; - } - } // for (ents) + for (auto& e : *ents) { + if (unlikely(e.name() == name)) { + // go to this directory, unless its the last name + debug("Found match for %s", name.c_str()); + // enter the matching directory + debug("\t\t cluster: %llu\n", e.block); + // only follow directories + if (e.type() == DIR) + (*next)(e.block); + else + callback(true, dirents); + return; + } + } // for (ents) debug("NO MATCH for %s\n", name.c_str()); callback(true, dirents); }); - }; + }; // start by reading root directory (*next)(0); } - void FAT::ls(const std::string& path, on_ls_func on_ls) - { + void FAT::ls(const std::string& path, on_ls_func on_ls) { + // parse this path into a stack of names auto pstk = std::make_shared (path); traverse(pstk, - [on_ls] (error_t error, dirvec_t dirents) - { - on_ls(error, dirents); - }); + [on_ls] (error_t error, dirvec_t dirents) { + on_ls(error, dirents); + }); } void FAT::read(const Dirent& ent, uint64_t pos, uint64_t n, on_read_func callback) { - // cluster -> sector - uint32_t sector = this->cl_to_sector(ent.block); - - // allocate buffer - auto* buffer = new uint8_t[n]; - - // start reading process - typedef std::function next_func_t; - auto next = std::make_shared (); + // cluster -> sector + position + uint32_t sector = this->cl_to_sector(ent.block) + pos / this->sector_size; + uint32_t nsect = sector - roundup(pos + n, sector_size) / sector_size; + uint32_t internal_ofs = pos % device.block_size(); - *next = - [this, sector, buffer, callback, next] (size_t start, size_t n, size_t end) - { - if (unlikely(n == end)) - { - // report back to HQ - debug("DONE start=%lu, current=%lu, total=%lu\n", start, n, end - start); - // create shared buffer - auto buffer_ptr = buffer_t(buffer, std::default_delete()); - // notify caller - callback(no_error, buffer_ptr, end - start); - return; - } + device.read(sector, nsect, + [pos, n, &callback, internal_ofs] (buffer_t data) { - // read the current sector based on position @n - uint32_t current_sector = sector + n / this->sector_size; + if (!data) { + // general I/O error occurred + debug("Failed to read sector %u for read()", sector); + callback(true, buffer_t(), 0); + return; + } - device.read(current_sector, - [this, start, n, end, buffer, &callback, sector, next] (buffer_t data) - { - if (!data) - { - // general I/O error occurred - debug("Failed to read sector %u for read()", sector); - // cleanup - delete[] buffer; - callback(true, buffer_t(), 0); - return; - } - - uint32_t length = n & (sector_size-1); - if (n == start && n > 0) - { - length = sector_size - length; - } - else - { - length = (n + sector_size) < end ? sector_size : (end - n); - } - - // copy over data - memcpy(buffer + n, data.get(), length); - // continue reading next sector - (*next)(start, n + length, end); - }); - }; - - // start! - (*next)(pos, pos, pos + n); + // allocate buffer & copy data + auto* result = new uint8_t[n]; + memcpy(result, data.get() + internal_ofs, n); + + auto buffer = buffer_t(result, std::default_delete()); + callback(no_error, buffer, n); + }); } void FAT::readFile(const std::string& strpath, on_read_func callback) { auto path = std::make_shared (strpath); - if (unlikely(path->empty())) - { - // there is no possible file to read where path is empty - callback(true, nullptr, 0); - return; - } + if (unlikely(path->empty())) { + // there is no possible file to read where path is empty + callback(true, nullptr, 0); + return; + } debug("readFile: %s\n", path->back().c_str()); std::string filename = path->back(); path->pop_back(); traverse(path, - [this, filename, &callback] (error_t error, dirvec_t dirents) - { - if (unlikely(error)) - { - // no path, no file! - callback(error, buffer_t(), 0); - return; - } + [this, filename, &callback] (error_t error, dirvec_t dirents) { + + if (unlikely(error)) { + // no path, no file! + callback(error, buffer_t(), 0); + return; + } - // find the matching filename in directory - for (auto& ent : *dirents) - { - if (unlikely(ent.name() == filename)) - { - // read this file - read(ent, 0, ent.size, callback); - return; - } - } + // find the matching filename in directory + for (auto& ent : *dirents) { + if (unlikely(ent.name() == filename)) { + // read this file + read(ent, 0, ent.size, callback); + return; + } + } - // file not found - callback(true, buffer_t(), 0); - }); + // file not found + callback(true, buffer_t(), 0); + }); } // readFile() void FAT::stat(const std::string& strpath, on_stat_func func) { auto path = std::make_shared (strpath); - if (unlikely(path->empty())) - { - // root doesn't have any stat anyways - // Note: could use ATTR_VOLUME_ID in FAT - func(true, Dirent(INVALID_ENTITY, strpath)); - return; - } + if (unlikely(path->empty())) { + // root doesn't have any stat anyways + // Note: could use ATTR_VOLUME_ID in FAT + func(true, Dirent(INVALID_ENTITY, strpath)); + return; + } debug("stat: %s\n", path->back().c_str()); // extract file we are looking for diff --git a/src/fs/fat_sync.cpp b/src/fs/fat_sync.cpp index e0dd51c87f..a6928ca317 100644 --- a/src/fs/fat_sync.cpp +++ b/src/fs/fat_sync.cpp @@ -23,7 +23,7 @@ namespace fs Buffer FAT::read(const Dirent& ent, uint64_t pos, uint64_t n) { - // cluster -> sector + position -> sector + // cluster -> sector + position uint32_t sector = this->cl_to_sector(ent.block) + pos / this->sector_size; uint32_t nsect = sector - roundup(pos + n, sector_size) / sector_size; @@ -36,8 +36,9 @@ namespace fs uint32_t internal_ofs = pos % device.block_size(); // copy data to result buffer memcpy(result, data.get() + internal_ofs, n); + auto buffer = buffer_t(result, std::default_delete()); - return Buffer(no_error, buffer_t(result), n); + return Buffer(no_error, buffer, n); } Buffer FAT::readFile(const std::string& strpath) From 8bcab7623f2ff365ec4936f7214abe1e158ca3dc Mon Sep 17 00:00:00 2001 From: Martin Nordsletten Date: Thu, 28 Apr 2016 14:10:52 +0200 Subject: [PATCH 237/311] Added vm. json to tcp test --- test/tcp/vm.json | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 test/tcp/vm.json diff --git a/test/tcp/vm.json b/test/tcp/vm.json new file mode 100644 index 0000000000..69fc7d46a9 --- /dev/null +++ b/test/tcp/vm.json @@ -0,0 +1,6 @@ +{ + "image" : "test_tcp.img", + "net" : [{"type" : "virtio", "mac" : "c0:01:0a:00:00:2a"}], + "cpu" : "host", + "mem" : 256 +} \ No newline at end of file From c8d65d6e0e2fe1a53a84e19f787324a2b10385b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Thu, 28 Apr 2016 14:24:47 +0200 Subject: [PATCH 238/311] tcp: keep track of used ports (wip) --- api/net/tcp.hpp | 36 +++++++++++------------------------- src/net/tcp.cpp | 25 +++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 27 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index 0318ed015b..b0a6cfe50e 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -27,6 +27,7 @@ #include // ostringstream #include // timer duration #include // enable_shared_from_this +#include inline unsigned round_up(unsigned n, unsigned div) { assert(n); @@ -1123,12 +1124,6 @@ namespace net { size_t i = 0; } rtx_timer; - - /* - Keep track of duplicate ACK - */ - size_t DUP_ACK = 0; - /* Bytes queued for transmission. */ @@ -1164,7 +1159,7 @@ namespace net { bool active = false; - RTTM() : t(OS::uptime()), RTO(1.0), active(false) {} + RTTM() : t(OS::uptime()), SRTT(1.0), RTTVAR(1.0), RTO(1.0), active(false) {} void start() { t = OS::uptime(); @@ -1452,9 +1447,6 @@ namespace net { Seq highest_ack_ = 0; size_t acks_rcvd_ = 0; - Seq RENO_PREV_HIGHEST_ACK = 0; - Seq RENO_HIGHEST_ACK = 0; - inline void setup_congestion_control() { reno_init(); } @@ -1519,25 +1511,10 @@ namespace net { printf(" Finished Fast Recovery - Cwnd: %u\n", cb.cwnd); } - inline bool reno_should_recover(Seq ACK) { - return (ACK - 1 > cb.recover) or reno_heuristic_segment_loss_detected(); - } - - inline bool reno_heuristic_segment_loss_detected() { - return (congestion_window() > SMSS()) - and (RENO_HIGHEST_ACK - RENO_PREV_HIGHEST_ACK <= 4*SMSS()); - } - inline bool reno_full_ack(Seq ACK) { return ACK - 1 > cb.recover; } - void reno_update_heuristic_ack(Seq ACK) { - RENO_PREV_HIGHEST_ACK = RENO_HIGHEST_ACK; - RENO_HIGHEST_ACK = ACK; - } - - /* Generate a new ISS. */ @@ -1760,6 +1737,10 @@ namespace net { std::deque writeq; + using PortMap = std::bitset; + //std::unique_ptr used_ports; + PortMap used_ports; + /* Settings */ @@ -1782,6 +1763,11 @@ namespace net { */ TCP::Port free_port(); + /* + Check if the port is in use either among "listeners" or "connections" + */ + bool port_in_use(const TCP::Port) const; + /* Packet is dropped. */ diff --git a/src/net/tcp.cpp b/src/net/tcp.cpp index 1a7884b59a..dcc2b3b007 100644 --- a/src/net/tcp.cpp +++ b/src/net/tcp.cpp @@ -21,13 +21,14 @@ using namespace std; using namespace net; - + TCP::TCP(IPStack& inet) : inet_(inet), listeners_(), connections_(), writeq(), + used_ports(), MAX_SEG_LIFETIME(30s) { inet.on_transmit_queue_available(transmit_avail_delg::from(this)); @@ -85,6 +86,7 @@ TCP::Seq TCP::generate_iss() { TODO: Check if there is any ports free. */ TCP::Port TCP::free_port() { + //assert(!used_ports.all()); if(++current_ephemeral_ == 0) current_ephemeral_ = 1025; // Avoid giving a port that is bound to a service. @@ -92,8 +94,26 @@ TCP::Port TCP::free_port() { current_ephemeral_++; return current_ephemeral_; + + /*TCP::Port port; + do { + port = current_ephemeral_ + rand() % (65535 - current_ephemeral_); + } while(port_in_use(port)); + + return port;*/ } +bool TCP::port_in_use(const TCP::Port port) const { + if(listeners_.find(port) != listeners_.end()) + return true; + + for(auto it : connections_) { + if(it.first.first == port) + return true; + } + return false; +} + uint16_t TCP::checksum(TCP::Packet_ptr packet) { // TCP header @@ -211,7 +231,8 @@ size_t TCP::send(Connection_ptr conn, const char* buffer, size_t n) { written += conn->send(buffer, n, packets); } // if connection still can send (means there wasn't enough packets) - if(conn->can_send()) { + // only requeue if not already queued + if(conn->can_send() and !conn->is_queued()) { debug2(" Conn queued.\n"); writeq.push_back(conn); conn->set_queued(true); From c9a27113fca6c15a902182ed9d281ed3d4890967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Thu, 28 Apr 2016 14:25:28 +0200 Subject: [PATCH 239/311] membitmap: chunks are now register size --- api/utility/membitmap.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/utility/membitmap.hpp b/api/utility/membitmap.hpp index 4205818f9a..8bbe6b5030 100644 --- a/api/utility/membitmap.hpp +++ b/api/utility/membitmap.hpp @@ -30,8 +30,8 @@ namespace fs class MemBitmap { public: - typedef uint64_t word; - static const word WORD_MAX = UINT64_MAX; + typedef uint32_t word; + static const word WORD_MAX = UINT32_MAX; typedef uint32_t index_t; static const int CHUNK_SIZE = sizeof(word) * 8; From 77810ffc7045be69f3ebb2f075cd8df31556a4af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Thu, 28 Apr 2016 14:28:00 +0200 Subject: [PATCH 240/311] crash when adding addtional bitset --- api/net/tcp.hpp | 1 + src/net/tcp.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index b0a6cfe50e..75891d8662 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -1740,6 +1740,7 @@ namespace net { using PortMap = std::bitset; //std::unique_ptr used_ports; PortMap used_ports; + PortMap available_ports; /* Settings diff --git a/src/net/tcp.cpp b/src/net/tcp.cpp index dcc2b3b007..830dc17ed9 100644 --- a/src/net/tcp.cpp +++ b/src/net/tcp.cpp @@ -29,6 +29,7 @@ TCP::TCP(IPStack& inet) : connections_(), writeq(), used_ports(), + available_ports(), MAX_SEG_LIFETIME(30s) { inet.on_transmit_queue_available(transmit_avail_delg::from(this)); From 10d80a64ac91a5736b14ec1a8a24d6681b356c99 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Fri, 29 Apr 2016 09:46:22 +0200 Subject: [PATCH 241/311] fs: Fix FAT read calculation --- src/fs/fat_async.cpp | 17 +++++++++++------ src/fs/fat_sync.cpp | 7 +++---- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/fs/fat_async.cpp b/src/fs/fat_async.cpp index 6ccca5c3cb..2b7fe00ee1 100644 --- a/src/fs/fat_async.cpp +++ b/src/fs/fat_async.cpp @@ -7,7 +7,6 @@ #include #include -#include #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) @@ -139,13 +138,19 @@ namespace fs void FAT::read(const Dirent& ent, uint64_t pos, uint64_t n, on_read_func callback) { - // cluster -> sector + position - uint32_t sector = this->cl_to_sector(ent.block) + pos / this->sector_size; - uint32_t nsect = sector - roundup(pos + n, sector_size) / sector_size; + // when n=0 roundup() will return an invalid value + if (n == 0) { + callback(true, buffer_t(), 0); + return; + } + // calculate start and length in sectors + uint32_t sector = pos / this->sector_size; + uint32_t nsect = roundup(pos + n, sector_size) / sector_size - sector; uint32_t internal_ofs = pos % device.block_size(); - device.read(sector, nsect, - [pos, n, &callback, internal_ofs] (buffer_t data) { + // cluster -> sector + position + device.read(this->cl_to_sector(ent.block) + sector, nsect, + [pos, n, callback, internal_ofs] (buffer_t data) { if (!data) { // general I/O error occurred diff --git a/src/fs/fat_sync.cpp b/src/fs/fat_sync.cpp index a6928ca317..14dd3a601d 100644 --- a/src/fs/fat_sync.cpp +++ b/src/fs/fat_sync.cpp @@ -7,7 +7,6 @@ #include #include -#include #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) @@ -24,14 +23,14 @@ namespace fs Buffer FAT::read(const Dirent& ent, uint64_t pos, uint64_t n) { // cluster -> sector + position - uint32_t sector = this->cl_to_sector(ent.block) + pos / this->sector_size; - uint32_t nsect = sector - roundup(pos + n, sector_size) / sector_size; + uint32_t sector = pos / this->sector_size; + uint32_t nsect = roundup(pos + n, sector_size) / sector_size - sector; // the resulting buffer uint8_t* result = new uint8_t[n]; // read @nsect sectors ahead - buffer_t data = device.read_sync(sector, nsect); + buffer_t data = device.read_sync(this->cl_to_sector(ent.block) + sector, nsect); // where to start copying from the device result uint32_t internal_ofs = pos % device.block_size(); // copy data to result buffer From 1aeb1ffd09be13c6800636a0ea519cc8688b20fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Fri, 29 Apr 2016 12:27:47 +0200 Subject: [PATCH 242/311] build: updated osx script from clang3.6 => 3.8 --- etc/install_osx.sh | 45 ++++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/etc/install_osx.sh b/etc/install_osx.sh index 606c8ce08e..cb0de43691 100755 --- a/etc/install_osx.sh +++ b/etc/install_osx.sh @@ -2,15 +2,15 @@ # Install the IncludeOS libraries (i.e. IncludeOS_home) from binary bundle # ...as opposed to building them all from scratch, which takes a long time -# # -# OPTIONS: +# +# OPTIONS: # # Location of the IncludeOS repo: # $ export INCLUDEOS_SRC=your/github/cloned/IncludeOS # # Parent directory of where you want the IncludeOS libraries (i.e. IncludeOS_home) -# $ export INCLUDEOS_INSTALL_LOC=parent/folder/for/IncludeOS/libraries i.e. +# $ export INCLUDEOS_INSTALL_LOC=parent/folder/for/IncludeOS/libraries i.e. [[ -z $INCLUDEOS_SRC ]] && export INCLUDEOS_SRC=`pwd` [[ -z $INCLUDEOS_INSTALL_LOC ]] && export INCLUDEOS_INSTALL_LOC=$HOME @@ -22,8 +22,8 @@ echo -e "\n###################################" echo -e "IncludeOS installation for Mac OS X" echo -e "###################################" -echo -e "\n# Prequisites:\n - - homebrew (OSX package manager - https://brew.sh) +echo -e "\n# Prequisites:\n + - homebrew (OSX package manager - https://brew.sh) - \`/usr/local\` directory with write access - \`/usr/local/bin\` added to your PATH - (Recommended) XCode CTL (Command Line Tools)" @@ -33,12 +33,12 @@ echo -e "\n# Prequisites:\n echo -e "\n# Dependencies" ## LLVM ## -echo -e "\nllvm36 (clang/clang++ 3.6) - required for compiling" +echo -e "\nllvm38 (clang/clang++ 3.8) - required for compiling" DEPENDENCY_LLVM=false -BREW_LLVM=llvm36 -BREW_CLANG_CC=/usr/local/bin/clang-3.6 -BREW_CLANG_CPP=/usr/local/bin/clang++-3.6 +BREW_LLVM=llvm38 +BREW_CLANG_CC=/usr/local/bin/clang-3.8 +BREW_CLANG_CPP=/usr/local/bin/clang++-3.8 [ -e $BREW_CLANG_CPP ] && DEPENDENCY_LLVM=true if ($DEPENDENCY_LLVM); then echo -e "> Found"; else echo -e "> Not Found"; fi @@ -47,6 +47,9 @@ function install_llvm { echo -e "\n>>> Installing: llvm" # Check if brew is installed command -v brew >/dev/null 2>&1 || { echo >&2 " Cannot find brew! Visit http://brew.sh/ for how-to install. Aborting."; exit 1; } + # Try to update brew + echo -e "\n> Make sure homebrew is up to date." + brew update # Install llvm echo -e "\n> Install $BREW_LLVM with brew" brew install $BREW_LLVM @@ -75,19 +78,19 @@ function install_binutils { # Create build directory if not exist mkdir -p $INCLUDEOS_BUILD - + # Decide filename (release) BINUTILS_RELEASE=binutils-2.25 filename_binutils=$BINUTILS_RELEASE".tar.gz" # Check if file is downloaded if [ -e $INCLUDEOS_BUILD/$filename_binutils ] - then + then echo -e "\n> $BINUTILS_RELEASE already downloaded." else # Download binutils echo -e "\n> Downloading $BINUTILS_RELEASE." - curl https://ftp.gnu.org/gnu/binutils/$filename_binutils -o $INCLUDEOS_BUILD/$filename_binutils + curl https://ftp.gnu.org/gnu/binutils/$filename_binutils -o $INCLUDEOS_BUILD/$filename_binutils fi ## Unzip @@ -96,7 +99,7 @@ function install_binutils { ## Configure pushd $INCLUDEOS_BUILD/$BINUTILS_RELEASE - + ## Install echo -e "\n> Installing $BINUTILS_RELEASE to $BINUTILS_DIR" ./configure --program-prefix=$LINKER_PREFIX --prefix=$BINUTILS_DIR --enable-multilib --enable-ld=yes --target=i686-elf --disable-werror --enable-silent-rules @@ -133,8 +136,8 @@ function install_nasm { ## WARN ABOUT XCODE CTL ## if ! [[ $(xcode-select -p) ]] -then - echo -e "\nWARNING: Command Line Tools don't seem to be installed, installation MAY not complete. +then + echo -e "\nWARNING: Command Line Tools don't seem to be installed, installation MAY not complete. Install with: xcode-select --install" fi @@ -167,18 +170,18 @@ echo ">>> Updating git-tags " pushd $INCLUDEOS_SRC git fetch --tags tag=`git describe --abbrev=0` -popd +popd filename_tag=`echo $tag | tr . -` filename="IncludeOS_install_"$filename_tag".tar.gz" -# If the tarball exists, use that -if [ -e $filename ] +# If the tarball exists, use that +if [ -e $filename ] then echo -e "\n\n>>> IncludeOS tarball exists - extracting to $INCLUDEOS_INSTALL_LOC" -else +else echo -e "\n\n>>> Downloading IncludeOS release tarball from GitHub" - # Download from GitHub API + # Download from GitHub API if [ "$1" = "-oauthToken" ] then oauthToken=$2 @@ -198,7 +201,7 @@ else else curl -H "Accept: application/octet-stream" -L -o $filename $ASSET_URL fi - + echo -e "\n\n>>> Fetched tarball - extracting to $INCLUDEOS_INSTALL_LOC" fi From 8eca1f88e74b690d06f48b671e1b5df4aab2ac97 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Fri, 29 Apr 2016 12:33:24 +0200 Subject: [PATCH 243/311] fs: Added error object --- api/fs/common.hpp | 33 ++++- api/fs/disk.hpp | 2 - src/fs/disk.cpp | 17 +-- src/fs/ext4.cpp | 26 ++-- src/fs/fat.cpp | 315 +++++++++++++++++++++--------------------- src/fs/fat_async.cpp | 59 ++++---- src/fs/fat_sync.cpp | 74 +++++----- src/fs/filesystem.cpp | 19 ++- 8 files changed, 282 insertions(+), 263 deletions(-) diff --git a/api/fs/common.hpp b/api/fs/common.hpp index 6ef7dc11c3..63a7920a9c 100644 --- a/api/fs/common.hpp +++ b/api/fs/common.hpp @@ -20,13 +20,42 @@ #define FS_COMMON_HPP #include +#include namespace fs { typedef std::shared_ptr buffer_t; - // TODO: transform this into a class with a bool operator - using error_t = bool; + struct error_t + { + enum token_t { + NO_ERR = 0, + E_IO, // general I/O error + E_MNT, + + E_NOENT, + E_NOTDIR, + }; + + error_t(token_t tk, const std::string& rsn) + : token_(tk), reason_(rsn) {} + + // error code to string + std::string to_string() const; + // show explanation for error + std::string reason() const noexcept { + return reason_; + } + + // returns true when it's an error + operator bool () const noexcept { + return token_ != NO_ERR; + } + + private: + token_t token_; + std::string reason_; + }; /** @var no_error: Always returns boolean false when used in expressions */ extern error_t no_error; diff --git a/api/fs/disk.hpp b/api/fs/disk.hpp index 07ae90969e..3c80e62077 100644 --- a/api/fs/disk.hpp +++ b/api/fs/disk.hpp @@ -73,8 +73,6 @@ namespace fs { VBR2, VBR3, VBR4, - - INVALID }; struct Partition { diff --git a/src/fs/disk.cpp b/src/fs/disk.cpp index 850bbac595..28342121e7 100644 --- a/src/fs/disk.cpp +++ b/src/fs/disk.cpp @@ -33,7 +33,7 @@ namespace fs { std::vector parts; if (!data) { - func(true, parts); + func({ error_t::E_IO, "Unable to read MBR"}, parts); return; } @@ -60,7 +60,7 @@ namespace fs { { if (!data) { // TODO: error-case for unable to read MBR - internal_mount(INVALID, func); + func({ error_t::E_IO, "Unable to read MBR"}); return; } @@ -98,7 +98,7 @@ namespace fs { } // no partition was found (TODO: extended partitions) - internal_mount(INVALID, func); + func({ error_t::E_MNT, "No FAT partition auto-detected"}); }); } @@ -110,14 +110,7 @@ namespace fs { void Disk::internal_mount(partition_t part, on_mount_func func) { - if (part == INVALID) - { - // Something bad happened maybe in auto-detect - // Either way, no partition was found - func(true); - return; - } - else if (part == MBR) + if (part == MBR) { // For the MBR case, all we need to do is mount on sector 0 fs().mount(0, device.size(), func); @@ -133,7 +126,7 @@ namespace fs { { if (!data) { // TODO: error-case for unable to read MBR - func(true); + func({ error_t::E_IO, "Unable to read MBR" }); return; } diff --git a/src/fs/ext4.cpp b/src/fs/ext4.cpp index bde88554b3..6b40ff7e5b 100644 --- a/src/fs/ext4.cpp +++ b/src/fs/ext4.cpp @@ -28,17 +28,17 @@ namespace fs // read Master Boot Record (sector 0) device.read(start, - [this, start, size, on_mount] (buffer_t data) - { - auto* mbr = (MBR::mbr*) data.get(); - assert(mbr != nullptr); + [this, start, size, on_mount] (buffer_t data) { - /// now what? - printf("Mounting EXT4 from LBA %llu to %llu\n", - start, size); - - init(data.get()); - }); + auto* mbr = (MBR::mbr*) data.get(); + assert(mbr != nullptr); + + /// now what? + printf("Mounting EXT4 from LBA %llu to %llu\n", + start, size); + + init(data.get()); + }); } @@ -49,18 +49,18 @@ namespace fs EXT4::Buffer EXT4::readFile(const std::string&) { - return Buffer(true, buffer_t(), 0); + return Buffer({ error_t::E_IO, "Not implemented" }, buffer_t(), 0); } void EXT4::readFile(const std::string& strpath, on_read_func callback) { (void) strpath; - callback(true, buffer_t(), 0); + callback({ error_t::E_IO, "Not implemented" }, buffer_t(), 0); } void EXT4::stat(const std::string& strpath, on_stat_func callback) { (void) strpath; - callback(true, Dirent()); + callback({ error_t::E_NOENT, "Not implemented" }, Dirent()); } // filesystem traversal function diff --git a/src/fs/fat.cpp b/src/fs/fat.cpp index 01f85911e4..585a6fb483 100644 --- a/src/fs/fat.cpp +++ b/src/fs/fat.cpp @@ -26,13 +26,12 @@ inline std::string trim_right_copy( namespace fs { FAT::FAT(hw::IDiskDevice& dev) - : device(dev) - { - + : device(dev) { + // } - void FAT::init(const void* base_sector) - { + void FAT::init(const void* base_sector) { + // assume its the master boot record for now auto* mbr = (MBR::mbr*) base_sector; @@ -71,206 +70,200 @@ namespace fs this->sectors = bpb->small_sectors; else this->sectors = bpb->large_sectors; + // sectors per FAT (not sure about the rule here) this->sectors_per_fat = bpb->sectors_per_fat; if (this->sectors_per_fat == 0) this->sectors_per_fat = *(uint32_t*) &mbr->boot[25]; + // root dir sectors from root entries this->root_dir_sectors = ((bpb->root_entries * 32) + (sector_size - 1)) / sector_size; + // calculate index of first data sector this->data_index = bpb->reserved_sectors + (bpb->fa_tables * this->sectors_per_fat) + this->root_dir_sectors; debug("First data sector: %u\n", this->data_index); + // number of reserved sectors is needed constantly this->reserved = bpb->reserved_sectors; debug("Reserved sectors: %u\n", this->reserved); + // number of sectors per cluster is important for calculating entry offsets this->sectors_per_cluster = bpb->sectors_per_cluster; debug("Sectors per cluster: %u\n", this->sectors_per_cluster); + // calculate number of data sectors this->data_sectors = this->sectors - this->data_index; debug("Data sectors: %u\n", this->data_sectors); + // calculate total cluster count this->clusters = this->data_sectors / this->sectors_per_cluster; debug("Total clusters: %u\n", this->clusters); // now that we're here, we can determine the actual FAT type // using the official method: - if (this->clusters < 4085) - { - this->fat_type = FAT::T_FAT12; - this->root_cluster = 2; - debug("The image is type FAT12, with %u clusters\n", this->clusters); - } - else if (this->clusters < 65525) - { - this->fat_type = FAT::T_FAT16; - this->root_cluster = 2; - debug("The image is type FAT16, with %u clusters\n", this->clusters); - } - else - { - this->fat_type = FAT::T_FAT32; - this->root_cluster = *(uint32_t*) &mbr->boot[33]; - this->root_cluster = 2; - debug("The image is type FAT32, with %u clusters\n", this->clusters); - //printf("Root dir entries: %u clusters\n", bpb->root_entries); - //assert(bpb->root_entries == 0); - //this->root_dir_sectors = 0; - //this->data_index = bpb->reserved_sectors + bpb->fa_tables * this->sectors_per_fat; - } + if (this->clusters < 4085) { + this->fat_type = FAT::T_FAT12; + this->root_cluster = 2; + debug("The image is type FAT12, with %u clusters\n", this->clusters); + } + else if (this->clusters < 65525) { + this->fat_type = FAT::T_FAT16; + this->root_cluster = 2; + debug("The image is type FAT16, with %u clusters\n", this->clusters); + } + else { + this->fat_type = FAT::T_FAT32; + this->root_cluster = *(uint32_t*) &mbr->boot[33]; + this->root_cluster = 2; + debug("The image is type FAT32, with %u clusters\n", this->clusters); + //printf("Root dir entries: %u clusters\n", bpb->root_entries); + //assert(bpb->root_entries == 0); + //this->root_dir_sectors = 0; + //this->data_index = bpb->reserved_sectors + bpb->fa_tables * this->sectors_per_fat; + } debug("Root cluster index: %u (sector %u)\n", this->root_cluster, cl_to_sector(root_cluster)); debug("System ID: %.8s\n", bpb->system_id); } - void FAT::mount(uint64_t base, uint64_t size, on_mount_func on_mount) - { + void FAT::mount(uint64_t base, uint64_t size, on_mount_func on_mount) { + this->lba_base = base; this->lba_size = size; // read Partition block device.read(this->lba_base, - [this, on_mount] (buffer_t data) - { - auto* mbr = (MBR::mbr*) data.get(); - assert(mbr != nullptr); + [this, on_mount] (buffer_t data) { - // verify image signature - debug("OEM name: \t%s\n", mbr->oem_name); - debug("MBR signature: \t0x%x\n", mbr->magic); - assert(mbr->magic == 0xAA55); - - // initialize FAT16 or FAT32 filesystem - init(mbr); - - // determine which FAT version is mounted - std::string inf = "ofs: " + std::to_string(lba_base) + - "size: " + std::to_string(lba_size) + - " (" + std::to_string(this->lba_size * sector_size) + " bytes)\n"; - - switch (this->fat_type) - { - case FAT::T_FAT12: - INFO("FS", "Mounting FAT12 filesystem"); - break; - case FAT::T_FAT16: - INFO("FS", "Mounting FAT16 filesystem"); - break; - case FAT::T_FAT32: - INFO("FS", "Mounting FAT32 filesystem"); - break; - } - INFO2("[ofs=%u size=%u (%u bytes)]\n", - this->lba_base, this->lba_size, this->lba_size * 512); + auto* mbr = (MBR::mbr*) data.get(); + assert(mbr != nullptr); + + // verify image signature + debug("OEM name: \t%s\n", mbr->oem_name); + debug("MBR signature: \t0x%x\n", mbr->magic); + if (unlikely(mbr->magic != 0xAA55)) { + on_mount({ error_t::E_MNT, "Missing or invalid MBR signature" }); + return; + } - // on_mount callback - on_mount(no_error); - }); + // initialize FAT16 or FAT32 filesystem + init(mbr); + + // determine which FAT version is mounted + std::string inf = "ofs: " + std::to_string(lba_base) + + "size: " + std::to_string(lba_size) + + " (" + std::to_string(this->lba_size * sector_size) + " bytes)\n"; + + switch (this->fat_type) { + case FAT::T_FAT12: + INFO("FS", "Mounting FAT12 filesystem"); + break; + case FAT::T_FAT16: + INFO("FS", "Mounting FAT16 filesystem"); + break; + case FAT::T_FAT32: + INFO("FS", "Mounting FAT32 filesystem"); + break; + } + INFO2("[ofs=%u size=%u (%u bytes)]\n", + this->lba_base, this->lba_size, this->lba_size * 512); + + // on_mount callback + on_mount(no_error); + }); } - bool FAT::int_dirent( - uint32_t sector, - const void* data, - dirvec_t dirents) - { + bool FAT::int_dirent(uint32_t sector, const void* data, dirvec_t dirents) { + auto* root = (cl_dir*) data; bool found_last = false; - for (int i = 0; i < 16; i++) - { - if (unlikely(root[i].shortname[0] == 0x0)) - { - //printf("end of dir\n"); - found_last = true; - // end of directory - break; - } - else if (unlikely(root[i].shortname[0] == 0xE5)) - { - // unused index - } - else - { - // traverse long names, then final cluster - // to read all the relevant info - - if (likely(root[i].is_longname())) - { - auto* L = (cl_long*) &root[i]; - // the last long index is part of a chain of entries - if (L->is_last()) - { - // buffer for long filename - char final_name[256]; - int final_count = 0; - - int total = L->long_index(); - // go to the last entry and work backwards - i += total-1; - L += total-1; - - for (int idx = total; idx > 0; idx--) - { - uint16_t longname[13]; - memcpy(longname+ 0, L->first, 10); - memcpy(longname+ 5, L->second, 12); - memcpy(longname+11, L->third, 4); - - for (int j = 0; j < 13; j++) - { - // 0xFFFF indicates end of name - if (unlikely(longname[j] == 0xFFFF)) break; - // sometimes, invalid stuff are snuck into filenames - if (unlikely(longname[j] == 0x0)) break; - - final_name[final_count] = longname[j] & 0xFF; - final_count++; - } - L--; - - if (unlikely(final_count > 240)) - { - debug("Suspicious long name length, breaking...\n"); - break; - } - } - - final_name[final_count] = 0; - debug("Long name: %s\n", final_name); - - i++; // skip over the long version - // to the short version for the stats and cluster - auto* D = &root[i]; - std::string dirname(final_name, final_count); - dirname = trim_right_copy(dirname); - - dirents->emplace_back( - D->type(), - dirname, - D->dir_cluster(root_cluster), - sector, // parent block - D->size(), - D->attrib); - } + for (int i = 0; i < 16; i++) { + + if (unlikely(root[i].shortname[0] == 0x0)) { + //printf("end of dir\n"); + found_last = true; + // end of directory + break; + } + else if (unlikely(root[i].shortname[0] == 0xE5)) { + // unused index + } + else { + // traverse long names, then final cluster + // to read all the relevant info + + if (likely(root[i].is_longname())) { + auto* L = (cl_long*) &root[i]; + // the last long index is part of a chain of entries + if (L->is_last()) { + // buffer for long filename + char final_name[256]; + int final_count = 0; + + int total = L->long_index(); + // go to the last entry and work backwards + i += total-1; + L += total-1; + + for (int idx = total; idx > 0; idx--) { + uint16_t longname[13]; + memcpy(longname+ 0, L->first, 10); + memcpy(longname+ 5, L->second, 12); + memcpy(longname+11, L->third, 4); + + for (int j = 0; j < 13; j++) { + // 0xFFFF indicates end of name + if (unlikely(longname[j] == 0xFFFF)) break; + // sometimes, invalid stuff are snuck into filenames + if (unlikely(longname[j] == 0x0)) break; + + final_name[final_count] = longname[j] & 0xFF; + final_count++; } - else - { - auto* D = &root[i]; - debug("Short name: %.11s\n", D->shortname); - - std::string dirname((char*) D->shortname, 11); - dirname = trim_right_copy(dirname); - - dirents->emplace_back( - D->type(), - dirname, - D->dir_cluster(root_cluster), - sector, // parent block - D->size(), - D->attrib); + L--; + + if (unlikely(final_count > 240)) { + debug("Suspicious long name length, breaking...\n"); + break; } + } + + final_name[final_count] = 0; + debug("Long name: %s\n", final_name); + + i++; // skip over the long version + // to the short version for the stats and cluster + auto* D = &root[i]; + std::string dirname(final_name, final_count); + dirname = trim_right_copy(dirname); + + dirents->emplace_back( + D->type(), + dirname, + D->dir_cluster(root_cluster), + sector, // parent block + D->size(), + D->attrib); } - } // directory list + } + else { + auto* D = &root[i]; + debug("Short name: %.11s\n", D->shortname); + + std::string dirname((char*) D->shortname, 11); + dirname = trim_right_copy(dirname); + + dirents->emplace_back( + D->type(), + dirname, + D->dir_cluster(root_cluster), + sector, // parent block + D->size(), + D->attrib); + } + } // entry is long name + } // directory list return found_last; } diff --git a/src/fs/fat_async.cpp b/src/fs/fat_async.cpp index 2b7fe00ee1..a037543d9d 100644 --- a/src/fs/fat_async.cpp +++ b/src/fs/fat_async.cpp @@ -36,7 +36,7 @@ namespace fs if (!data) { // could not read sector - callback(true, dirents); + callback({ error_t::E_IO, "Unable to read directory" }, dirents); return; } @@ -96,7 +96,7 @@ namespace fs if (unlikely(err)) { debug("Could not find: %s\n", name.c_str()); - callback(true, dirents); + callback(err, dirents); return; } @@ -111,13 +111,13 @@ namespace fs if (e.type() == DIR) (*next)(e.block); else - callback(true, dirents); + callback({ error_t::E_NOTDIR, e.name() }, dirents); return; } } // for (ents) debug("NO MATCH for %s\n", name.c_str()); - callback(true, dirents); + callback({ error_t::E_NOENT, name }, dirents); }); }; @@ -140,7 +140,7 @@ namespace fs { // when n=0 roundup() will return an invalid value if (n == 0) { - callback(true, buffer_t(), 0); + callback({ error_t::E_IO, "Zero read length" }, buffer_t(), 0); return; } // calculate start and length in sectors @@ -155,7 +155,7 @@ namespace fs if (!data) { // general I/O error occurred debug("Failed to read sector %u for read()", sector); - callback(true, buffer_t(), 0); + callback({ error_t::E_IO, "Unable to read file" }, buffer_t(), 0); return; } @@ -173,7 +173,7 @@ namespace fs auto path = std::make_shared (strpath); if (unlikely(path->empty())) { // there is no possible file to read where path is empty - callback(true, nullptr, 0); + callback({ error_t::E_NOENT, "Path is empty" }, nullptr, 0); return; } debug("readFile: %s\n", path->back().c_str()); @@ -200,7 +200,7 @@ namespace fs } // file not found - callback(true, buffer_t(), 0); + callback({ error_t::E_NOENT, filename }, buffer_t(), 0); }); } // readFile() @@ -210,7 +210,7 @@ namespace fs if (unlikely(path->empty())) { // root doesn't have any stat anyways // Note: could use ATTR_VOLUME_ID in FAT - func(true, Dirent(INVALID_ENTITY, strpath)); + func({ error_t::E_NOENT, "Cannot stat root" }, Dirent(INVALID_ENTITY, strpath)); return; } @@ -218,32 +218,27 @@ namespace fs // extract file we are looking for std::string filename = path->back(); path->pop_back(); - // we need to remember this later - auto callback = std::make_shared (func); traverse(path, - [this, filename, callback] (error_t error, dirvec_t dirents) - { - if (unlikely(error)) - { - // no path, no file! - (*callback)(error, Dirent(INVALID_ENTITY, filename)); - return; - } + [this, filename, func] (error_t error, dirvec_t dirents) + { + if (unlikely(error)) { + // no path, no file! + func(error, Dirent(INVALID_ENTITY, filename)); + return; + } - // find the matching filename in directory - for (auto& e : *dirents) - { - if (unlikely(e.name() == filename)) - { - // read this file - (*callback)(no_error, e); - return; - } - } + // find the matching filename in directory + for (auto& e : *dirents) { + if (unlikely(e.name() == filename)) { + // read this file + func(no_error, e); + return; + } + } - // not found - (*callback)(true, Dirent(INVALID_ENTITY, filename)); - }); + // not found + func({ error_t::E_NOENT, filename }, Dirent(INVALID_ENTITY, filename)); + }); } } diff --git a/src/fs/fat_sync.cpp b/src/fs/fat_sync.cpp index 14dd3a601d..9c186f66b8 100644 --- a/src/fs/fat_sync.cpp +++ b/src/fs/fat_sync.cpp @@ -43,11 +43,10 @@ namespace fs Buffer FAT::readFile(const std::string& strpath) { Path path(strpath); - if (unlikely(path.empty())) - { - // there is no possible file to read where path is empty - return Buffer(true, nullptr, 0); - } + if (unlikely(path.empty())) { + // there is no possible file to read where path is empty + return Buffer({ error_t::E_NOENT, "Path is empty" }, nullptr, 0); + } debug("readFile: %s\n", path.back().c_str()); std::string filename = path.back(); @@ -57,7 +56,7 @@ namespace fs auto dirents = new_shared_vector(); auto err = traverse(path, dirents); - if (err) return Buffer(true, buffer_t(), 0); // for now + if (err) return Buffer(err, buffer_t(), 0); // for now // find the matching filename in directory for (auto& e : *dirents) @@ -66,22 +65,21 @@ namespace fs return read(e, 0, e.size); } // entry not found - return Buffer(true, buffer_t(), 0); + return Buffer({ error_t::E_NOENT, filename }, buffer_t(), 0); } // readFile() error_t FAT::int_ls(uint32_t sector, dirvec_t ents) { bool done = false; - while (!done) - { - // read sector sync - buffer_t data = device.read_sync(sector); - if (!data) return true; - // parse directory into @ents - done = int_dirent(sector, data.get(), ents); - // go to next sector until done - sector++; - } + while (!done) { + // read sector sync + buffer_t data = device.read_sync(sector); + if (!data) return { error_t::E_IO, "Unable to read directory" }; + // parse directory into @ents + done = int_dirent(sector, data.get(), ents); + // go to next sector until done + sector++; + } return no_error; } @@ -106,31 +104,27 @@ namespace fs // check for matches in dirents for (auto& e : *dirents) - if (unlikely(e.name() == name)) - { - // go to this directory, unless its the last name - debug("traverse_sync: Found match for %s", name.c_str()); - // enter the matching directory - debug("\t\t cluster: %lu\n", e.block); - // only follow if the name is a directory - if (e.type() == DIR) - { - found = e; - break; - } - else - { - // not dir = error, for now - return true; - } - } // for (ents) + if (unlikely(e.name() == name)) { + // go to this directory, unless its the last name + debug("traverse_sync: Found match for %s", name.c_str()); + // enter the matching directory + debug("\t\t cluster: %lu\n", e.block); + // only follow if the name is a directory + if (e.type() == DIR) { + found = e; + break; + } + else { + // not dir = error, for now + return { error_t::E_NOTDIR, "Cannot list non-directory" }; + } + } // for (ents) // validate result - if (found.type() == INVALID_ENTITY) - { - debug("traverse_sync: NO MATCH for %s\n", name.c_str()); - return true; - } + if (found.type() == INVALID_ENTITY) { + debug("traverse_sync: NO MATCH for %s\n", name.c_str()); + return { error_t::E_NOENT, name }; + } // set next cluster cluster = found.block; } diff --git a/src/fs/filesystem.cpp b/src/fs/filesystem.cpp index 8d32a929c6..d33e7b1d65 100644 --- a/src/fs/filesystem.cpp +++ b/src/fs/filesystem.cpp @@ -2,6 +2,23 @@ namespace fs { - error_t no_error = false; + error_t no_error { error_t::NO_ERR, "" }; + + std::string error_t::to_string() const { + switch (token_) { + case NO_ERR: + return "No error"; + case E_IO: + return "General I/O error"; + case E_MNT: + return "Mounting filesystem failed"; + + case E_NOENT: + return "No such entry"; + case E_NOTDIR: + return "Not a directory"; + + } + } } From 3405a2cbb5ad2f2a64eb3e2a27eac288a3158dee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Fri, 29 Apr 2016 12:39:02 +0200 Subject: [PATCH 244/311] test: updated udp test to reflect changes to ip4::addr --- test/UDP/service.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/UDP/service.cpp b/test/UDP/service.cpp index 7f64fb33d3..2c3a9046b9 100644 --- a/test/UDP/service.cpp +++ b/test/UDP/service.cpp @@ -32,8 +32,8 @@ void Service::start() // Assign an IP-address, using Hårek-mapping :-) auto& eth0 = hw::Dev::eth<0,VirtioNet>(); auto& inet = *new net::Inet4(eth0, // Device - {{ 10,0,0,42 }}, // IP - {{ 255,255,0,0 }} ); // Netmask + { 10,0,0,42 }, // IP + { 255,255,0,0 } ); // Netmask printf("Service IP address is %s\n", inet.ip_addr().str().c_str()); From 6c21956e6a04bce1b1ae7c42020df88dfa6c2353 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Fri, 29 Apr 2016 12:48:46 +0200 Subject: [PATCH 245/311] fs: Move buffer from FileSystem to namespace --- api/fs/common.hpp | 39 +++++++++++++++++++++++++++++++++++++-- api/fs/filesystem.hpp | 41 ++++------------------------------------- src/debug/test_disk.cpp | 8 +++++++- src/fs/ext4.cpp | 2 +- src/fs/fat_sync.cpp | 2 -- src/fs/filesystem.cpp | 3 +-- 6 files changed, 50 insertions(+), 45 deletions(-) diff --git a/api/fs/common.hpp b/api/fs/common.hpp index 63a7920a9c..f01a247630 100644 --- a/api/fs/common.hpp +++ b/api/fs/common.hpp @@ -41,12 +41,17 @@ namespace fs { : token_(tk), reason_(rsn) {} // error code to string - std::string to_string() const; + std::string token() const noexcept; // show explanation for error std::string reason() const noexcept { return reason_; } + // returns "description": "reason" + std::string to_string() const noexcept { + return token() + ": " + reason(); + } + // returns true when it's an error operator bool () const noexcept { return token_ != NO_ERR; @@ -56,7 +61,37 @@ namespace fs { token_t token_; std::string reason_; }; - + + struct Buffer + { + Buffer(error_t e, buffer_t b, size_t l) + : err(e), buffer(b), len(l) {} + + // returns true if this buffer is valid + bool is_valid() const noexcept { + return buffer != nullptr; + } + operator bool () const noexcept { + return is_valid(); + } + + uint8_t* data() { + return buffer.get(); + } + size_t size() const noexcept { + return len; + } + + // create a std::string from the stored buffer and return it + std::string to_string() const noexcept { + return std::string((char*) buffer.get(), size()); + } + + error_t err; + buffer_t buffer; + uint64_t len; + }; + /** @var no_error: Always returns boolean false when used in expressions */ extern error_t no_error; diff --git a/api/fs/filesystem.hpp b/api/fs/filesystem.hpp index a519b41e6d..f7a66a52bf 100644 --- a/api/fs/filesystem.hpp +++ b/api/fs/filesystem.hpp @@ -27,7 +27,7 @@ #include namespace fs { - + class FileSystem { public: struct Dirent; //< Generic structure for directory entries @@ -41,41 +41,6 @@ namespace fs { using on_read_func = std::function; using on_stat_func = std::function; - struct Buffer - { - Buffer(error_t e, buffer_t b, size_t l) - : err(e), buffer(b), len(l) {} - - // returns true if this buffer is valid - bool is_valid() const - { - return buffer != nullptr; - } - operator bool () const - { - return is_valid(); - } - - uint8_t* data() - { - return buffer.get(); - } - size_t size() const - { - return len; - } - - // create a std::string from the stored buffer and return it - std::string to_string() const - { - return std::string((char*) buffer.get(), size()); - } - - error_t err; - buffer_t buffer; - uint64_t len; - }; - enum Enttype { FILE, DIR, @@ -176,7 +141,9 @@ namespace fs { { return std::make_shared (); } - + + using Dirent = FileSystem::Dirent; + } //< namespace fs #endif //< FS_FILESYSTEM_HPP diff --git a/src/debug/test_disk.cpp b/src/debug/test_disk.cpp index d2b0fe2248..4ab01fa38c 100644 --- a/src/debug/test_disk.cpp +++ b/src/debug/test_disk.cpp @@ -48,11 +48,17 @@ void Service::start() disk->mount( [] (fs::error_t err) { if (err) { - printf("Could not mount filesystem\n"); + printf("Error: %s\n", err.to_string().c_str()); return; } printf("Mounted filesystem\n"); + // read something that doesn't exist + disk->fs().stat("/fefe/fefe", + [] (fs::error_t err, const fs::Dirent&) { + printf("Error: %s\n", err.to_string().c_str()); + }); + // async ls disk->fs().ls("/", [] (fs::error_t err, auto ents) { diff --git a/src/fs/ext4.cpp b/src/fs/ext4.cpp index 6b40ff7e5b..81959edeb7 100644 --- a/src/fs/ext4.cpp +++ b/src/fs/ext4.cpp @@ -47,7 +47,7 @@ namespace fs (void) path; } - EXT4::Buffer EXT4::readFile(const std::string&) + Buffer EXT4::readFile(const std::string&) { return Buffer({ error_t::E_IO, "Not implemented" }, buffer_t(), 0); } diff --git a/src/fs/fat_sync.cpp b/src/fs/fat_sync.cpp index 9c186f66b8..aa14bcf5ec 100644 --- a/src/fs/fat_sync.cpp +++ b/src/fs/fat_sync.cpp @@ -18,8 +18,6 @@ inline size_t roundup(size_t n, size_t multiple) namespace fs { - typedef FileSystem::Buffer Buffer; - Buffer FAT::read(const Dirent& ent, uint64_t pos, uint64_t n) { // cluster -> sector + position diff --git a/src/fs/filesystem.cpp b/src/fs/filesystem.cpp index d33e7b1d65..be2ef7a520 100644 --- a/src/fs/filesystem.cpp +++ b/src/fs/filesystem.cpp @@ -4,7 +4,7 @@ namespace fs { error_t no_error { error_t::NO_ERR, "" }; - std::string error_t::to_string() const { + std::string error_t::token() const noexcept { switch (token_) { case NO_ERR: return "No error"; @@ -17,7 +17,6 @@ namespace fs return "No such entry"; case E_NOTDIR: return "Not a directory"; - } } From 199ad3f61e0cf519ed3708aafd438da4ff3f2cfd Mon Sep 17 00:00:00 2001 From: Martin Nordsletten Date: Fri, 29 Apr 2016 13:20:42 +0200 Subject: [PATCH 246/311] Updated transmission test to reflect changes to ip4::addr --- test/transmit/service.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/transmit/service.cpp b/test/transmit/service.cpp index eacbd38ffa..7e9a115da1 100644 --- a/test/transmit/service.cpp +++ b/test/transmit/service.cpp @@ -36,10 +36,10 @@ void Service::start() inet = std::make_shared>(eth0); auto& timer = hw::PIT::instance(); - inet->network_config({{ mac.part[2],mac.part[3],mac.part[4],mac.part[5] }}, - {{ 255,255,0,0 }}, // Netmask - {{ 10,0,0,1 }}, // Gateway - {{ 8,8,8,8}}); // DNS + inet->network_config({ mac.part[2],mac.part[3],mac.part[4],mac.part[5] }, + { 255,255,0,0 }, // Netmask + { 10,0,0,1 }, // Gateway + { 8,8,8,8 }); // DNS printf("Service IP address: %s \n", inet->ip_addr().str().c_str()); From 873326ad16f7ccbdad458d60674e0074d9dbf5fb Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Mon, 2 May 2016 10:40:44 +0200 Subject: [PATCH 247/311] fs: fat_sync errors are unlikely --- src/fs/fat_sync.cpp | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/fs/fat_sync.cpp b/src/fs/fat_sync.cpp index aa14bcf5ec..790b367c32 100644 --- a/src/fs/fat_sync.cpp +++ b/src/fs/fat_sync.cpp @@ -54,7 +54,8 @@ namespace fs auto dirents = new_shared_vector(); auto err = traverse(path, dirents); - if (err) return Buffer(err, buffer_t(), 0); // for now + if (unlikely(err)) + return Buffer(err, buffer_t(), 0); // for now // find the matching filename in directory for (auto& e : *dirents) @@ -72,7 +73,8 @@ namespace fs while (!done) { // read sector sync buffer_t data = device.read_sync(sector); - if (!data) return { error_t::E_IO, "Unable to read directory" }; + if (unlikely(!data)) + return { error_t::E_IO, "Unable to read directory" }; // parse directory into @ents done = int_dirent(sector, data.get(), ents); // go to next sector until done @@ -95,7 +97,7 @@ namespace fs dirents->clear(); // mui importante // sync read entire directory auto err = int_ls(S, dirents); - if (err) return err; + if (unlikely(err)) return err; // the name we are looking for std::string name = path.front(); path.pop_front(); @@ -140,11 +142,10 @@ namespace fs FAT::Dirent FAT::stat(const std::string& strpath) { Path path(strpath); - if (unlikely(path.empty())) - { - // root doesn't have any stat anyways (except ATTR_VOLUME_ID in FAT) - return Dirent(INVALID_ENTITY); - } + if (unlikely(path.empty())) { + // root doesn't have any stat anyways (except ATTR_VOLUME_ID in FAT) + return Dirent(INVALID_ENTITY); + } debug("stat_sync: %s\n", path.back().c_str()); // extract file we are looking for @@ -155,17 +156,15 @@ namespace fs auto dirents = std::make_shared> (); auto err = traverse(path, dirents); - if (err) return Dirent(INVALID_ENTITY); // for now + if (unlikely(err)) + return Dirent(INVALID_ENTITY); // for now // find the matching filename in directory for (auto& e : *dirents) - { - if (unlikely(e.name() == filename)) - { - // return this directory entry - return e; - } - } + if (unlikely(e.name() == filename)) { + // return this directory entry + return e; + } // entry not found return Dirent(INVALID_ENTITY); } From afcd91c37941c6e3659ee2b6f100788bfe68c2b3 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Mon, 2 May 2016 13:10:21 +0200 Subject: [PATCH 248/311] dns: Resolve now only takes 1 parameter --- api/net/dns/dns.hpp | 6 +++--- api/net/inet.hpp | 2 +- src/net/dns/client.cpp | 18 +++++++++--------- test/tcp/service.cpp | 3 ++- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/api/net/dns/dns.hpp b/api/net/dns/dns.hpp index 8b2bd9f2d5..1b03f90eaa 100644 --- a/api/net/dns/dns.hpp +++ b/api/net/dns/dns.hpp @@ -159,10 +159,10 @@ namespace net } IP4::addr getFirstIP4() const { - IP4::addr result(0); if (answers.size()) - result = answers[0].getIP4(); - return result; + return answers[0].getIP4(); + + return IP4::INADDR_ANY; } private: diff --git a/api/net/inet.hpp b/api/net/inet.hpp index 348f100091..17431d00b4 100644 --- a/api/net/inet.hpp +++ b/api/net/inet.hpp @@ -33,7 +33,7 @@ namespace net { using Stack = Inet; template - using resolve_func = delegate; + using resolve_func = delegate; virtual typename IPV::addr ip_addr() = 0; virtual typename IPV::addr netmask() = 0; diff --git a/src/net/dns/client.cpp b/src/net/dns/client.cpp index f90ba0b480..41e5584bb5 100644 --- a/src/net/dns/client.cpp +++ b/src/net/dns/client.cpp @@ -38,14 +38,14 @@ namespace net // wait for response // FIXME: WE DO NOT CHECK TRANSACTION IDS HERE (yet), GOD HELP US ALL sock.on_read( - [this, hostname, request, func] - (IP4::addr, UDP::port_t, const char* data, size_t) mutable - { - // original request ID = this->id; - request.parseResponse(data); - - // fire onResolve event - func(this->stack, hostname, request.getFirstIP4()); - }); + [this, hostname, request, func] + (IP4::addr, UDP::port_t, const char* data, size_t) mutable + { + // original request ID = this->id; + request.parseResponse(data); + + // fire onResolve event + func(request.getFirstIP4()); + }); } } diff --git a/test/tcp/service.cpp b/test/tcp/service.cpp index 43efd82088..6261df80c4 100644 --- a/test/tcp/service.cpp +++ b/test/tcp/service.cpp @@ -75,7 +75,8 @@ void FINISH_TEST() { void OUTGOING_TEST_INTERNET(const HostAddress& address) { auto port = address.second; INFO("TEST", "Outgoing Internet Connection (%s:%u)", address.first.c_str(), address.second); - inet->resolve(address.first, [port](auto&, auto&, auto ip_address) { + inet->resolve(address.first, + [port](auto ip_address) { CHECK(ip_address != 0, "Resolved host"); if(ip_address != 0) { From 8af6a4efb630ebc2a6b87ef7d68ea939831e02ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Mon, 2 May 2016 13:13:52 +0200 Subject: [PATCH 249/311] tcp: work on port usage --- api/net/tcp.hpp | 12 +++++++++--- src/net/tcp.cpp | 38 +++++++++++++++++++------------------- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index b0a6cfe50e..bffdc1eab3 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -835,6 +835,12 @@ namespace net { */ inline const TCP& host() const { return host_; } + /* + The local Port bound to this connection. + */ + inline TCP::Port local_port() const + { return local_port_; } + /* The local Socket bound to this connection. */ @@ -1484,6 +1490,7 @@ namespace net { inline void reduce_ssthresh() { auto fs = flight_size(); + printf(" FlightSize: %u\n", fs); if(limited_tx_) fs -= 2*(uint32_t)SMSS(); @@ -1738,8 +1745,7 @@ namespace net { std::deque writeq; using PortMap = std::bitset; - //std::unique_ptr used_ports; - PortMap used_ports; + std::unique_ptr used_ports; /* Settings @@ -1761,7 +1767,7 @@ namespace net { /* Returns a free port for outgoing connections. */ - TCP::Port free_port(); + TCP::Port next_free_port(); /* Check if the port is in use either among "listeners" or "connections" diff --git a/src/net/tcp.cpp b/src/net/tcp.cpp index dcc2b3b007..683c45ad95 100644 --- a/src/net/tcp.cpp +++ b/src/net/tcp.cpp @@ -18,6 +18,7 @@ #define DEBUG2 #include +#include using namespace std; using namespace net; @@ -28,7 +29,7 @@ TCP::TCP(IPStack& inet) : listeners_(), connections_(), writeq(), - used_ports(), + used_ports(new PortMap), MAX_SEG_LIFETIME(30s) { inet.on_transmit_queue_available(transmit_avail_delg::from(this)); @@ -46,12 +47,12 @@ TCP::TCP(IPStack& inet) : Simple. */ TCP::Connection& TCP::bind(Port port) { - auto listen_conn_it = listeners_.find(port); // Already a listening socket. - if(listen_conn_it != listeners_.end()) { + if(port_in_use(port)) { throw TCPException{"Port is already taken."}; } auto& connection = (listeners_.emplace(port, Connection{*this, port})).first->second; + (*used_ports)[port]=1; debug(" Bound to port %i \n", port); connection.open(false); return connection; @@ -64,7 +65,9 @@ TCP::Connection& TCP::bind(Port port) { and open() is called before callback is added. */ TCP::Connection_ptr TCP::connect(Socket remote) { - std::shared_ptr connection = add_connection(free_port(), remote); + auto port = next_free_port(); + std::shared_ptr connection = add_connection(port, remote); + (*used_ports)[port]=1; connection->open(true); return connection; } @@ -73,7 +76,9 @@ TCP::Connection_ptr TCP::connect(Socket remote) { Active open a new connection to the given remote. */ void TCP::connect(Socket remote, Connection::ConnectCallback callback) { - auto connection = add_connection(free_port(), remote); + auto port = next_free_port(); + auto connection = add_connection(port, remote); + (*used_ports)[port]=1; connection->onConnect(callback).open(true); } @@ -85,12 +90,13 @@ TCP::Seq TCP::generate_iss() { /* TODO: Check if there is any ports free. */ -TCP::Port TCP::free_port() { - //assert(!used_ports.all()); +TCP::Port TCP::next_free_port() { + Ensures(!used_ports->all()); + if(++current_ephemeral_ == 0) current_ephemeral_ = 1025; // Avoid giving a port that is bound to a service. - while(listeners_.find(current_ephemeral_) != listeners_.end()) + while(port_in_use(current_ephemeral_)) current_ephemeral_++; return current_ephemeral_; @@ -104,14 +110,7 @@ TCP::Port TCP::free_port() { } bool TCP::port_in_use(const TCP::Port port) const { - if(listeners_.find(port) != listeners_.end()) - return true; - - for(auto it : connections_) { - if(it.first.first == port) - return true; - } - return false; + return (*used_ports)[port]; } @@ -279,7 +278,10 @@ TCP::Connection_ptr TCP::add_connection(Port local_port, TCP::Socket remote) { void TCP::close_connection(TCP::Connection& conn) { debug(" Closing connection: %s \n", conn.to_string().c_str()); connections_.erase(conn.tuple()); - debug2(" TCP Status: \n%s \n", status().c_str()); + auto port = conn.local_port(); + // If it's an active connection + if(listeners_.find(port) == listeners_.end()) + (*used_ports)[port]=0; } void TCP::drop(TCP::Packet_ptr) { @@ -287,11 +289,9 @@ void TCP::drop(TCP::Packet_ptr) { } void TCP::transmit(TCP::Packet_ptr packet) { - // Translate into a net::Packet_ptr and send away. // Generate checksum. packet->set_checksum(TCP::checksum(packet)); //if(packet->has_data()) // printf(" S: %u\n", packet->seq()); - //packet->set_checksum(checksum(packet)); _network_layer_out(packet); } From c34fb27db6bf52e1efdf4d2e08af1c20c5d43f47 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Mon, 2 May 2016 15:41:18 +0200 Subject: [PATCH 250/311] util: Async stream --- api/stream | 8 ++++++ api/utility/stream.hpp | 27 ++++++++++++++++++++ src/Makefile | 2 +- src/util/stream.cpp | 58 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 api/stream create mode 100644 api/utility/stream.hpp create mode 100644 src/util/stream.cpp diff --git a/api/stream b/api/stream new file mode 100644 index 0000000000..dfb8aafcd1 --- /dev/null +++ b/api/stream @@ -0,0 +1,8 @@ +#pragma once +#ifndef API_STREAM_HEADER +#define API_STREAM_HEADER + +// hmm... +#include "utility/stream.hpp" + +#endif diff --git a/api/utility/stream.hpp b/api/utility/stream.hpp new file mode 100644 index 0000000000..ccf9e0dbac --- /dev/null +++ b/api/utility/stream.hpp @@ -0,0 +1,27 @@ +#pragma once +#ifndef UTILITY_STREAM_HPP +#define UTILITY_STREAM_HPP + +#include +#include +#include + +class Stream +{ + static const size_t PAYLOAD_SIZE = 64000; + + typedef net::TCP::Connection_ptr Connection; + typedef fs::Disk_ptr Disk; + typedef fs::FileSystem::Dirent Dirent; + + typedef std::function on_after_func; + + static void upload( + Connection, + Disk, + const Dirent&, + on_after_func, + size_t = PAYLOAD_SIZE); +}; + +#endif diff --git a/src/Makefile b/src/Makefile index 73b754f8e8..c9598d8ad5 100644 --- a/src/Makefile +++ b/src/Makefile @@ -63,7 +63,7 @@ OS_OBJECTS = kernel/kernel_start.o kernel/syscalls.o \ kernel/interrupts.o kernel/os.o kernel/cpuid.o \ kernel/irq_manager.o kernel/pci_manager.o \ kernel/terminal.o kernel/terminal_disk.o \ - kernel/vga.o util/memstream.o \ + kernel/vga.o util/memstream.o util/stream.o \ crt/c_abi.o crt/string.o crt/quick_exit.o crt/cxx_abi.o crt/mman.o \ hw/ide.o hw/pit.o hw/pic.o hw/pci_device.o hw/cpu_freq_sampling.o hw/serial.o\ virtio/virtio.o virtio/virtio_queue.o virtio/virtionet.o \ diff --git a/src/util/stream.cpp b/src/util/stream.cpp new file mode 100644 index 0000000000..fde520f47b --- /dev/null +++ b/src/util/stream.cpp @@ -0,0 +1,58 @@ +#include + +#include + +void Stream::upload( + Connection conn, + Disk disk, + const Dirent& ent, + on_after_func callback, + const size_t CHUNK_SIZE) +{ + typedef std::function next_func_t; + auto next = std::make_shared (); + + *next = + [next, conn, disk, ent, callback, CHUNK_SIZE] (size_t pos) { + + // number of write calls necessary + const size_t writes = ent.size / CHUNK_SIZE; + + // done condition + if (pos >= writes) { + callback(fs::no_error, true); + return; + } + + // read chunk from file + disk->fs().read(ent, pos * CHUNK_SIZE, CHUNK_SIZE, + [next, pos, conn, ent, callback] ( + fs::error_t err, + fs::buffer_t buffer, + uint64_t length) + { + if (err) { + printf("BAD\n"); + callback(err, false); + return; + } + + // write chunk to TCP connection + conn->write(buffer.get(), length, + [next, pos, ent, callback] (size_t n) { + + // if all data written, go to next chunk + if (n == ent.size) + (*next)(pos+1); + else + // otherwise, fail + callback(fs::no_error, false); + + }, true); + + }); + + }; + + (*next)(0); +} From 36062c6aa3bb78931de781665d360d654a06a1e3 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Mon, 2 May 2016 16:24:11 +0200 Subject: [PATCH 251/311] stream: Add disk_transfer, rename to Async --- api/utility/stream.hpp | 14 ++++++++++-- src/debug/service.gdb | 2 +- src/util/stream.cpp | 52 ++++++++++++++++++++++++++++++------------ 3 files changed, 51 insertions(+), 17 deletions(-) diff --git a/api/utility/stream.hpp b/api/utility/stream.hpp index ccf9e0dbac..db80ef9ef8 100644 --- a/api/utility/stream.hpp +++ b/api/utility/stream.hpp @@ -6,7 +6,7 @@ #include #include -class Stream +class Async { static const size_t PAYLOAD_SIZE = 64000; @@ -14,14 +14,24 @@ class Stream typedef fs::Disk_ptr Disk; typedef fs::FileSystem::Dirent Dirent; + typedef std::function next_func; typedef std::function on_after_func; + typedef std::function on_write_func; - static void upload( + static void upload_file( + Disk, + const Dirent&, Connection, + on_after_func, + size_t = PAYLOAD_SIZE); + + static void disk_transfer( Disk, const Dirent&, + on_write_func, on_after_func, size_t = PAYLOAD_SIZE); + }; #endif diff --git a/src/debug/service.gdb b/src/debug/service.gdb index 655fa909ae..fd52480ae6 100644 --- a/src/debug/service.gdb +++ b/src/debug/service.gdb @@ -1,4 +1,4 @@ file test_service -break VirtioNet::irq_handler +break Service::start set non-stop off target remote localhost:1234 diff --git a/src/util/stream.cpp b/src/util/stream.cpp index fde520f47b..057b3130ad 100644 --- a/src/util/stream.cpp +++ b/src/util/stream.cpp @@ -2,10 +2,37 @@ #include -void Stream::upload( +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) + +void Async::upload_file( + Disk disk, + const Dirent& ent, Connection conn, + on_after_func callback, + const size_t CHUNK_SIZE) +{ + disk_transfer(disk, ent, + [conn, callback, CHUNK_SIZE] (fs::buffer_t buffer, + size_t length, + next_func next) + { + // write chunk to TCP connection + conn->write(buffer.get(), length, + [callback, CHUNK_SIZE, next] (size_t n) { + + // if all data written, go to next chunk + next(n == CHUNK_SIZE); + + }, true); + + }, callback, CHUNK_SIZE); +} + +void Async::disk_transfer( Disk disk, const Dirent& ent, + on_write_func write_func, on_after_func callback, const size_t CHUNK_SIZE) { @@ -13,7 +40,7 @@ void Stream::upload( auto next = std::make_shared (); *next = - [next, conn, disk, ent, callback, CHUNK_SIZE] (size_t pos) { + [next, disk, ent, write_func, callback, CHUNK_SIZE] (size_t pos) { // number of write calls necessary const size_t writes = ent.size / CHUNK_SIZE; @@ -26,33 +53,30 @@ void Stream::upload( // read chunk from file disk->fs().read(ent, pos * CHUNK_SIZE, CHUNK_SIZE, - [next, pos, conn, ent, callback] ( + [next, pos, write_func, callback, CHUNK_SIZE] ( fs::error_t err, fs::buffer_t buffer, uint64_t length) { if (err) { - printf("BAD\n"); + printf("%s\n", err.to_string().c_str()); callback(err, false); return; } - // write chunk to TCP connection - conn->write(buffer.get(), length, - [next, pos, ent, callback] (size_t n) { - - // if all data written, go to next chunk - if (n == ent.size) + // call write callback with data + write_func(buffer, length, + [next, pos, callback] (bool good) { + // if the write succeeded, call next + if (likely(good)) (*next)(pos+1); else // otherwise, fail callback(fs::no_error, false); - - }, true); - + }); }); }; - + // start async loop (*next)(0); } From c25d792f4eb3081f043f089aaa454c2fa386fa35 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Mon, 2 May 2016 16:27:26 +0200 Subject: [PATCH 252/311] util: Rename stream to async --- api/async | 8 ++++++++ api/stream | 8 -------- api/utility/{stream.hpp => async.hpp} | 4 ++-- src/util/{stream.cpp => async.cpp} | 0 4 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 api/async delete mode 100644 api/stream rename api/utility/{stream.hpp => async.hpp} (93%) rename src/util/{stream.cpp => async.cpp} (100%) diff --git a/api/async b/api/async new file mode 100644 index 0000000000..e8c027dd2b --- /dev/null +++ b/api/async @@ -0,0 +1,8 @@ +#pragma once +#ifndef API_ASYNC_HEADER +#define API_ASYNC_HEADER + +// hmm... +#include "utility/async.hpp" + +#endif diff --git a/api/stream b/api/stream deleted file mode 100644 index dfb8aafcd1..0000000000 --- a/api/stream +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#ifndef API_STREAM_HEADER -#define API_STREAM_HEADER - -// hmm... -#include "utility/stream.hpp" - -#endif diff --git a/api/utility/stream.hpp b/api/utility/async.hpp similarity index 93% rename from api/utility/stream.hpp rename to api/utility/async.hpp index db80ef9ef8..8d65e6e50d 100644 --- a/api/utility/stream.hpp +++ b/api/utility/async.hpp @@ -1,6 +1,6 @@ #pragma once -#ifndef UTILITY_STREAM_HPP -#define UTILITY_STREAM_HPP +#ifndef UTILITY_ASYNC_HPP +#define UTILITY_ASYNC_HPP #include #include diff --git a/src/util/stream.cpp b/src/util/async.cpp similarity index 100% rename from src/util/stream.cpp rename to src/util/async.cpp From 62ea735e468641bae37a6ceb4aeea353a4272a7f Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Mon, 2 May 2016 16:40:14 +0200 Subject: [PATCH 253/311] util: Fix async header include --- src/Makefile | 2 +- src/util/async.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Makefile b/src/Makefile index c9598d8ad5..5da97bc26e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -63,7 +63,7 @@ OS_OBJECTS = kernel/kernel_start.o kernel/syscalls.o \ kernel/interrupts.o kernel/os.o kernel/cpuid.o \ kernel/irq_manager.o kernel/pci_manager.o \ kernel/terminal.o kernel/terminal_disk.o \ - kernel/vga.o util/memstream.o util/stream.o \ + kernel/vga.o util/memstream.o util/async.o \ crt/c_abi.o crt/string.o crt/quick_exit.o crt/cxx_abi.o crt/mman.o \ hw/ide.o hw/pit.o hw/pic.o hw/pci_device.o hw/cpu_freq_sampling.o hw/serial.o\ virtio/virtio.o virtio/virtio_queue.o virtio/virtionet.o \ diff --git a/src/util/async.cpp b/src/util/async.cpp index 057b3130ad..36e3fc8879 100644 --- a/src/util/async.cpp +++ b/src/util/async.cpp @@ -1,4 +1,4 @@ -#include +#include #include From 43d6ce07fa3136d1e605f2f01445108a9293a923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Mon, 2 May 2016 17:04:11 +0200 Subject: [PATCH 254/311] tcp: changes to writeq to avoid storing rtx packets (wip) --- api/net/tcp.hpp | 72 ++++++++++++++++++++++++++++++++++---- src/net/tcp.cpp | 35 +++++++++--------- src/net/tcp_connection.cpp | 61 +++++++++++++------------------- 3 files changed, 107 insertions(+), 61 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index bffdc1eab3..d4798091a0 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -533,14 +533,15 @@ namespace net { buffer_t buffer; size_t remaining; size_t offset; + size_t acknowledged; bool push; WriteBuffer(buffer_t buf, size_t length, bool PSH, size_t offs = 0) - : buffer(buf), remaining(length-offs), offset(offs), push(PSH) {} + : buffer(buf), remaining(length-offs), offset(offs), acknowledged(0), push(PSH) {} inline size_t length() const { return remaining + offset; } - inline bool done() const { return remaining == 0; } + inline bool done() const { return acknowledged == length(); } inline uint8_t* begin() const { return buffer.get(); } @@ -554,6 +555,13 @@ namespace net { remaining -= length; return length > 0; } + + size_t acknowledge(size_t bytes) { + auto acked = std::min(bytes, length()-acknowledged); + acknowledged += acked; + return acked; + } + }; // < Connection::WriteBuffer /* @@ -580,6 +588,59 @@ namespace net { using WriteRequest = std::pair; + + /* + Write Queue + */ + struct WriteQueue { + + std::deque q; + + std::deque::iterator current; + + WriteQueue() : q(), current(q.begin()) {} + + void acknowledge(size_t bytes) { + while(bytes and !q.empty()) + { + auto& buf = q.front()->first; + + bytes -= buf.acknowledge(bytes); + + if(buf.done()) { + buf.pop_front(); + } + } + } + + bool empty() const + { return q.empty(); } + + size_t size() const + { return q.size(); } + + bool remaining_requests() const + { return !q.empty() and q.back().remaining; } + + const WriteBuffer& nxt() + { return current->first; } + + const WriteBuffer& una() + { return q.front()->first; } + + void advance(size_t bytes) { + + auto& buf = current->first; + + buf.advance(bytes); + + if(!buf.remaining) { + current->second(buf.offset); + current++; + } + } + }; + /* Connection identifier */ @@ -1112,7 +1173,7 @@ namespace net { /* Queue for write requests to process */ - std::queue writeq; + WriteQueue writeq; /* State if connection is in TCP write queue or not. @@ -1333,7 +1394,7 @@ namespace net { Returns if the connection has a doable write job. */ inline bool has_doable_job() { - return !writeq.empty() and usable_window() >= SMSS(); + return !writeq.remaining_requests() and usable_window() >= SMSS(); } /* @@ -1744,8 +1805,7 @@ namespace net { std::deque writeq; - using PortMap = std::bitset; - std::unique_ptr used_ports; + std::vector used_ports; /* Settings diff --git a/src/net/tcp.cpp b/src/net/tcp.cpp index 683c45ad95..bbda00d2d9 100644 --- a/src/net/tcp.cpp +++ b/src/net/tcp.cpp @@ -29,7 +29,7 @@ TCP::TCP(IPStack& inet) : listeners_(), connections_(), writeq(), - used_ports(new PortMap), + used_ports(), MAX_SEG_LIFETIME(30s) { inet.on_transmit_queue_available(transmit_avail_delg::from(this)); @@ -52,7 +52,6 @@ TCP::Connection& TCP::bind(Port port) { throw TCPException{"Port is already taken."}; } auto& connection = (listeners_.emplace(port, Connection{*this, port})).first->second; - (*used_ports)[port]=1; debug(" Bound to port %i \n", port); connection.open(false); return connection; @@ -67,7 +66,6 @@ TCP::Connection& TCP::bind(Port port) { TCP::Connection_ptr TCP::connect(Socket remote) { auto port = next_free_port(); std::shared_ptr connection = add_connection(port, remote); - (*used_ports)[port]=1; connection->open(true); return connection; } @@ -78,7 +76,6 @@ TCP::Connection_ptr TCP::connect(Socket remote) { void TCP::connect(Socket remote, Connection::ConnectCallback callback) { auto port = next_free_port(); auto connection = add_connection(port, remote); - (*used_ports)[port]=1; connection->onConnect(callback).open(true); } @@ -91,26 +88,30 @@ TCP::Seq TCP::generate_iss() { TODO: Check if there is any ports free. */ TCP::Port TCP::next_free_port() { - Ensures(!used_ports->all()); - if(++current_ephemeral_ == 0) + if(++current_ephemeral_ == 0) { current_ephemeral_ = 1025; + // TODO: Can be taken + } // Avoid giving a port that is bound to a service. - while(port_in_use(current_ephemeral_)) + while(listeners_.find(current_ephemeral_) != listeners_.end()) current_ephemeral_++; return current_ephemeral_; - - /*TCP::Port port; - do { - port = current_ephemeral_ + rand() % (65535 - current_ephemeral_); - } while(port_in_use(port)); - - return port;*/ } +/* + Expensive look up if port is in use. +*/ bool TCP::port_in_use(const TCP::Port port) const { - return (*used_ports)[port]; + if(listeners_.find(port) != listeners_.end()) + return true; + + for(auto conn : connections_) { + if(conn.first.first == port) + return true; + } + return false; } @@ -278,10 +279,6 @@ TCP::Connection_ptr TCP::add_connection(Port local_port, TCP::Socket remote) { void TCP::close_connection(TCP::Connection& conn) { debug(" Closing connection: %s \n", conn.to_string().c_str()); connections_.erase(conn.tuple()); - auto port = conn.local_port(); - // If it's an active connection - if(listeners_.find(port) == listeners_.end()) - (*used_ports)[port]=0; } void TCP::drop(TCP::Packet_ptr) { diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index 5c47a9e2a1..80f282796f 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -101,6 +101,7 @@ size_t Connection::receive(const uint8_t* data, size_t n, bool PUSH) { void Connection::write(WriteBuffer buffer, WriteCallback callback) { try { + state_->is_writeable(); auto written = state_->send(*this, buffer); buffer.advance(written); @@ -129,25 +130,19 @@ void Connection::offer(size_t& packets) { auto packet = create_outgoing_packet(); packets--; - // get the first buffer in queue - auto& buf = writeq.front().first; + // get next request in writeq + auto& buf = writeq.nxt(); // fill the packet with data - auto written = fill_packet(packet, (char*)buf.pos(), std::min(buf.remaining, (size_t)SMSS())); - // advance the buffer - buf.advance(written); + auto written = fill_packet(packet, (char*)buf.pos(), std::min(buf.remaining, (size_t)SMSS()), cb.SND.NXT); + cb.SND.NXT += packet->data_length(); + + // advance the write q + writeq.advance(written); debug2(" Wrote %u bytes (%u remaining) with [%u] packets left and a usable window of %u.\n", written, buf.remaining, packets, usable_window()); transmit(packet); - - // if finished - if(!buf.remaining) { - // callback and remove object - writeq.front().second(buf.offset); - writeq.pop(); - debug(" Request finished.\n"); - } } debug(" Finished working offer with [%u] packets left and a queue of (%u) with a usable window of %i\n", @@ -167,7 +162,8 @@ size_t Connection::send(const char* buffer, size_t remaining, size_t& packets_av auto packet = create_outgoing_packet(); packets_avail--; - auto written = fill_packet(packet, buffer+bytes_written, std::min(remaining, (size_t)SMSS())); + auto written = fill_packet(packet, buffer+bytes_written, std::min(remaining, (size_t)SMSS()), cb.SND.NXT); + cb.SND.NXT += packet->data_length(); bytes_written += written; remaining -= written; @@ -217,24 +213,21 @@ void Connection::make_flight_ready(Packet_ptr packet) { }*/ void Connection::writeq_push() { - while(!writeq.empty()) { - auto& buf = writeq.front().first; + while(!writeq.remaining_requests()) { + auto& buf = writeq.nxt(); auto written = host_.send(shared_from_this(), (char*)buf.pos(), buf.remaining); - buf.advance(written); + writeq.advance(written); if(buf.remaining) return; - writeq.front().second(buf.offset); - writeq.pop(); } } -size_t Connection::fill_packet(Packet_ptr packet, const char* buffer, size_t n) { +size_t Connection::fill_packet(Packet_ptr packet, const char* buffer, size_t n, Seq seq) { Expects(!packet->has_data()); auto written = packet->fill(buffer, n); - packet->set_seq(cb.SND.NXT).set_ack(cb.RCV.NXT).set_flag(ACK); - cb.SND.NXT += packet->data_length(); + packet->set_seq(seq).set_ack(cb.RCV.NXT).set_flag(ACK); Ensures(written <= n); @@ -247,25 +240,21 @@ void Connection::limited_tx() { debug(" UW: %u CW: %u, FS: %u\n", usable_window(), cb.cwnd, flight_size()); - auto& buf = writeq.front().first; - auto written = fill_packet(packet, (char*)buf.pos(), std::min(buf.remaining, (uint32_t)SMSS())); + auto& buf = writeq.nxt(); + + auto written = fill_packet(packet, (char*)buf.pos(), std::min(buf.remaining, (uint32_t)SMSS()), cb.SND.NXT); + cb.SND.NXT += packet->data_length(); - buf.advance(written); + writeq.advance(written); transmit(packet); - - if(buf.remaining) - return; - - writeq.front().second(buf.offset); - writeq.pop(); } void Connection::writeq_reset() { while(!writeq.empty()) { - auto& job = writeq.front(); + auto& job = writeq.q.front(); job.second(job.first.offset); - writeq.pop(); + writeq.q.pop_front(); } } @@ -381,11 +370,11 @@ void Connection::transmit(TCP::Packet_ptr packet) { rtx_start(); } bool Connection::can_send_one() { - return send_window() >= SMSS() and !writeq.empty(); + return send_window() >= SMSS() and !writeq.remaining_requests(); } bool Connection::can_send() { - return (usable_window() >= SMSS()) and !writeq.empty(); + return (usable_window() >= SMSS()) and !writeq.remaining_requests(); } void Connection::send_much() { @@ -549,7 +538,7 @@ void Connection::on_dup_ack() { if(limited_tx_) { // try to send one segment - if(cb.SND.WND >= SMSS() and (flight_size() <= cb.cwnd + 2*SMSS()) and !writeq.empty()) { + if(cb.SND.WND >= SMSS() and (flight_size() <= cb.cwnd + 2*SMSS()) and !writeq.remaining_requests()) { limited_tx(); } } From a3f5b51382ee0e60efcd71f24c78e19cb2c3d964 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Tue, 3 May 2016 00:39:53 +0200 Subject: [PATCH 255/311] fs: Return vector and error pair for sync ls --- api/fs/ext4.hpp | 4 +- api/fs/fat.hpp | 10 +-- api/fs/filesystem.hpp | 11 +++- src/fs/fat.cpp | 6 +- src/fs/fat_async.cpp | 2 +- src/fs/fat_sync.cpp | 92 +++++++++++++-------------- src/kernel/terminal_disk.cpp | 9 ++- test/fat/fat16.cpp | 9 ++- test/fat/fat32.cpp | 119 +++++++++++++++++------------------ 9 files changed, 131 insertions(+), 131 deletions(-) diff --git a/api/fs/ext4.hpp b/api/fs/ext4.hpp index b2d1a5678d..6ff0b2839c 100644 --- a/api/fs/ext4.hpp +++ b/api/fs/ext4.hpp @@ -49,8 +49,8 @@ namespace fs virtual void mount(uint64_t lba, uint64_t size, on_mount_func on_mount) override; // path is a path in the mounted filesystem - virtual void ls(const std::string& path, on_ls_func) override; - virtual error_t ls(const std::string& path, dirvec_t e) override; + virtual void ls(const std::string& path, on_ls_func) override; + virtual List ls(const std::string& path) override; // read an entire file into a buffer, then call on_read virtual void readFile(const std::string&, on_read_func) override; diff --git a/api/fs/fat.hpp b/api/fs/fat.hpp index b7f7d7af8c..9e393b547c 100644 --- a/api/fs/fat.hpp +++ b/api/fs/fat.hpp @@ -35,8 +35,8 @@ namespace fs virtual void mount(uint64_t lba, uint64_t size, on_mount_func on_mount) override; // path is a path in the mounted filesystem - virtual void ls (const std::string& path, on_ls_func) override; - virtual error_t ls(const std::string& path, dirvec_t) override; + virtual void ls (const std::string& path, on_ls_func) override; + virtual List ls(const std::string& path) override; // read an entire file into a buffer, then call on_read virtual void readFile(const std::string&, on_read_func) override; @@ -179,15 +179,15 @@ namespace fs // return a list of entries from directory entries at @sector typedef std::function on_internal_ls_func; void int_ls(uint32_t sector, dirvec_t, on_internal_ls_func); - bool int_dirent(uint32_t sector, const void* data, dirvec_t); + bool int_dirent(uint32_t sector, const void* data, dirvector&); // tree traversal typedef std::function cluster_func; // async tree traversal void traverse(std::shared_ptr path, cluster_func callback); // sync version - error_t traverse(Path path, dirvec_t); - error_t int_ls(uint32_t sector, dirvec_t); + error_t traverse(Path path, dirvector&); + error_t int_ls(uint32_t sector, dirvector&); // device we can read and write sectors to hw::IDiskDevice& device; diff --git a/api/fs/filesystem.hpp b/api/fs/filesystem.hpp index f7a66a52bf..b18d46c727 100644 --- a/api/fs/filesystem.hpp +++ b/api/fs/filesystem.hpp @@ -109,13 +109,18 @@ namespace fs { uint32_t attrib; int64_t timestamp; }; //< struct Dirent - + + struct List { + error_t error; + dirvector entries; + }; + /** Mount this filesystem with LBA at @base_sector */ virtual void mount(uint64_t lba, uint64_t size, on_mount_func on_mount) = 0; /** @param path: Path in the mounted filesystem */ - virtual void ls(const std::string& path, on_ls_func) = 0; - virtual error_t ls(const std::string& path, dirvec_t e) = 0; + virtual void ls(const std::string& path, on_ls_func) = 0; + virtual List ls(const std::string& path) = 0; /** Read an entire file into a buffer, then call on_read */ virtual void readFile(const std::string&, on_read_func) = 0; diff --git a/src/fs/fat.cpp b/src/fs/fat.cpp index 585a6fb483..1b1719f96c 100644 --- a/src/fs/fat.cpp +++ b/src/fs/fat.cpp @@ -172,7 +172,7 @@ namespace fs }); } - bool FAT::int_dirent(uint32_t sector, const void* data, dirvec_t dirents) { + bool FAT::int_dirent(uint32_t sector, const void* data, dirvector& dirents) { auto* root = (cl_dir*) data; bool found_last = false; @@ -237,7 +237,7 @@ namespace fs std::string dirname(final_name, final_count); dirname = trim_right_copy(dirname); - dirents->emplace_back( + dirents.emplace_back( D->type(), dirname, D->dir_cluster(root_cluster), @@ -253,7 +253,7 @@ namespace fs std::string dirname((char*) D->shortname, 11); dirname = trim_right_copy(dirname); - dirents->emplace_back( + dirents.emplace_back( D->type(), dirname, D->dir_cluster(root_cluster), diff --git a/src/fs/fat_async.cpp b/src/fs/fat_async.cpp index a037543d9d..32e8de28d8 100644 --- a/src/fs/fat_async.cpp +++ b/src/fs/fat_async.cpp @@ -41,7 +41,7 @@ namespace fs } // parse entries in sector - bool done = int_dirent(sector, data.get(), dirents); + bool done = int_dirent(sector, data.get(), *dirents); if (done) // execute callback callback(no_error, dirents); diff --git a/src/fs/fat_sync.cpp b/src/fs/fat_sync.cpp index 790b367c32..b2f6aa725d 100644 --- a/src/fs/fat_sync.cpp +++ b/src/fs/fat_sync.cpp @@ -51,14 +51,14 @@ namespace fs path.pop_back(); // result directory entries are put into @dirents - auto dirents = new_shared_vector(); + dirvector dirents; auto err = traverse(path, dirents); if (unlikely(err)) return Buffer(err, buffer_t(), 0); // for now // find the matching filename in directory - for (auto& e : *dirents) + for (auto& e : dirents) if (unlikely(e.name() == filename)) { // read this file return read(e, 0, e.size); @@ -67,10 +67,10 @@ namespace fs return Buffer({ error_t::E_NOENT, filename }, buffer_t(), 0); } // readFile() - error_t FAT::int_ls(uint32_t sector, dirvec_t ents) + error_t FAT::int_ls(uint32_t sector, dirvector& ents) { bool done = false; - while (!done) { + do { // read sector sync buffer_t data = device.read_sync(sector); if (unlikely(!data)) @@ -79,64 +79,64 @@ namespace fs done = int_dirent(sector, data.get(), ents); // go to next sector until done sector++; - } + } while (!done); return no_error; } - error_t FAT::traverse(Path path, dirvec_t ents) + error_t FAT::traverse(Path path, dirvector& ents) { // start with root dir uint32_t cluster = 0; - // directory entries are read into this - auto dirents = new_shared_vector(); Dirent found(INVALID_ENTITY); - while (!path.empty()) - { - uint32_t S = this->cl_to_sector(cluster); - dirents->clear(); // mui importante - // sync read entire directory - auto err = int_ls(S, dirents); - if (unlikely(err)) return err; - // the name we are looking for - std::string name = path.front(); - path.pop_front(); - - // check for matches in dirents - for (auto& e : *dirents) - if (unlikely(e.name() == name)) { - // go to this directory, unless its the last name - debug("traverse_sync: Found match for %s", name.c_str()); - // enter the matching directory - debug("\t\t cluster: %lu\n", e.block); - // only follow if the name is a directory - if (e.type() == DIR) { - found = e; - break; - } - else { - // not dir = error, for now - return { error_t::E_NOTDIR, "Cannot list non-directory" }; - } - } // for (ents) + while (!path.empty()) { - // validate result - if (found.type() == INVALID_ENTITY) { - debug("traverse_sync: NO MATCH for %s\n", name.c_str()); - return { error_t::E_NOENT, name }; + uint32_t S = this->cl_to_sector(cluster); + ents.clear(); // mui importante + // sync read entire directory + auto err = int_ls(S, ents); + if (unlikely(err)) return err; + // the name we are looking for + std::string name = path.front(); + path.pop_front(); + + // check for matches in dirents + for (auto& e : ents) + if (unlikely(e.name() == name)) { + // go to this directory, unless its the last name + debug("traverse_sync: Found match for %s", name.c_str()); + // enter the matching directory + debug("\t\t cluster: %lu\n", e.block); + // only follow if the name is a directory + if (e.type() == DIR) { + found = e; + break; } - // set next cluster - cluster = found.block; + else { + // not dir = error, for now + return { error_t::E_NOTDIR, "Cannot list non-directory" }; + } + } // for (ents) + + // validate result + if (found.type() == INVALID_ENTITY) { + debug("traverse_sync: NO MATCH for %s\n", name.c_str()); + return { error_t::E_NOENT, name }; } + // set next cluster + cluster = found.block; + } uint32_t S = this->cl_to_sector(cluster); // read result directory entries into ents return int_ls(S, ents); } - error_t FAT::ls(const std::string& strpath, dirvec_t ents) + FAT::List FAT::ls(const std::string& strpath) { - return traverse(strpath, ents); + dirvector ents; + auto err = traverse(strpath, ents); + return { err, ents }; } FAT::Dirent FAT::stat(const std::string& strpath) @@ -153,14 +153,14 @@ namespace fs path.pop_back(); // result directory entries are put into @dirents - auto dirents = std::make_shared> (); + dirvector dirents; auto err = traverse(path, dirents); if (unlikely(err)) return Dirent(INVALID_ENTITY); // for now // find the matching filename in directory - for (auto& e : *dirents) + for (auto& e : dirents) if (unlikely(e.name() == filename)) { // return this directory entry return e; diff --git a/src/kernel/terminal_disk.cpp b/src/kernel/terminal_disk.cpp index ad2446fd8e..9abe132e9b 100644 --- a/src/kernel/terminal_disk.cpp +++ b/src/kernel/terminal_disk.cpp @@ -81,18 +81,17 @@ void Terminal::add_disk_commands(Disk_ptr disk) std::string target = path.to_string(); auto& fs = disk->fs(); - auto vec = fs::new_shared_vector(); - auto err = fs.ls(target, vec); - if (!err) + auto list = fs.ls(target); + if (!list.error) { this->write("%s \t%s \t%s \t%s\r\n", "Name", "Size", "Type", "Sector"); - for (auto& ent : *vec) + for (auto& ent : list.entries) { this->write("%s \t%llu \t%s \t%llu\r\n", ent.name().c_str(), ent.size, ent.type_string().c_str(), ent.block); } - this->write("Total %u\r\n", vec->size()); + this->write("Total %u\r\n", list.entries.size()); return 0; } else diff --git a/test/fat/fat16.cpp b/test/fat/fat16.cpp index 2ce4bc481f..61b5bdd5ff 100644 --- a/test/fat/fat16.cpp +++ b/test/fat/fat16.cpp @@ -45,13 +45,12 @@ void Service::start() auto& fs = disk->fs(); printf("\t\t%s filesystem\n", fs.name().c_str()); - auto vec = fs::new_shared_vector(); - err = fs.ls("/", vec); - CHECKSERT(!err, "List root directory"); + auto list = fs.ls("/"); + CHECKSERT(!list.error, "List root directory"); - CHECKSERT(vec->size() == 1, "Exactly one ent in root dir"); + CHECKSERT(list.entries.size() == 1, "Exactly one ent in root dir"); - auto& e = vec->at(0); + auto& e = list.entries.at(0); CHECKSERT(e.is_file(), "Ent is a file"); CHECKSERT(e.name() == "banana.txt", "Ents name is 'banana.txt'"); diff --git a/test/fat/fat32.cpp b/test/fat/fat32.cpp index 9a501dd006..3402c05fda 100644 --- a/test/fat/fat32.cpp +++ b/test/fat/fat32.cpp @@ -44,73 +44,70 @@ void Service::start() // auto-mount filesystem disk->mount(disk->MBR, - [] (fs::error_t err) - { - CHECKSERT(!err, "Filesystem auto-mounted"); + [] (fs::error_t err) + { + CHECKSERT(!err, "Filesystem auto-mounted"); - auto& fs = disk->fs(); - printf("\t\t%s filesystem\n", fs.name().c_str()); + auto& fs = disk->fs(); + printf("\t\t%s filesystem\n", fs.name().c_str()); - auto vec = fs::new_shared_vector(); - err = fs.ls("/", vec); - CHECKSERT(!err, "List root directory"); + auto list = fs.ls("/"); + CHECKSERT(!list.error, "List root directory"); - CHECKSERT(vec->size() == 2, "Exactly two ents in root dir"); + CHECKSERT(list.entries.size() == 2, "Exactly two ents in root dir"); - auto& e = vec->at(0); - CHECKSERT(e.is_file(), "Ent is a file"); - CHECKSERT(e.name() == "banana.txt", "Ents name is 'banana.txt'"); - }); + auto& e = list.entries.at(0); + CHECKSERT(e.is_file(), "Ent is a file"); + CHECKSERT(e.name() == "banana.txt", "Ents name is 'banana.txt'"); + }); // re-mount on VBR1 disk->mount(disk->VBR1, - [] (fs::error_t err) - { - CHECK(!err, "Filesystem mounted on VBR1"); - assert(!err); - - auto& fs = disk->fs(); - auto ent = fs.stat("/banana.txt"); - CHECKSERT(ent.is_valid(), "Stat file in root dir"); - CHECKSERT(ent.is_file(), "Entity is file"); - CHECKSERT(!ent.is_dir(), "Entity is not directory"); - CHECKSERT(ent.name() == "banana.txt", "Name is 'banana.txt'"); - - ent = fs.stat("/dir1/dir2/dir3/dir4/dir5/dir6/banana.txt"); - CHECKSERT(ent.is_valid(), "Stat file in deep dir"); - CHECKSERT(ent.is_file(), "Entity is file"); - CHECKSERT(!ent.is_dir(), "Entity is not directory"); - - CHECKSERT(ent.name() == "banana.txt", "Name is 'banana.txt'"); - - printf("%s\n", internal_banana.c_str()); - - // asynch file reading test - fs.read(ent, 0, ent.size, - [&fs] (fs::error_t err, fs::buffer_t buf, uint64_t len) - { - CHECKSERT(!err, "read: Read 'banana.txt' asynchronously"); - if (err) - { - panic("Failed to read file async"); - } - - std::string banana((char*) buf.get(), len); - CHECKSERT(banana == internal_banana, "Correct banana #1"); - - fs.readFile("/banana.txt", - [&fs] (fs::error_t err, fs::buffer_t buf, uint64_t len) - { - CHECKSERT(!err, "readFile: Read 'banana.txt' asynchronously"); - if (err) - { - panic("Failed to read file async"); - } - - std::string banana((char*) buf.get(), len); - CHECKSERT(banana == internal_banana, "Correct banana #2"); - }); - }); - }); + [] (fs::error_t err) + { + CHECK(!err, "Filesystem mounted on VBR1"); + assert(!err); + + auto& fs = disk->fs(); + auto ent = fs.stat("/banana.txt"); + CHECKSERT(ent.is_valid(), "Stat file in root dir"); + CHECKSERT(ent.is_file(), "Entity is file"); + CHECKSERT(!ent.is_dir(), "Entity is not directory"); + CHECKSERT(ent.name() == "banana.txt", "Name is 'banana.txt'"); + + ent = fs.stat("/dir1/dir2/dir3/dir4/dir5/dir6/banana.txt"); + CHECKSERT(ent.is_valid(), "Stat file in deep dir"); + CHECKSERT(ent.is_file(), "Entity is file"); + CHECKSERT(!ent.is_dir(), "Entity is not directory"); + + CHECKSERT(ent.name() == "banana.txt", "Name is 'banana.txt'"); + + printf("%s\n", internal_banana.c_str()); + + // asynch file reading test + fs.read(ent, 0, ent.size, + [&fs] (fs::error_t err, fs::buffer_t buf, uint64_t len) + { + CHECKSERT(!err, "read: Read 'banana.txt' asynchronously"); + if (err) { + panic("Failed to read file (async)"); + } + + std::string banana((char*) buf.get(), len); + CHECKSERT(banana == internal_banana, "Correct banana #1"); + + fs.readFile("/banana.txt", + [&fs] (fs::error_t err, fs::buffer_t buf, uint64_t len) + { + CHECKSERT(!err, "readFile: Read 'banana.txt' asynchronously"); + if (err) { + panic("Failed to read file (async)"); + } + + std::string banana((char*) buf.get(), len); + CHECKSERT(banana == internal_banana, "Correct banana #2"); + }); + }); + }); INFO("FAT32", "SUCCESS"); } From b74d75c05ef5702d1e5f7ff72d51affbc2b8fb96 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Tue, 3 May 2016 00:49:29 +0200 Subject: [PATCH 256/311] fs: Add Dirent only versions for ls --- api/fs/fat.hpp | 2 ++ api/fs/filesystem.hpp | 2 ++ src/fs/fat_async.cpp | 16 ++++++++++++++++ src/fs/fat_sync.cpp | 12 ++++++++++++ 4 files changed, 32 insertions(+) diff --git a/api/fs/fat.hpp b/api/fs/fat.hpp index 9e393b547c..981a473824 100644 --- a/api/fs/fat.hpp +++ b/api/fs/fat.hpp @@ -36,7 +36,9 @@ namespace fs // path is a path in the mounted filesystem virtual void ls (const std::string& path, on_ls_func) override; + virtual void ls (const Dirent& entry, on_ls_func) override; virtual List ls(const std::string& path) override; + virtual List ls(const Dirent&) override; // read an entire file into a buffer, then call on_read virtual void readFile(const std::string&, on_read_func) override; diff --git a/api/fs/filesystem.hpp b/api/fs/filesystem.hpp index b18d46c727..0583a6d258 100644 --- a/api/fs/filesystem.hpp +++ b/api/fs/filesystem.hpp @@ -120,7 +120,9 @@ namespace fs { /** @param path: Path in the mounted filesystem */ virtual void ls(const std::string& path, on_ls_func) = 0; + virtual void ls(const Dirent& entry, on_ls_func) = 0; virtual List ls(const std::string& path) = 0; + virtual List ls(const Dirent&) = 0; /** Read an entire file into a buffer, then call on_read */ virtual void readFile(const std::string&, on_read_func) = 0; diff --git a/src/fs/fat_async.cpp b/src/fs/fat_async.cpp index 32e8de28d8..2186167f35 100644 --- a/src/fs/fat_async.cpp +++ b/src/fs/fat_async.cpp @@ -135,6 +135,22 @@ namespace fs on_ls(error, dirents); }); } + void FAT::ls(const Dirent& ent, on_ls_func on_ls) + { + auto dirents = std::make_shared (); + // verify ent is a directory + if (!ent.is_valid() || !ent.is_dir()) { + on_ls( { error_t::E_NOTDIR, ent.name() }, dirents ); + return; + } + // convert cluster to sector + uint32_t S = this->cl_to_sector(ent.block); + // read result directory entries into ents + int_ls(S, dirents, + [on_ls] (error_t err, dirvec_t entries) { + on_ls( err, entries ); + }); + } void FAT::read(const Dirent& ent, uint64_t pos, uint64_t n, on_read_func callback) { diff --git a/src/fs/fat_sync.cpp b/src/fs/fat_sync.cpp index b2f6aa725d..03a0d36ae2 100644 --- a/src/fs/fat_sync.cpp +++ b/src/fs/fat_sync.cpp @@ -138,6 +138,18 @@ namespace fs auto err = traverse(strpath, ents); return { err, ents }; } + FAT::List FAT::ls(const Dirent& ent) + { + dirvector ents; + // verify ent is a directory + if (!ent.is_valid() || !ent.is_dir()) + return { { error_t::E_NOTDIR, ent.name() }, ents }; + // convert cluster to sector + uint32_t S = this->cl_to_sector(ent.block); + // read result directory entries into ents + auto err = int_ls(S, ents); + return { err, ents }; + } FAT::Dirent FAT::stat(const std::string& strpath) { From 839652a2148b88210e2e13bd3cd9264836675833 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Tue, 3 May 2016 10:38:38 +0200 Subject: [PATCH 257/311] test: updated vmrunner to not exit on missing kvm --- test/vmrunner.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/test/vmrunner.py b/test/vmrunner.py index 9df9752427..38c770fa23 100644 --- a/test/vmrunner.py +++ b/test/vmrunner.py @@ -92,13 +92,15 @@ def net_arg(self, if_type = "virtio", if_name = "net0", mac="c0:01:0a:00:00:2a") def kvm_present(self): command = "egrep -m 1 '^flags.*(vmx|svm)' /proc/cpuinfo" - if not subprocess.check_output(command, shell = True): - print " KVM OFF" - return False - else: + try: + subprocess.check_output(command, shell = True) print " KVM ON" return True + except Exception as err: + print " KVM OFF" + return False + def boot(self): self._out_sign = "<" + type(self).__name__ + ">" print self._out_sign,"booting ",self._config["image"] @@ -182,6 +184,9 @@ def on_panic(self, callback): def on_timeout(self, callback): self._on_timeout = callback + def readline(self): + return self._hyper.readline() + def boot(self, timeout = None): # Start the timeout thread From d3b663aed525df770a3425536fca27927f01cdda Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Tue, 3 May 2016 11:24:14 +0200 Subject: [PATCH 258/311] make: Add stack-protector --- src/Makefile | 2 +- src/seed/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Makefile b/src/Makefile index 5da97bc26e..56e97d6093 100644 --- a/src/Makefile +++ b/src/Makefile @@ -11,7 +11,7 @@ INSTALL = $(INCLUDEOS_INSTALL) # stackrealign is needed to guarantee 16-byte stack alignment for SSE # the compiler seems to be really dumb in this regard, creating a misaligned stack left and right -CAPABS_COMMON = -mstackrealign -msse3 +CAPABS_COMMON = -mstackrealign -fstack-protector -msse3 CAPABS = $(CAPABS_COMMON) -O2 -DNO_DEBUG=1 -DOS_TERMINATE_ON_CONTRACT_VIOLATION WARNS = -Wall -Wextra #-pedantic diff --git a/src/seed/Makefile b/src/seed/Makefile index 8f8a231826..60fa28d7fc 100644 --- a/src/seed/Makefile +++ b/src/seed/Makefile @@ -16,7 +16,7 @@ INSTALL = $(INCLUDEOS_INSTALL) # Compiler and linker options ################################################### -CAPABS_COMMON = -mstackrealign -msse3 +CAPABS_COMMON = -mstackrealign -fstack-protector -msse3 WARNS = -Wall -Wextra #-pedantic DEBUG_OPTS = -ggdb3 -v From 82c51051fdded9022ee8c2b3cb71f95871f4a89e Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Tue, 3 May 2016 12:09:15 +0200 Subject: [PATCH 259/311] cabi: Enable stack protector --- src/Makefile | 6 +++--- src/crt/c_abi.c | 11 +++++++++++ src/kernel/kernel_start.cpp | 10 +++------- src/seed/Makefile | 4 ++-- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/Makefile b/src/Makefile index 56e97d6093..a56b5a74ee 100644 --- a/src/Makefile +++ b/src/Makefile @@ -11,7 +11,7 @@ INSTALL = $(INCLUDEOS_INSTALL) # stackrealign is needed to guarantee 16-byte stack alignment for SSE # the compiler seems to be really dumb in this regard, creating a misaligned stack left and right -CAPABS_COMMON = -mstackrealign -fstack-protector -msse3 +CAPABS_COMMON = -mstackrealign -fstack-protector-strong -msse3 CAPABS = $(CAPABS_COMMON) -O2 -DNO_DEBUG=1 -DOS_TERMINATE_ON_CONTRACT_VIOLATION WARNS = -Wall -Wextra #-pedantic @@ -49,8 +49,8 @@ CPPOPTS = -target i686-elf INCLUDES = -I../api/sys -I$(INSTALL)/libcxx/include -I$(INC_NEWLIB) -Iinclude -I../api -I../mod/GSL/include # CINCLUDES = -I../api/sys -I$(INC_NEWLIB) -Iinclude -I../api # -CCOPTS += $(CAPABS) $(WARNS) -c -m32 -fno-stack-protector -fno-builtin -march=i686 $(CINCLUDES) -CPPOPTS += $(CAPABS) $(WARNS) -c -m32 -std=c++14 -fno-stack-protector $(INCLUDES) -D_LIBCPP_HAS_NO_THREADS=1 -DOS_VERSION="\"$(shell git describe --dirty)\"" +CCOPTS += $(CAPABS) $(WARNS) -c -m32 -march=i686 $(CINCLUDES) +CPPOPTS += $(CAPABS) $(WARNS) -c -m32 -std=c++14 $(INCLUDES) -D_LIBCPP_HAS_NO_THREADS=1 -DOS_VERSION="\"$(shell git describe --dirty)\"" LDOPTS = -nostdlib -melf_i386 -N --eh-frame-hdr --script=linker.ld #-flto diff --git a/src/crt/c_abi.c b/src/crt/c_abi.c index 4a3666c1da..ec7a313a1f 100644 --- a/src/crt/c_abi.c +++ b/src/crt/c_abi.c @@ -34,6 +34,10 @@ __FILE* stdin; __FILE* stdout; __FILE* stderr; +// stack-protector guard +extern uintptr_t __stack_chk_guard; +extern void panic(const char* why) __attribute__((noreturn)); + void _init_c_runtime() { // Initialize .bss section @@ -70,6 +74,13 @@ void _init_c_runtime() // global/static objects should never be destructed here, so ignore this void* __dso_handle; +// stack-protector +__attribute__((noreturn)) +void __stack_chk_fail(void) +{ + panic("Stack protector: Canary modified"); +} + // old function result system int errno = 0; int* __errno_location(void) diff --git a/src/kernel/kernel_start.cpp b/src/kernel/kernel_start.cpp index 03de9092ef..a067d47379 100644 --- a/src/kernel/kernel_start.cpp +++ b/src/kernel/kernel_start.cpp @@ -16,13 +16,12 @@ // limitations under the License. //#define DEBUG -#include #include #include -#include extern "C" { + uintptr_t __stack_chk_guard = 23453; void _init_c_runtime(); // enables Streaming SIMD Extensions @@ -38,18 +37,15 @@ extern "C" __asm__ ("mov %eax, %cr4"); } - void _start(void) - { - __asm__ volatile ("cli"); - + void _start(void) { // enable SSE extensions bitmask in CR4 register enableSSE(); // Initialize stack-unwinder, call global constructors etc. _init_c_runtime(); + assert(__stack_chk_guard == 23453); // Initialize some OS functionality OS::start(); - } } diff --git a/src/seed/Makefile b/src/seed/Makefile index 60fa28d7fc..f8e346bd34 100644 --- a/src/seed/Makefile +++ b/src/seed/Makefile @@ -16,7 +16,7 @@ INSTALL = $(INCLUDEOS_INSTALL) # Compiler and linker options ################################################### -CAPABS_COMMON = -mstackrealign -fstack-protector -msse3 +CAPABS_COMMON = -mstackrealign -fstack-protector-all -msse3 WARNS = -Wall -Wextra #-pedantic DEBUG_OPTS = -ggdb3 -v @@ -47,7 +47,7 @@ all: CAPABS = $(CAPABS_COMMON) -O2 debug: CAPABS = $(CAPABS_COMMON) -O0 stripped: CAPABS = $(CAPABS_COMMON) -Oz -CPPOPTS = $(CAPABS) $(WARNS) -c -m32 -std=c++14 -fno-stack-protector $(INCLUDES) -D_LIBCPP_HAS_NO_THREADS=1 +CPPOPTS = $(CAPABS) $(WARNS) -c -m32 -std=c++14 $(INCLUDES) -D_LIBCPP_HAS_NO_THREADS=1 LDOPTS = -nostdlib -melf_i386 -N --script=$(INSTALL)/linker.ld # Objects From ad1d00c04907844bbaac005569e600fc2722cebb Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Tue, 3 May 2016 12:40:42 +0200 Subject: [PATCH 260/311] make: Generate random number for stack protector --- src/Makefile | 3 ++- src/kernel/kernel_start.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Makefile b/src/Makefile index a56b5a74ee..d94024b65e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -9,9 +9,10 @@ endif # shorter name INSTALL = $(INCLUDEOS_INSTALL) +STACK_PROTECTOR_VALUE=$(shell awk 'BEGIN{print rand()*65536}') # stackrealign is needed to guarantee 16-byte stack alignment for SSE # the compiler seems to be really dumb in this regard, creating a misaligned stack left and right -CAPABS_COMMON = -mstackrealign -fstack-protector-strong -msse3 +CAPABS_COMMON = -mstackrealign -fstack-protector-strong -msse3 -D_STACK_GUARD_VALUE_=$(STACK_PROTECTOR_VALUE) CAPABS = $(CAPABS_COMMON) -O2 -DNO_DEBUG=1 -DOS_TERMINATE_ON_CONTRACT_VIOLATION WARNS = -Wall -Wextra #-pedantic diff --git a/src/kernel/kernel_start.cpp b/src/kernel/kernel_start.cpp index a067d47379..8ea1193e74 100644 --- a/src/kernel/kernel_start.cpp +++ b/src/kernel/kernel_start.cpp @@ -21,7 +21,7 @@ extern "C" { - uintptr_t __stack_chk_guard = 23453; + uintptr_t __stack_chk_guard = (uintptr_t) _STACK_GUARD_VALUE_; void _init_c_runtime(); // enables Streaming SIMD Extensions From 6f6a84716da7dd819e3a677b63583c0efc86b677 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Tue, 3 May 2016 12:43:30 +0200 Subject: [PATCH 261/311] tcp: work on write queue --- api/net/tcp.hpp | 44 ++++++++++++++++++++++--------- src/net/tcp.cpp | 2 +- src/net/tcp_connection.cpp | 26 +++++++++--------- src/net/tcp_connection_states.cpp | 4 +-- 4 files changed, 48 insertions(+), 28 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index d4798091a0..51c300247c 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -28,6 +28,7 @@ #include // timer duration #include // enable_shared_from_this #include +#include inline unsigned round_up(unsigned n, unsigned div) { assert(n); @@ -594,21 +595,22 @@ namespace net { */ struct WriteQueue { - std::deque q; + std::list q; - std::deque::iterator current; + std::list::iterator current; - WriteQueue() : q(), current(q.begin()) {} + WriteQueue() : q(), current(q.end()) {} void acknowledge(size_t bytes) { while(bytes and !q.empty()) { - auto& buf = q.front()->first; + auto& buf = q.front().first; bytes -= buf.acknowledge(bytes); - + printf(" Buf offset=%u rem=%u ack=%u\n", + buf.offset, buf.remaining, buf.acknowledged); if(buf.done()) { - buf.pop_front(); + q.pop_front(); } } } @@ -620,25 +622,43 @@ namespace net { { return q.size(); } bool remaining_requests() const - { return !q.empty() and q.back().remaining; } + { return !q.empty() and q.back().first.remaining; } const WriteBuffer& nxt() - { return current->first; } + { auto& buf = current->first; + printf(" Buf offset=%u rem=%u ack=%u\n", + buf.offset, buf.remaining, buf.acknowledged); + return current->first; } const WriteBuffer& una() - { return q.front()->first; } + { return q.front().first; } void advance(size_t bytes) { auto& buf = current->first; buf.advance(bytes); + printf(" Buf offset=%u rem=%u ack=%u\n", + buf.offset, buf.remaining, buf.acknowledged); if(!buf.remaining) { current->second(buf.offset); current++; } } + + void push_back(const WriteRequest& wr) { + printf(" Adding WR \n"); + auto& buf = current->first; + printf(" Buf offset=%u rem=%u ack=%u\n", + buf.offset, buf.remaining, buf.acknowledged); + bool update = (current == q.end()); + q.push_back(wr); + if(update) { + current = --q.end(); + printf(" Updated iter \n"); + } + } }; /* @@ -1394,7 +1414,7 @@ namespace net { Returns if the connection has a doable write job. */ inline bool has_doable_job() { - return !writeq.remaining_requests() and usable_window() >= SMSS(); + return writeq.remaining_requests() and usable_window() >= SMSS(); } /* @@ -1498,7 +1518,7 @@ namespace net { bool can_send(); void send_much(); - size_t fill_packet(Packet_ptr, const char*, size_t); + size_t fill_packet(Packet_ptr, const char*, size_t, Seq); //void send_ack(TCP::Packet_ptr = nullptr); /// Congestion Control [RFC 5681] /// @@ -1805,7 +1825,7 @@ namespace net { std::deque writeq; - std::vector used_ports; + std::vector used_ports; /* Settings diff --git a/src/net/tcp.cpp b/src/net/tcp.cpp index bbda00d2d9..ef7f3aa113 100644 --- a/src/net/tcp.cpp +++ b/src/net/tcp.cpp @@ -48,7 +48,7 @@ TCP::TCP(IPStack& inet) : */ TCP::Connection& TCP::bind(Port port) { // Already a listening socket. - if(port_in_use(port)) { + if(listeners_.find(port) != listeners_.end()) { throw TCPException{"Port is already taken."}; } auto& connection = (listeners_.emplace(port, Connection{*this, port})).first->second; diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index 80f282796f..959ea922d8 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -101,15 +101,14 @@ size_t Connection::receive(const uint8_t* data, size_t n, bool PUSH) { void Connection::write(WriteBuffer buffer, WriteCallback callback) { try { - state_->is_writeable(); + // try to write auto written = state_->send(*this, buffer); - buffer.advance(written); - - if(!buffer.remaining) { - callback(buffer.offset); - } - else { - writeq.emplace(buffer, callback); + // put request in line + writeq.push_back({buffer, callback}); + // if data was written, advance + if(written) { + printf(" Wrote %u.\n", written); + writeq.advance(written); } } catch(TCPException err) { @@ -213,7 +212,7 @@ void Connection::make_flight_ready(Packet_ptr packet) { }*/ void Connection::writeq_push() { - while(!writeq.remaining_requests()) { + while(writeq.remaining_requests()) { auto& buf = writeq.nxt(); auto written = host_.send(shared_from_this(), (char*)buf.pos(), buf.remaining); writeq.advance(written); @@ -370,11 +369,11 @@ void Connection::transmit(TCP::Packet_ptr packet) { rtx_start(); } bool Connection::can_send_one() { - return send_window() >= SMSS() and !writeq.remaining_requests(); + return send_window() >= SMSS() and writeq.remaining_requests(); } bool Connection::can_send() { - return (usable_window() >= SMSS()) and !writeq.remaining_requests(); + return (usable_window() >= SMSS()) and writeq.remaining_requests(); } void Connection::send_much() { @@ -435,6 +434,7 @@ bool Connection::handle_ack(TCP::Packet_ptr in) { size_t bytes_acked = in->ack() - cb.SND.UNA; cb.SND.UNA = in->ack(); + writeq.acknowledge(bytes_acked); // ack everything in rtx queue rtx_ack(in->ack()); @@ -538,7 +538,7 @@ void Connection::on_dup_ack() { if(limited_tx_) { // try to send one segment - if(cb.SND.WND >= SMSS() and (flight_size() <= cb.cwnd + 2*SMSS()) and !writeq.remaining_requests()) { + if(cb.SND.WND >= SMSS() and (flight_size() <= cb.cwnd + 2*SMSS()) and writeq.remaining_requests()) { limited_tx(); } } @@ -633,7 +633,7 @@ void Connection::rtx_start() { [this, i, rto] { rtx_timer.active = false; - debug(" %i Timed out (%f). rt_q: %u, i: %u rt_i: %u\n", + printf(" %i Timed out (%f). rt_q: %u, i: %u rt_i: %u\n", local_port_, rto, rtx_q.size(), i, rtx_timer.i); rtx_timeout(); }); diff --git a/src/net/tcp_connection_states.cpp b/src/net/tcp_connection_states.cpp index 935d04c2af..080b0744cd 100644 --- a/src/net/tcp_connection_states.cpp +++ b/src/net/tcp_connection_states.cpp @@ -589,7 +589,7 @@ size_t Connection::SynReceived::send(Connection&, WriteBuffer&) { size_t Connection::Established::send(Connection& tcp, WriteBuffer& buffer) { // if nothing in queue, try to write directly - if(tcp.writeq.empty()) + if(!tcp.writeq.remaining_requests()) return tcp.send(buffer); return 0; @@ -597,7 +597,7 @@ size_t Connection::Established::send(Connection& tcp, WriteBuffer& buffer) { size_t Connection::CloseWait::send(Connection& tcp, WriteBuffer& buffer) { // if nothing in queue, try to write directly - if(tcp.writeq.empty()) + if(!tcp.writeq.remaining_requests()) return tcp.send(buffer); return 0; From df387730e65fea675ff275090353e988385287e4 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Tue, 3 May 2016 13:30:44 +0200 Subject: [PATCH 262/311] cabi: Implement stack-smasher self-test --- src/Makefile | 4 ++-- src/crt/c_abi.c | 2 +- src/kernel/kernel_start.cpp | 17 ++++++++++++++--- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/Makefile b/src/Makefile index d94024b65e..99ed68c1c6 100644 --- a/src/Makefile +++ b/src/Makefile @@ -9,10 +9,10 @@ endif # shorter name INSTALL = $(INCLUDEOS_INSTALL) -STACK_PROTECTOR_VALUE=$(shell awk 'BEGIN{print rand()*65536}') +STACK_PROTECTOR_VALUE=$(shell awk 'BEGIN{print int(rand()*65536)}') # stackrealign is needed to guarantee 16-byte stack alignment for SSE # the compiler seems to be really dumb in this regard, creating a misaligned stack left and right -CAPABS_COMMON = -mstackrealign -fstack-protector-strong -msse3 -D_STACK_GUARD_VALUE_=$(STACK_PROTECTOR_VALUE) +CAPABS_COMMON = -mstackrealign -fstack-protector-all -msse3 -D_STACK_GUARD_VALUE_=$(STACK_PROTECTOR_VALUE) CAPABS = $(CAPABS_COMMON) -O2 -DNO_DEBUG=1 -DOS_TERMINATE_ON_CONTRACT_VIOLATION WARNS = -Wall -Wextra #-pedantic diff --git a/src/crt/c_abi.c b/src/crt/c_abi.c index ec7a313a1f..f3a856af89 100644 --- a/src/crt/c_abi.c +++ b/src/crt/c_abi.c @@ -35,7 +35,7 @@ __FILE* stdout; __FILE* stderr; // stack-protector guard -extern uintptr_t __stack_chk_guard; +uintptr_t __stack_chk_guard = _STACK_GUARD_VALUE_; extern void panic(const char* why) __attribute__((noreturn)); void _init_c_runtime() diff --git a/src/kernel/kernel_start.cpp b/src/kernel/kernel_start.cpp index 8ea1193e74..5b8ad7704c 100644 --- a/src/kernel/kernel_start.cpp +++ b/src/kernel/kernel_start.cpp @@ -21,9 +21,9 @@ extern "C" { - uintptr_t __stack_chk_guard = (uintptr_t) _STACK_GUARD_VALUE_; + extern uintptr_t __stack_chk_guard; void _init_c_runtime(); - + // enables Streaming SIMD Extensions static void enableSSE(void) { @@ -37,13 +37,24 @@ extern "C" __asm__ ("mov %eax, %cr4"); } + __attribute__((noinline)) + static char stack_smasher(const char* src) { + char bullshit[16]; + + for (int i = -100; i < 100; i++) + strcpy(bullshit+i, src); + + return bullshit[15]; + } + void _start(void) { // enable SSE extensions bitmask in CR4 register enableSSE(); + //stack_smasher("1234567890 12345 hello world! test -.-"); + // Initialize stack-unwinder, call global constructors etc. _init_c_runtime(); - assert(__stack_chk_guard == 23453); // Initialize some OS functionality OS::start(); From 6121d10733a1aae122928fdca66bf993d85d9393 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Tue, 3 May 2016 14:16:31 +0200 Subject: [PATCH 263/311] fs: shared vector for sync ls --- api/fs/filesystem.hpp | 12 ++++++++---- src/Makefile | 2 +- src/fs/fat_async.cpp | 2 +- src/fs/fat_sync.cpp | 10 +++++----- src/kernel/kernel_start.cpp | 2 +- src/kernel/terminal_disk.cpp | 10 +++++----- src/util/async.cpp | 2 +- test/fat/fat16.cpp | 31 +++++++++++++++---------------- test/fat/fat32.cpp | 6 +++--- 9 files changed, 40 insertions(+), 37 deletions(-) diff --git a/api/fs/filesystem.hpp b/api/fs/filesystem.hpp index 0583a6d258..595de33c66 100644 --- a/api/fs/filesystem.hpp +++ b/api/fs/filesystem.hpp @@ -61,7 +61,7 @@ namespace fs { fname {n}, block {blk}, parent {pr}, - size {sz}, + size_ {sz}, attrib {attr}, timestamp {0} {} @@ -101,18 +101,22 @@ namespace fs { } //< switch (type) } + uint64_t size() const noexcept { + return size_; + } + Enttype ftype; std::string fname; uint64_t block; uint64_t parent; //< Parent's block# - uint64_t size; + uint64_t size_; uint32_t attrib; int64_t timestamp; }; //< struct Dirent struct List { - error_t error; - dirvector entries; + error_t error; + dirvec_t entries; }; /** Mount this filesystem with LBA at @base_sector */ diff --git a/src/Makefile b/src/Makefile index 99ed68c1c6..e62534af83 100644 --- a/src/Makefile +++ b/src/Makefile @@ -12,7 +12,7 @@ INSTALL = $(INCLUDEOS_INSTALL) STACK_PROTECTOR_VALUE=$(shell awk 'BEGIN{print int(rand()*65536)}') # stackrealign is needed to guarantee 16-byte stack alignment for SSE # the compiler seems to be really dumb in this regard, creating a misaligned stack left and right -CAPABS_COMMON = -mstackrealign -fstack-protector-all -msse3 -D_STACK_GUARD_VALUE_=$(STACK_PROTECTOR_VALUE) +CAPABS_COMMON = -mstackrealign -fstack-protector-all -fno-omit-frame-pointer -msse3 -D_STACK_GUARD_VALUE_=$(STACK_PROTECTOR_VALUE) CAPABS = $(CAPABS_COMMON) -O2 -DNO_DEBUG=1 -DOS_TERMINATE_ON_CONTRACT_VIOLATION WARNS = -Wall -Wextra #-pedantic diff --git a/src/fs/fat_async.cpp b/src/fs/fat_async.cpp index 2186167f35..f950f96bfb 100644 --- a/src/fs/fat_async.cpp +++ b/src/fs/fat_async.cpp @@ -210,7 +210,7 @@ namespace fs for (auto& ent : *dirents) { if (unlikely(ent.name() == filename)) { // read this file - read(ent, 0, ent.size, callback); + read(ent, 0, ent.size(), callback); return; } } diff --git a/src/fs/fat_sync.cpp b/src/fs/fat_sync.cpp index 03a0d36ae2..2ea45b8643 100644 --- a/src/fs/fat_sync.cpp +++ b/src/fs/fat_sync.cpp @@ -61,7 +61,7 @@ namespace fs for (auto& e : dirents) if (unlikely(e.name() == filename)) { // read this file - return read(e, 0, e.size); + return read(e, 0, e.size()); } // entry not found return Buffer({ error_t::E_NOENT, filename }, buffer_t(), 0); @@ -134,20 +134,20 @@ namespace fs FAT::List FAT::ls(const std::string& strpath) { - dirvector ents; - auto err = traverse(strpath, ents); + auto ents = std::make_shared (); + auto err = traverse(strpath, *ents); return { err, ents }; } FAT::List FAT::ls(const Dirent& ent) { - dirvector ents; + auto ents = std::make_shared (); // verify ent is a directory if (!ent.is_valid() || !ent.is_dir()) return { { error_t::E_NOTDIR, ent.name() }, ents }; // convert cluster to sector uint32_t S = this->cl_to_sector(ent.block); // read result directory entries into ents - auto err = int_ls(S, ents); + auto err = int_ls(S, *ents); return { err, ents }; } diff --git a/src/kernel/kernel_start.cpp b/src/kernel/kernel_start.cpp index 5b8ad7704c..b86d4ad2eb 100644 --- a/src/kernel/kernel_start.cpp +++ b/src/kernel/kernel_start.cpp @@ -51,7 +51,7 @@ extern "C" // enable SSE extensions bitmask in CR4 register enableSSE(); - //stack_smasher("1234567890 12345 hello world! test -.-"); + stack_smasher("1234567890 12345 hello world! test -.-"); // Initialize stack-unwinder, call global constructors etc. _init_c_runtime(); diff --git a/src/kernel/terminal_disk.cpp b/src/kernel/terminal_disk.cpp index 9abe132e9b..3e1a0bf114 100644 --- a/src/kernel/terminal_disk.cpp +++ b/src/kernel/terminal_disk.cpp @@ -86,12 +86,12 @@ void Terminal::add_disk_commands(Disk_ptr disk) { this->write("%s \t%s \t%s \t%s\r\n", "Name", "Size", "Type", "Sector"); - for (auto& ent : list.entries) + for (auto& ent : *list.entries) { this->write("%s \t%llu \t%s \t%llu\r\n", - ent.name().c_str(), ent.size, ent.type_string().c_str(), ent.block); + ent.name().c_str(), ent.size(), ent.type_string().c_str(), ent.block); } - this->write("Total %u\r\n", list.entries.size()); + this->write("Total %u\r\n", list.entries->size()); return 0; } else @@ -113,7 +113,7 @@ void Terminal::add_disk_commands(Disk_ptr disk) this->write("%s \t%s \t%s \t%s\r\n", "Name", "Size", "Type", "Sector"); this->write("%s \t%llu \t%s \t%llu\r\n", - ent.name().c_str(), ent.size, ent.type_string().c_str(), ent.block); + ent.name().c_str(), ent.size(), ent.type_string().c_str(), ent.block); return 0; } else @@ -144,7 +144,7 @@ void Terminal::add_disk_commands(Disk_ptr disk) return 1; } // read file contents - auto buf = fs.read(ent, 0, ent.size); + auto buf = fs.read(ent, 0, ent.size()); if (!buf.buffer) { this->write("cat: '%s': I/O error\r\n", file.c_str()); diff --git a/src/util/async.cpp b/src/util/async.cpp index 36e3fc8879..cb4e38edee 100644 --- a/src/util/async.cpp +++ b/src/util/async.cpp @@ -43,7 +43,7 @@ void Async::disk_transfer( [next, disk, ent, write_func, callback, CHUNK_SIZE] (size_t pos) { // number of write calls necessary - const size_t writes = ent.size / CHUNK_SIZE; + const size_t writes = ent.size() / CHUNK_SIZE; // done condition if (pos >= writes) { diff --git a/test/fat/fat16.cpp b/test/fat/fat16.cpp index 61b5bdd5ff..d125b21ef5 100644 --- a/test/fat/fat16.cpp +++ b/test/fat/fat16.cpp @@ -48,9 +48,9 @@ void Service::start() auto list = fs.ls("/"); CHECKSERT(!list.error, "List root directory"); - CHECKSERT(list.entries.size() == 1, "Exactly one ent in root dir"); + CHECKSERT(list.entries->size() == 1, "Exactly one ent in root dir"); - auto& e = list.entries.at(0); + auto& e = list.entries->at(0); CHECKSERT(e.is_file(), "Ent is a file"); CHECKSERT(e.name() == "banana.txt", "Ents name is 'banana.txt'"); @@ -72,7 +72,7 @@ void Service::start() printf("%s\n", internal_banana.c_str()); // try reading banana-file - auto buf = fs.read(ent, 0, ent.size); + auto buf = fs.read(ent, 0, ent.size()); auto banana = buf.to_string(); CHECKSERT(banana == internal_banana, "Correct banana #1"); @@ -80,20 +80,19 @@ void Service::start() bool test = true; for (size_t i = 0; i < internal_banana.size(); i++) - { - // read one byte at a time - buf = fs.read(ent, i, 1); - /// @buf should evaluate to 'true' if its valid - CHECKSERT(buf, "Validate buffer"); - - // verify that it matches the same location in test-string - test = ((char) buf.buffer.get()[0] == internal_banana[i]); - if (!test) - { - printf("!! Random access read test failed on i = %u\n", i); - break; - } + { + // read one byte at a time + buf = fs.read(ent, i, 1); + /// @buf should evaluate to 'true' if its valid + CHECKSERT(buf, "Validate buffer"); + + // verify that it matches the same location in test-string + test = ((char) buf.buffer.get()[0] == internal_banana[i]); + if (!test) { + printf("!! Random access read test failed on i = %u\n", i); + break; } + } CHECKSERT(test, "Validate random access sync read"); buf = fs.readFile("/banana.txt"); diff --git a/test/fat/fat32.cpp b/test/fat/fat32.cpp index 3402c05fda..763a2f463d 100644 --- a/test/fat/fat32.cpp +++ b/test/fat/fat32.cpp @@ -54,9 +54,9 @@ void Service::start() auto list = fs.ls("/"); CHECKSERT(!list.error, "List root directory"); - CHECKSERT(list.entries.size() == 2, "Exactly two ents in root dir"); + CHECKSERT(list.entries->size() == 2, "Exactly two ents in root dir"); - auto& e = list.entries.at(0); + auto& e = list.entries->at(0); CHECKSERT(e.is_file(), "Ent is a file"); CHECKSERT(e.name() == "banana.txt", "Ents name is 'banana.txt'"); }); @@ -84,7 +84,7 @@ void Service::start() printf("%s\n", internal_banana.c_str()); // asynch file reading test - fs.read(ent, 0, ent.size, + fs.read(ent, 0, ent.size(), [&fs] (fs::error_t err, fs::buffer_t buf, uint64_t len) { CHECKSERT(!err, "read: Read 'banana.txt' asynchronously"); From d32434ede14e8832b23125be4c655dd9d6294d58 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Tue, 3 May 2016 14:21:24 +0200 Subject: [PATCH 264/311] fs: Fix disk test, disable stack smasher --- src/debug/test_disk.cpp | 4 ++-- src/kernel/kernel_start.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/debug/test_disk.cpp b/src/debug/test_disk.cpp index 4ab01fa38c..4f6189677b 100644 --- a/src/debug/test_disk.cpp +++ b/src/debug/test_disk.cpp @@ -71,11 +71,11 @@ void Service::start() // go through directory entries for (auto& e : *ents) { printf("%s: %s\t of size %llu bytes (CL: %llu)\n", - e.type_string().c_str(), e.name().c_str(), e.size, e.block); + e.type_string().c_str(), e.name().c_str(), e.size(), e.block); if (e.is_file()) { printf("*** Read file %s\n", e.name().c_str()); - disk->fs().read(e, 0, e.size, + disk->fs().read(e, 0, e.size(), [e] (fs::error_t err, fs::buffer_t buffer, size_t len) { if (err) { printf("Failed to read file %s!\n", diff --git a/src/kernel/kernel_start.cpp b/src/kernel/kernel_start.cpp index b86d4ad2eb..fe3cf58222 100644 --- a/src/kernel/kernel_start.cpp +++ b/src/kernel/kernel_start.cpp @@ -37,8 +37,8 @@ extern "C" __asm__ ("mov %eax, %cr4"); } - __attribute__((noinline)) - static char stack_smasher(const char* src) { + static char __attribute__((noinline)) + stack_smasher(const char* src) { char bullshit[16]; for (int i = -100; i < 100; i++) @@ -51,7 +51,7 @@ extern "C" // enable SSE extensions bitmask in CR4 register enableSSE(); - stack_smasher("1234567890 12345 hello world! test -.-"); + //stack_smasher("1234567890 12345 hello world! test -.-"); // Initialize stack-unwinder, call global constructors etc. _init_c_runtime(); From 75361fd93b0ddbd2026253c9f4ac42e340cf30a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Tue, 3 May 2016 15:47:20 +0200 Subject: [PATCH 265/311] tcp: no longer queues packets, but creates new on rtx --- api/net/tcp.hpp | 49 ++++------------ src/net/tcp_connection.cpp | 97 +++++++++++-------------------- src/net/tcp_connection_states.cpp | 12 ++-- test/tcp/service.cpp | 10 ++-- 4 files changed, 57 insertions(+), 111 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index 51c300247c..07b90ec62e 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -298,6 +298,8 @@ namespace net { inline TCP::Socket destination() const { return TCP::Socket{dst(), dst_port()}; } + inline TCP::Seq end() const { return seq() + data_length(); } + // SETTERS inline TCP::Packet& set_src_port(TCP::Port p) { header().source_port = htons(p); @@ -595,11 +597,11 @@ namespace net { */ struct WriteQueue { - std::list q; + std::deque q; - std::list::iterator current; + uint32_t current; - WriteQueue() : q(), current(q.end()) {} + WriteQueue() : q(), current(0) {} void acknowledge(size_t bytes) { while(bytes and !q.empty()) @@ -607,10 +609,9 @@ namespace net { auto& buf = q.front().first; bytes -= buf.acknowledge(bytes); - printf(" Buf offset=%u rem=%u ack=%u\n", - buf.offset, buf.remaining, buf.acknowledged); if(buf.done()) { q.pop_front(); + current--; } } } @@ -625,39 +626,26 @@ namespace net { { return !q.empty() and q.back().first.remaining; } const WriteBuffer& nxt() - { auto& buf = current->first; - printf(" Buf offset=%u rem=%u ack=%u\n", - buf.offset, buf.remaining, buf.acknowledged); - return current->first; } + { return q[current-1].first; } const WriteBuffer& una() { return q.front().first; } void advance(size_t bytes) { - auto& buf = current->first; - + auto& buf = q[current-1].first; buf.advance(bytes); - printf(" Buf offset=%u rem=%u ack=%u\n", - buf.offset, buf.remaining, buf.acknowledged); - + if(!buf.remaining) { - current->second(buf.offset); + q[current-1].second(buf.offset); current++; } } void push_back(const WriteRequest& wr) { - printf(" Adding WR \n"); - auto& buf = current->first; - printf(" Buf offset=%u rem=%u ack=%u\n", - buf.offset, buf.remaining, buf.acknowledged); - bool update = (current == q.end()); q.push_back(wr); - if(update) { - current = --q.end(); - printf(" Updated iter \n"); - } + if(current == q.size()-1) + current++; } }; @@ -1200,11 +1188,6 @@ namespace net { */ bool queued_; - /* - Retransmission queue - */ - std::deque rtx_q; - struct { hw::PIT::Timer_iterator iter; bool active = false; @@ -1512,9 +1495,6 @@ namespace net { bool can_send_one(); - inline bool need_send() - { return rtx_q.empty(); } - bool can_send(); void send_much(); @@ -1672,11 +1652,6 @@ namespace net { */ void rtx_ack(Seq ack); - /* - Flush the queue (transmit every packet in queue) - */ - void rtx_flush(); - /* Delete retransmission queue */ diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index 959ea922d8..8a18100062 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -107,7 +107,6 @@ void Connection::write(WriteBuffer buffer, WriteCallback callback) { writeq.push_back({buffer, callback}); // if data was written, advance if(written) { - printf(" Wrote %u.\n", written); writeq.advance(written); } } @@ -132,7 +131,7 @@ void Connection::offer(size_t& packets) { // get next request in writeq auto& buf = writeq.nxt(); // fill the packet with data - auto written = fill_packet(packet, (char*)buf.pos(), std::min(buf.remaining, (size_t)SMSS()), cb.SND.NXT); + auto written = fill_packet(packet, (char*)buf.pos(), buf.remaining, cb.SND.NXT); cb.SND.NXT += packet->data_length(); // advance the write q @@ -161,7 +160,7 @@ size_t Connection::send(const char* buffer, size_t remaining, size_t& packets_av auto packet = create_outgoing_packet(); packets_avail--; - auto written = fill_packet(packet, buffer+bytes_written, std::min(remaining, (size_t)SMSS()), cb.SND.NXT); + auto written = fill_packet(packet, buffer+bytes_written, remaining, cb.SND.NXT); cb.SND.NXT += packet->data_length(); bytes_written += written; @@ -224,7 +223,7 @@ void Connection::writeq_push() { size_t Connection::fill_packet(Packet_ptr packet, const char* buffer, size_t n, Seq seq) { Expects(!packet->has_data()); - auto written = packet->fill(buffer, n); + auto written = packet->fill(buffer, std::min(n, (size_t)SMSS())); packet->set_seq(seq).set_ack(cb.RCV.NXT).set_flag(ACK); @@ -241,7 +240,7 @@ void Connection::limited_tx() { auto& buf = writeq.nxt(); - auto written = fill_packet(packet, (char*)buf.pos(), std::min(buf.remaining, (uint32_t)SMSS()), cb.SND.NXT); + auto written = fill_packet(packet, (char*)buf.pos(), buf.remaining, cb.SND.NXT); cb.SND.NXT += packet->data_length(); writeq.advance(written); @@ -310,7 +309,7 @@ void Connection::segment_arrived(TCP::Packet_ptr incoming) { } case State::CLOSED: { debug(" State handle finished with CLOSED. We're done, ask host() to delete the connection. \n"); - rtx_clear(); + writeq_reset(); signal_close(); break; }; @@ -353,7 +352,7 @@ TCP::Packet_ptr Connection::create_outgoing_packet() { } void Connection::transmit(TCP::Packet_ptr packet) { - if(!rttm.active) { + if(!rttm.active and packet->end() == cb.SND.NXT) { //printf(" Starting RTT measurement.\n"); rttm.start(); } @@ -363,11 +362,11 @@ void Connection::transmit(TCP::Packet_ptr packet) { debug2(" TX %s\n", packet->to_string().c_str()); host_.transmit(packet); - if(packet->has_data()) - rtx_q.push_back(packet); - if(!rtx_timer.active) - rtx_start(); + if(packet->has_data() and !rtx_timer.active) { + rtx_start(); + } } + bool Connection::can_send_one() { return send_window() >= SMSS() and writeq.remaining_requests(); } @@ -378,19 +377,6 @@ bool Connection::can_send() { void Connection::send_much() { writeq_push(); - /*while(can_send()) { - auto& buf = writeq.front().first; - auto written = send((char*)buf.pos(), std::min(buf.remaining, (uint32_t)RMSS()), create_outgoing_packet()); - bytes_written += written; - buf.advance(written); - if(!buf.remaining) { - writeq.front().second(buf.offset); - writeq.pop(); - } - }*/ - - //printf(" Prev UW: %u UW: %u CW: %u, FS: %u BW: %u\n", - // uw, usable_window(), cb.cwnd, flight_size(), bytes_written); } bool Connection::handle_ack(TCP::Packet_ptr in) { @@ -423,7 +409,7 @@ bool Connection::handle_ack(TCP::Packet_ptr in) { acks_rcvd_++; - debug2(" New ACK#%u: %u FS: %u %s\n", acks_rcvd_, + debug(" New ACK#%u: %u FS: %u %s\n", acks_rcvd_, in->ack() - cb.ISS, flight_size(), fast_recovery ? "[RECOVERY]" : ""); // [RFC 6582] p. 8 @@ -434,9 +420,9 @@ bool Connection::handle_ack(TCP::Packet_ptr in) { size_t bytes_acked = in->ack() - cb.SND.UNA; cb.SND.UNA = in->ack(); - writeq.acknowledge(bytes_acked); - // ack everything in rtx queue - rtx_ack(in->ack()); + // ack everything in write queue + if(!writeq.empty()) + rtx_ack(in->ack()); // update cwnd when congestion avoidance? bool cong_avoid_rtt = false; @@ -577,43 +563,38 @@ void Connection::on_dup_ack() { (for the current value of RTO). */ void Connection::rtx_ack(const Seq ack) { - auto x = rtx_q.size(); - while(!rtx_q.empty()) { - if(rtx_q.front()->is_acked_by(ack)) - rtx_q.pop_front(); - else - break; - } + auto acked = ack - prev_highest_ack_; + writeq.acknowledge(acked); /* When all outstanding data has been acknowledged, turn off the retransmission timer. */ - if(rtx_q.empty() and rtx_timer.active) { + if(cb.SND.UNA == cb.SND.NXT) { rtx_stop(); + rto_attempt = 0; } /* When an ACK is received that acknowledges new data, restart the retransmission timer so that it will expire after RTO seconds (for the current value of RTO). */ - else if(x - rtx_q.size() > 0) { - rto_attempt = 0; + else if(acked > 0) { rtx_reset(); + rto_attempt = 0; } + //printf(" ACK'ed %u packets. rtx_q: %u\n", // x-rtx_q.size(), rtx_q.size()); } void Connection::retransmit() { - if(rtx_q.empty()) - return; - auto packet = rtx_q.front(); - packet->clear_flag(PSH); + auto packet = create_outgoing_packet(); + auto& buf = writeq.una(); + fill_packet(packet, (char*)buf.pos(), buf.remaining, cb.SND.UNA); + packet->set_flag(ACK); //printf(" rseq=%u \n", packet->seq() - cb.ISS); debug(" RT %s\n", packet->to_string().c_str()); - Ensures(packet->tail() == nullptr); - Ensures(packet->last_in_chain() == nullptr); host_.transmit(packet); /* Every time a packet containing data is sent (including a @@ -621,20 +602,21 @@ void Connection::retransmit() { so that it will expire after RTO seconds (for the current value of RTO). */ - //if(!rt_timer.active) - // rt_start(); + if(packet->has_data() and !rtx_timer.active) { + rtx_start(); + } } void Connection::rtx_start() { - assert(!rtx_timer.active); + Expects(!rtx_timer.active); auto i = rtx_timer.i; auto rto = rttm.RTO; rtx_timer.iter = hw::PIT::instance().on_timeout(rttm.RTO, [this, i, rto] { rtx_timer.active = false; - printf(" %i Timed out (%f). rt_q: %u, i: %u rt_i: %u\n", - local_port_, rto, rtx_q.size(), i, rtx_timer.i); + printf(" %i Timed out (%f). FS: %u, i: %u rt_i: %u\n", + local_port_, rto, flight_size(), i, rtx_timer.i); rtx_timeout(); }); rtx_timer.i++; @@ -642,22 +624,14 @@ void Connection::rtx_start() { } void Connection::rtx_stop() { - assert(rtx_timer.active); + Expects(rtx_timer.active); hw::PIT::instance().stop_timer(rtx_timer.iter); rtx_timer.active = false; } -void Connection::rtx_flush() { - while(!rtx_q.empty()) { - host_.transmit(rtx_q.front()); - rtx_q.pop_front(); - } -} - void Connection::rtx_clear() { if(rtx_timer.active) rtx_stop(); - rtx_q.clear(); } /* @@ -682,11 +656,8 @@ void Connection::rtx_clear() { void Connection::rtx_timeout() { // retransmit SND.UNA retransmit(); - //auto hax = ++rtx_q.begin(); - //for(auto i = 0; i < 2 and hax != rtx_q.end(); i++) - // host_.transmit(*hax++); - if(!rtx_q.front()->isset(SYN)) { + if(cb.SND.UNA != cb.ISS) { // "back off" timer rttm.RTO *= 2.0; } @@ -737,7 +708,7 @@ TCP::Seq Connection::generate_iss() { void Connection::set_state(State& state) { prev_state_ = state_; state_ = &state; - debug(" %s => %s \n", + printf(" %s => %s \n", prev_state_->to_string().c_str(), state_->to_string().c_str()); } diff --git a/src/net/tcp_connection_states.cpp b/src/net/tcp_connection_states.cpp index 080b0744cd..31dbfb1d51 100644 --- a/src/net/tcp_connection_states.cpp +++ b/src/net/tcp_connection_states.cpp @@ -436,8 +436,6 @@ void Connection::State::send_reset(Connection& tcp) { tcp.writeq_reset(); auto packet = tcp.outgoing_packet(); packet->set_seq(tcp.tcb().SND.NXT).set_ack(0).set_flag(RST); - // flush retransmission queue - tcp.rtx_flush(); tcp.transmit(packet); } ///////////////////////////////////////////////////////////////////// @@ -898,7 +896,7 @@ State::Result Connection::SynSent::handle(Connection& tcp, TCP::Packet_ptr in) { tcb.IRS = in->seq(); tcb.SND.UNA = in->ack(); - tcp.rtx_ack(in->ack()); + //tcp.rtx_ack(in->ack()); // (our SYN has been ACKed) if(tcb.SND.UNA > tcb.ISS) { @@ -1010,7 +1008,7 @@ State::Result Connection::SynReceived::handle(Connection& tcp, TCP::Packet_ptr i tcb.SND.UNA = in->ack(); if(tcp.rttm.active) tcp.rttm.stop(); - tcp.rtx_ack(in->ack()); + //tcp.rtx_ack(in->ack()); // 7. proccess the segment text if(in->has_data()) { @@ -1145,7 +1143,8 @@ State::Result Connection::FinWait1::handle(Connection& tcp, TCP::Packet_ptr in) if(in->ack() == tcp.tcb().SND.NXT) { // TODO: I guess or FIN is ACK'ed..? tcp.set_state(TimeWait::instance()); - tcp.rtx_stop(); + if(tcp.rtx_timer.active) + tcp.rtx_stop(); tcp.start_time_wait_timeout(); } else { tcp.set_state(Closing::instance()); @@ -1191,7 +1190,8 @@ State::Result Connection::FinWait2::handle(Connection& tcp, TCP::Packet_ptr in) Start the time-wait timer, turn off the other timers. */ tcp.set_state(Connection::TimeWait::instance()); - tcp.rtx_stop(); + if(tcp.rtx_timer.active) + tcp.rtx_stop(); tcp.start_time_wait_timeout(); } return OK; diff --git a/test/tcp/service.cpp b/test/tcp/service.cpp index 6261df80c4..50755612c8 100644 --- a/test/tcp/service.cpp +++ b/test/tcp/service.cpp @@ -61,10 +61,10 @@ void FINISH_TEST() { INFO("TEST", "Started 3 x MSL timeout."); hw::PIT::instance().onTimeout(3 * MSL_TEST, [] { INFO("TEST", "Verify release of resources"); - CHECK(inet->tcp().activeConnections() == 0, "tcp.activeConnections() == 0"); - CHECK(inet->buffers_available() == buffers_available, - "inet->buffers_available() == buffers_available"); - INFO("Buffers available", "%u", inet->buffers_available()); + CHECK(inet->tcp().activeConnections() == 0, + "tcp.activeConnections() == 0"); + CHECK(inet->buffers_available() == buffers_available, + "inet->buffers_available() == buffers_available"); printf("# TEST SUCCESS #\n"); }); } @@ -153,7 +153,7 @@ void print_stuff() void Service::start() { - hw::PIT::on_timeout(5.0, print_stuff); + //hw::PIT::on_timeout(5.0, print_stuff); IP4::addr A1 (255, 255, 255, 255); IP4::addr B1 ( 0, 255, 255, 255); From 39d0cfb011b5628997ebf2f917e863e275bf5491 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Tue, 3 May 2016 16:25:06 +0200 Subject: [PATCH 266/311] tcp: comments and cleanup --- api/net/tcp.hpp | 73 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 58 insertions(+), 15 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index 07b90ec62e..62c2210dfd 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -593,16 +593,24 @@ namespace net { /* - Write Queue + Write Queue containig WriteRequests from user. + Stores requests until they are fully acknowledged; + this will make it possible to retransmit */ struct WriteQueue { std::deque q; + /* Current element (index + 1) */ uint32_t current; WriteQueue() : q(), current(0) {} + /* + Acknowledge n bytes from the write queue. + If a Request is fully acknowledged, release from queue + and "step back". + */ void acknowledge(size_t bytes) { while(bytes and !q.empty()) { @@ -622,15 +630,29 @@ namespace net { size_t size() const { return q.size(); } + /* + If the queue has more data to send + */ bool remaining_requests() const { return !q.empty() and q.back().first.remaining; } + /* + The current buffer to write from. + Can be in the middle/back of the queue due to unacknowledged buffers in front. + */ const WriteBuffer& nxt() { return q[current-1].first; } + /* + The oldest unacknowledged buffer. (Always in front) + */ const WriteBuffer& una() { return q.front().first; } + /* + Advances the queue forward. + If current buffer finishes; exec user callback and step to next. + */ void advance(size_t bytes) { auto& buf = q[current-1].first; @@ -642,12 +664,17 @@ namespace net { } } + /* + Add a request to the back of the queue. + If the queue was empty/finished, point current to the new request. + */ void push_back(const WriteRequest& wr) { q.push_back(wr); if(current == q.size()-1) current++; } - }; + }; // < TCP::Connection::WriteQueue + /* Connection identifier @@ -1194,11 +1221,6 @@ namespace net { size_t i = 0; } rtx_timer; - /* - Bytes queued for transmission. - */ - //size_t write_queue_total; - /* When time-wait timer was started. */ @@ -1491,27 +1513,49 @@ namespace net { */ bool handle_ack(TCP::Packet_ptr); + /* + When a duplicate ACK is received. + */ void on_dup_ack(); + /* + Is it possible to send ONE segment. + */ bool can_send_one(); + /* + Is the usable window large enough, and is there data to send. + */ bool can_send(); + + /* + Send as much as possible from write queue. + */ void send_much(); + /* + Fill a packet with data and give it a SEQ number. + */ size_t fill_packet(Packet_ptr, const char*, size_t, Seq); - //void send_ack(TCP::Packet_ptr = nullptr); /// Congestion Control [RFC 5681] /// + // is fast recovery state bool fast_recovery = false; + // First partial ack seen bool reno_fpack_seen = false; - + + // limited transmit [RFC 3042] active bool limited_tx_ = true; + // number of duplicate acks size_t dup_acks_ = 0; + Seq prev_highest_ack_ = 0; Seq highest_ack_ = 0; + + // number of non duplicate acks received size_t acks_rcvd_ = 0; inline void setup_congestion_control() @@ -1549,6 +1593,7 @@ namespace net { inline void reno_deflate_cwnd(uint16_t n) { cb.cwnd -= (n >= SMSS()) ? n-SMSS() : n; } + // TODO: Flight size goes from zero to max uint32 when limited tx inline void reduce_ssthresh() { auto fs = flight_size(); printf(" FlightSize: %u\n", fs); @@ -1579,9 +1624,8 @@ namespace net { printf(" Finished Fast Recovery - Cwnd: %u\n", cb.cwnd); } - inline bool reno_full_ack(Seq ACK) { - return ACK - 1 > cb.recover; - } + inline bool reno_full_ack(Seq ACK) + { return ACK - 1 > cb.recover; } /* Generate a new ISS. @@ -1612,9 +1656,8 @@ namespace net { /* */ - inline TCP::Packet_ptr outgoing_packet() { - return create_outgoing_packet(); - } + inline TCP::Packet_ptr outgoing_packet() + { return create_outgoing_packet(); } /// RETRANSMISSION /// From fcea04839686478b1fa9855b38f440fbc462ec87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Tue, 3 May 2016 16:28:51 +0200 Subject: [PATCH 267/311] tcp: silenced printf --- src/net/tcp_connection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index 8a18100062..203c7511d9 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -708,7 +708,7 @@ TCP::Seq Connection::generate_iss() { void Connection::set_state(State& state) { prev_state_ = state_; state_ = &state; - printf(" %s => %s \n", + debug(" %s => %s \n", prev_state_->to_string().c_str(), state_->to_string().c_str()); } From cb8e15345b998d383087fdfba0966cd1640e251b Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Tue, 3 May 2016 20:52:04 +0200 Subject: [PATCH 268/311] Script to create FAT-image from folder contents --- etc/copy_scripts.sh | 2 +- etc/create_memdisk.sh | 47 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100755 etc/create_memdisk.sh diff --git a/etc/copy_scripts.sh b/etc/copy_scripts.sh index 86fe8fdd00..bcb9f7303c 100755 --- a/etc/copy_scripts.sh +++ b/etc/copy_scripts.sh @@ -6,4 +6,4 @@ mkdir -p $INCLUDEOS_INSTALL/etc cp $INCLUDEOS_SRC/etc/qemu-ifup $INCLUDEOS_INSTALL/etc/ cp $INCLUDEOS_SRC/etc/qemu_cmd.sh $INCLUDEOS_INSTALL/etc/ cp $INCLUDEOS_SRC/etc/run.sh $INCLUDEOS_INSTALL/etc/ - +cp $INCLUDEOS_SRC/etc/create_memdisk.sh $INCLUDEOS_INSTALL/etc/ diff --git a/etc/create_memdisk.sh b/etc/create_memdisk.sh new file mode 100755 index 0000000000..940bf07ca0 --- /dev/null +++ b/etc/create_memdisk.sh @@ -0,0 +1,47 @@ +#! /bin/bash +# +# Stuff everything in the ./memdisk directory into a brand new +# FAT-formatted disk image, $FILENAME. +# +# WARNING: +# * Existing disk image of the same name gets overwritten +# * An assembly-file 'memdisk.asm' gets created / overwritten +# +# NOTE: +# * A temporary mount-point $MOUNT gets created then removed + +if [ ! -d memdisk ] +then + echo "Directory 'memdisk' not found" + exit 1 +fi + +BLOCK_SIZE=512 +FILENAME=memdisk.fat +MOUNT=temp_mount +ASM_FILE=memdisk.asm + +# The assembly trick to get the memdisk into the ELF binary +cat > $ASM_FILE <<-EOF +USE32 +ALIGN 32 + +section .diskdata +contents: + incbin "$FILENAME" + +EOF + +size=`du -s --block-size=$BLOCK_SIZE memdisk | cut -f1` +echo -e "\n>>> Creating memdisk with $size blocks" + +[ -e $FILENAME ] && rm $FILENAME + +mkfs.fat -C $FILENAME -S $BLOCK_SIZE $size + +mkdir -p $MOUNT +sudo mount $FILENAME $MOUNT +sudo cp -r memdisk/* $MOUNT/ +sync +sudo umount $MOUNT +rmdir $MOUNT From decb2c00c0119e82200eb5930a5ed2c46a2d238a Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Wed, 4 May 2016 13:33:03 +0200 Subject: [PATCH 269/311] async: Fix missing error for write failed --- src/util/async.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/util/async.cpp b/src/util/async.cpp index cb4e38edee..af5637dfec 100644 --- a/src/util/async.cpp +++ b/src/util/async.cpp @@ -13,13 +13,13 @@ void Async::upload_file( const size_t CHUNK_SIZE) { disk_transfer(disk, ent, - [conn, callback, CHUNK_SIZE] (fs::buffer_t buffer, - size_t length, - next_func next) + [conn, CHUNK_SIZE] (fs::buffer_t buffer, + size_t length, + next_func next) { // write chunk to TCP connection conn->write(buffer.get(), length, - [callback, CHUNK_SIZE, next] (size_t n) { + [CHUNK_SIZE, next] (size_t n) { // if all data written, go to next chunk next(n == CHUNK_SIZE); @@ -72,7 +72,7 @@ void Async::disk_transfer( (*next)(pos+1); else // otherwise, fail - callback(fs::no_error, false); + callback({fs::error_t::E_IO, "Write failed"}, false); }); }); From 970f447d2f1faa7b07233e8c7543974d1d60e385 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Wed, 4 May 2016 13:43:04 +0200 Subject: [PATCH 270/311] async: Functions made public --- api/utility/async.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/api/utility/async.hpp b/api/utility/async.hpp index 8d65e6e50d..8fcc0a25ad 100644 --- a/api/utility/async.hpp +++ b/api/utility/async.hpp @@ -8,6 +8,7 @@ class Async { +public: static const size_t PAYLOAD_SIZE = 64000; typedef net::TCP::Connection_ptr Connection; From f2cdf156b4c2b08eb52f7c6e1df675482786682a Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Wed, 4 May 2016 16:44:28 +0200 Subject: [PATCH 271/311] Added minimum values for FAT image creation --- etc/create_memdisk.sh | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/etc/create_memdisk.sh b/etc/create_memdisk.sh index 940bf07ca0..004b5a496c 100755 --- a/etc/create_memdisk.sh +++ b/etc/create_memdisk.sh @@ -17,6 +17,8 @@ then fi BLOCK_SIZE=512 +MIN_BLOCKS=34 +MIN_ROOT_ENTS=16 FILENAME=memdisk.fat MOUNT=temp_mount ASM_FILE=memdisk.asm @@ -33,11 +35,20 @@ contents: EOF size=`du -s --block-size=$BLOCK_SIZE memdisk | cut -f1` -echo -e "\n>>> Creating memdisk with $size blocks" +echo -e "\n>>> Memdisk requires $size blocks, minimum block-count is $MIN_BLOCKS" + +[ $size -gt $MIN_BLOCKS ] || size=$MIN_BLOCKS + +echo -e ">>> Creating $size blocks" + +root_entries=`ls -l memdisk | wc -l` +[ $root_entries -gt $MIN_ROOT_ENTS ] || root_entries=$MIN_ROOT_ENTS + +echo -e ">>> Creating $root_entries root entries" [ -e $FILENAME ] && rm $FILENAME -mkfs.fat -C $FILENAME -S $BLOCK_SIZE $size +mkfs.fat -C $FILENAME -S $BLOCK_SIZE $size -n "INC_MEMDISK" -r $root_entries mkdir -p $MOUNT sudo mount $FILENAME $MOUNT From 2fffa6b04afbc1416268aaf03465478316984169 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Wed, 4 May 2016 16:46:28 +0200 Subject: [PATCH 272/311] util: fixes to async --- src/util/async.cpp | 53 +++++++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/src/util/async.cpp b/src/util/async.cpp index af5637dfec..65bb9638e6 100644 --- a/src/util/async.cpp +++ b/src/util/async.cpp @@ -5,57 +5,62 @@ #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) +inline unsigned roundup(unsigned n, unsigned div) { + return (n + div - 1) / div; +} + void Async::upload_file( - Disk disk, - const Dirent& ent, - Connection conn, + Disk disk, + const Dirent& ent, + Connection conn, on_after_func callback, const size_t CHUNK_SIZE) { disk_transfer(disk, ent, - [conn, CHUNK_SIZE] (fs::buffer_t buffer, - size_t length, - next_func next) + [conn] (fs::buffer_t buffer, + size_t length, + next_func next) { // write chunk to TCP connection - conn->write(buffer.get(), length, - [CHUNK_SIZE, next] (size_t n) { - + conn->write(buffer.get(), length, + [length, next] (size_t n) { + // if all data written, go to next chunk - next(n == CHUNK_SIZE); - + printf("sock write: %u / %u\n", n, length); + next(n == length); + }, true); - + }, callback, CHUNK_SIZE); } void Async::disk_transfer( - Disk disk, - const Dirent& ent, - on_write_func write_func, + Disk disk, + const Dirent& ent, + on_write_func write_func, on_after_func callback, const size_t CHUNK_SIZE) { typedef std::function next_func_t; auto next = std::make_shared (); - + *next = [next, disk, ent, write_func, callback, CHUNK_SIZE] (size_t pos) { - + // number of write calls necessary - const size_t writes = ent.size() / CHUNK_SIZE; - + const size_t writes = roundup(ent.size(), CHUNK_SIZE); + // done condition if (pos >= writes) { callback(fs::no_error, true); return; } - + // read chunk from file disk->fs().read(ent, pos * CHUNK_SIZE, CHUNK_SIZE, [next, pos, write_func, callback, CHUNK_SIZE] ( - fs::error_t err, - fs::buffer_t buffer, + fs::error_t err, + fs::buffer_t buffer, uint64_t length) { if (err) { @@ -63,7 +68,7 @@ void Async::disk_transfer( callback(err, false); return; } - + // call write callback with data write_func(buffer, length, [next, pos, callback] (bool good) { @@ -75,7 +80,7 @@ void Async::disk_transfer( callback({fs::error_t::E_IO, "Write failed"}, false); }); }); - + }; // start async loop (*next)(0); From 87d220f6a8bef5a3427d9610740954ccf4715126 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Wed, 4 May 2016 16:52:05 +0200 Subject: [PATCH 273/311] fs: Bounds check read() calls, optimize for sector boundary reads --- src/fs/fat_async.cpp | 24 ++++++++++++++++-------- src/fs/fat_sync.cpp | 22 +++++++++++++++------- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/fs/fat_async.cpp b/src/fs/fat_async.cpp index f950f96bfb..245c1e87c8 100644 --- a/src/fs/fat_async.cpp +++ b/src/fs/fat_async.cpp @@ -159,10 +159,15 @@ namespace fs callback({ error_t::E_IO, "Zero read length" }, buffer_t(), 0); return; } + // bounds check the read position and length + uint32_t stapos = std::min(ent.size(), pos); + uint32_t endpos = std::min(ent.size(), pos + n); + // new length + n = endpos - stapos; // calculate start and length in sectors - uint32_t sector = pos / this->sector_size; - uint32_t nsect = roundup(pos + n, sector_size) / sector_size - sector; - uint32_t internal_ofs = pos % device.block_size(); + uint32_t sector = stapos / this->sector_size; + uint32_t nsect = roundup(endpos, sector_size) / sector_size - sector; + uint32_t internal_ofs = stapos % device.block_size(); // cluster -> sector + position device.read(this->cl_to_sector(ent.block) + sector, nsect, @@ -175,12 +180,15 @@ namespace fs return; } - // allocate buffer & copy data - auto* result = new uint8_t[n]; - memcpy(result, data.get() + internal_ofs, n); + // when the offset is non-zero we aren't on a sector boundary + if (internal_ofs != 0) { + // so, we need to copy offset data to data buffer + auto* result = new uint8_t[n]; + memcpy(result, data.get() + internal_ofs, n); + data = buffer_t(result, std::default_delete()); + } - auto buffer = buffer_t(result, std::default_delete()); - callback(no_error, buffer, n); + callback(no_error, data, n); }); } diff --git a/src/fs/fat_sync.cpp b/src/fs/fat_sync.cpp index 2ea45b8643..914b150714 100644 --- a/src/fs/fat_sync.cpp +++ b/src/fs/fat_sync.cpp @@ -20,9 +20,14 @@ namespace fs { Buffer FAT::read(const Dirent& ent, uint64_t pos, uint64_t n) { + // bounds check the read position and length + uint32_t stapos = std::min(ent.size(), pos); + uint32_t endpos = std::min(ent.size(), pos + n); + // new length + n = endpos - stapos; // cluster -> sector + position - uint32_t sector = pos / this->sector_size; - uint32_t nsect = roundup(pos + n, sector_size) / sector_size - sector; + uint32_t sector = stapos / this->sector_size; + uint32_t nsect = roundup(endpos, sector_size) / sector_size - sector; // the resulting buffer uint8_t* result = new uint8_t[n]; @@ -30,12 +35,15 @@ namespace fs // read @nsect sectors ahead buffer_t data = device.read_sync(this->cl_to_sector(ent.block) + sector, nsect); // where to start copying from the device result - uint32_t internal_ofs = pos % device.block_size(); - // copy data to result buffer - memcpy(result, data.get() + internal_ofs, n); - auto buffer = buffer_t(result, std::default_delete()); + uint32_t internal_ofs = stapos % device.block_size(); + // when the offset is non-zero we aren't on a sector boundary + if (internal_ofs != 0) { + // so, we need to copy offset data to data buffer + memcpy(result, data.get() + internal_ofs, n); + data = buffer_t(result, std::default_delete()); + } - return Buffer(no_error, buffer, n); + return Buffer(no_error, data, n); } Buffer FAT::readFile(const std::string& strpath) From 7c2dc0f1fa146a174b10949032ca9fe5a9094982 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Wed, 4 May 2016 17:20:34 +0200 Subject: [PATCH 274/311] tcp: disabled forced close --- api/net/tcp.hpp | 32 ++++++++++++++++++------------- src/net/tcp_connection.cpp | 28 ++++++++++++++------------- src/net/tcp_connection_states.cpp | 2 +- 3 files changed, 35 insertions(+), 27 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index 62c2210dfd..0a7f0954e5 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -28,7 +28,6 @@ #include // timer duration #include // enable_shared_from_this #include -#include inline unsigned round_up(unsigned n, unsigned div) { assert(n); @@ -595,12 +594,12 @@ namespace net { /* Write Queue containig WriteRequests from user. Stores requests until they are fully acknowledged; - this will make it possible to retransmit + this will make it possible to retransmit */ struct WriteQueue { std::deque q; - + /* Current element (index + 1) */ uint32_t current; @@ -612,10 +611,10 @@ namespace net { and "step back". */ void acknowledge(size_t bytes) { - while(bytes and !q.empty()) + while(bytes and !q.empty()) { auto& buf = q.front().first; - + bytes -= buf.acknowledge(bytes); if(buf.done()) { q.pop_front(); @@ -633,7 +632,7 @@ namespace net { /* If the queue has more data to send */ - bool remaining_requests() const + bool remaining_requests() const { return !q.empty() and q.back().first.remaining; } /* @@ -646,7 +645,7 @@ namespace net { /* The oldest unacknowledged buffer. (Always in front) */ - const WriteBuffer& una() + const WriteBuffer& una() { return q.front().first; } /* @@ -654,11 +653,16 @@ namespace net { If current buffer finishes; exec user callback and step to next. */ void advance(size_t bytes) { - + auto& buf = q[current-1].first; buf.advance(bytes); + debug2(" Advance: off=%u rem=%u ack=%u\n", + buf.offset, buf.remaining, buf.acknowledged); + if(!buf.remaining) { + debug(" Advance: Done (%u)\n", + buf.offset); q[current-1].second(buf.offset); current++; } @@ -670,6 +674,8 @@ namespace net { */ void push_back(const WriteRequest& wr) { q.push_back(wr); + debug2(" Inserted WR: off=%u rem=%u ack=%u\n", + wr.first.offset, wr.first.remaining, wr.first.acknowledged); if(current == q.size()-1) current++; } @@ -1542,19 +1548,19 @@ namespace net { // is fast recovery state bool fast_recovery = false; - + // First partial ack seen bool reno_fpack_seen = false; - + // limited transmit [RFC 3042] active bool limited_tx_ = true; // number of duplicate acks size_t dup_acks_ = 0; - + Seq prev_highest_ack_ = 0; Seq highest_ack_ = 0; - + // number of non duplicate acks received size_t acks_rcvd_ = 0; @@ -1597,7 +1603,7 @@ namespace net { inline void reduce_ssthresh() { auto fs = flight_size(); printf(" FlightSize: %u\n", fs); - + if(limited_tx_) fs -= 2*(uint32_t)SMSS(); diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index 203c7511d9..14db6e7a3b 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -107,7 +107,7 @@ void Connection::write(WriteBuffer buffer, WriteCallback callback) { writeq.push_back({buffer, callback}); // if data was written, advance if(written) { - writeq.advance(written); + writeq.advance(written); } } catch(TCPException err) { @@ -242,13 +242,14 @@ void Connection::limited_tx() { auto written = fill_packet(packet, (char*)buf.pos(), buf.remaining, cb.SND.NXT); cb.SND.NXT += packet->data_length(); - + writeq.advance(written); transmit(packet); } void Connection::writeq_reset() { + debug2(" Reseting.\n"); while(!writeq.empty()) { auto& job = writeq.q.front(); job.second(job.first.offset); @@ -269,7 +270,7 @@ void Connection::open(bool active) { } void Connection::close() { - debug(" Active close on connection. \n"); + printf(" Active close on connection. \n"); try { state_->close(*this); if(is_state(Closed::instance())) @@ -308,7 +309,8 @@ void Connection::segment_arrived(TCP::Packet_ptr incoming) { break; } case State::CLOSED: { - debug(" State handle finished with CLOSED. We're done, ask host() to delete the connection. \n"); + debug(" (%s => %s) State handle finished with CLOSED. We're done, ask host() to delete the connection.\n", + prev_state_->to_string().c_str(), state_->to_string().c_str()); writeq_reset(); signal_close(); break; @@ -357,13 +359,13 @@ void Connection::transmit(TCP::Packet_ptr packet) { rttm.start(); } //if(packet->seq() + packet->data_length() != cb.SND.NXT) - //printf(" rseq=%u rack=%u\n", + //printf(" rseq=%u rack=%u\n", // packet->seq() - cb.ISS, packet->ack() - cb.IRS); debug2(" TX %s\n", packet->to_string().c_str()); host_.transmit(packet); if(packet->has_data() and !rtx_timer.active) { - rtx_start(); + rtx_start(); } } @@ -398,7 +400,7 @@ bool Connection::handle_ack(TCP::Packet_ptr in) { // new ack else if(in->ack() >= cb.SND.UNA) { - + if( cb.SND.WL1 < in->seq() or ( cb.SND.WL1 == in->seq() and cb.SND.WL2 <= in->ack() ) ) { cb.SND.WND = in->win(); @@ -409,7 +411,7 @@ bool Connection::handle_ack(TCP::Packet_ptr in) { acks_rcvd_++; - debug(" New ACK#%u: %u FS: %u %s\n", acks_rcvd_, + debug(" New ACK#%u: %u FS: %u %s\n", acks_rcvd_, in->ack() - cb.ISS, flight_size(), fast_recovery ? "[RECOVERY]" : ""); // [RFC 6582] p. 8 @@ -442,7 +444,7 @@ bool Connection::handle_ack(TCP::Packet_ptr in) { // slow start if(cb.slow_start()) { reno_increase_cwnd(bytes_acked); - debug2(" Slow start. cwnd=%u uw=%u\n", + debug2(" Slow start. cwnd=%u uw=%u\n", cb.cwnd, usable_window()); } @@ -450,7 +452,7 @@ bool Connection::handle_ack(TCP::Packet_ptr in) { else { // increase cwnd once per RTT cb.cwnd += std::max(SMSS()*SMSS()/cb.cwnd, (uint32_t)1); - debug2(" Congestion avoidance. cwnd=%u uw=%u\n", + debug2(" Congestion avoidance. cwnd=%u uw=%u\n", cb.cwnd, usable_window()); } // < congestion avoidance @@ -526,7 +528,7 @@ void Connection::on_dup_ack() { // try to send one segment if(cb.SND.WND >= SMSS() and (flight_size() <= cb.cwnd + 2*SMSS()) and writeq.remaining_requests()) { limited_tx(); - } + } } } @@ -582,7 +584,7 @@ void Connection::rtx_ack(const Seq ack) { rtx_reset(); rto_attempt = 0; } - + //printf(" ACK'ed %u packets. rtx_q: %u\n", // x-rtx_q.size(), rtx_q.size()); } @@ -603,7 +605,7 @@ void Connection::retransmit() { of RTO). */ if(packet->has_data() and !rtx_timer.active) { - rtx_start(); + rtx_start(); } } diff --git a/src/net/tcp_connection_states.cpp b/src/net/tcp_connection_states.cpp index 31dbfb1d51..133cc06d2e 100644 --- a/src/net/tcp_connection_states.cpp +++ b/src/net/tcp_connection_states.cpp @@ -1085,7 +1085,7 @@ State::Result Connection::Established::handle(Connection& tcp, TCP::Packet_ptr i if(in->isset(FIN)) { process_fin(tcp, in); tcp.set_state(Connection::CloseWait::instance()); - return CLOSE; + return OK; } return OK; From 9ad6eba75aeea9573d8878690edec9d221714df3 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Wed, 4 May 2016 17:30:24 +0200 Subject: [PATCH 275/311] acpi: MSR, base address retrieval --- api/hw/apic.hpp | 29 +++++++++++ src/Makefile | 3 +- src/debug/test_disk.cpp | 12 ++++- src/hw/apic.cpp | 111 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 api/hw/apic.hpp create mode 100644 src/hw/apic.cpp diff --git a/api/hw/apic.hpp b/api/hw/apic.hpp new file mode 100644 index 0000000000..583786dd63 --- /dev/null +++ b/api/hw/apic.hpp @@ -0,0 +1,29 @@ +// This file is a part of the IncludeOS unikernel - www.includeos.org +// +// Copyright 2015 Oslo and Akershus University College of Applied Sciences +// and Alfred Bratterud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once +#include + +namespace hw { + + class APIC { + public: + static void init(); + + }; + +} diff --git a/src/Makefile b/src/Makefile index e62534af83..d9f52bf255 100644 --- a/src/Makefile +++ b/src/Makefile @@ -66,7 +66,8 @@ OS_OBJECTS = kernel/kernel_start.o kernel/syscalls.o \ kernel/terminal.o kernel/terminal_disk.o \ kernel/vga.o util/memstream.o util/async.o \ crt/c_abi.o crt/string.o crt/quick_exit.o crt/cxx_abi.o crt/mman.o \ - hw/ide.o hw/pit.o hw/pic.o hw/pci_device.o hw/cpu_freq_sampling.o hw/serial.o\ + hw/ide.o hw/pit.o hw/pic.o hw/pci_device.o hw/cpu_freq_sampling.o \ + hw/serial.o hw/apic.o \ virtio/virtio.o virtio/virtio_queue.o virtio/virtionet.o \ net/ethernet.o net/inet_common.o net/ip4/arp.o net/ip4/ip4.o \ net/tcp.o net/tcp_connection.o net/tcp_connection_states.o \ diff --git a/src/debug/test_disk.cpp b/src/debug/test_disk.cpp index 4f6189677b..11b527545d 100644 --- a/src/debug/test_disk.cpp +++ b/src/debug/test_disk.cpp @@ -24,7 +24,7 @@ void Service::start() { printf("buffer %d is not null: %d\n", i, !!buffer); assert(buffer); - });*/ + }); // 2. create alot of sequential jobs of 1024 sectors each // note: if we queue more than this we will run out of RAM static int bufcounter = 0; @@ -91,8 +91,11 @@ void Service::start() } }); // ls }); // disk->auto_detect() + */ printf("*** TEST SERVICE STARTED *** \n"); + void test_APIC(); + test_APIC(); } void list_partitions(decltype(disk) disk) @@ -109,3 +112,10 @@ void list_partitions(decltype(disk) disk) part.name().c_str(), part.lba()); }); } + +#include +void test_APIC() { + + hw::APIC::init(); + +} diff --git a/src/hw/apic.cpp b/src/hw/apic.cpp new file mode 100644 index 0000000000..eaa6c1d42d --- /dev/null +++ b/src/hw/apic.cpp @@ -0,0 +1,111 @@ +// This file is a part of the IncludeOS unikernel - www.includeos.org +// +// Copyright 2015 Oslo and Akershus University College of Applied Sciences +// and Alfred Bratterud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +namespace hw { + + static const uintptr_t IA32_APIC_BASE = 0x1B; + + uint64_t RDMSR(uint32_t addr) + { + uint32_t EAX = 0, EDX = 0; + asm volatile("rdmsr": "=a" (EAX),"=d"(EDX) : "c" (addr)); + return ((uint64_t)EDX << 32) | EAX; + } + + // a single 16-byte aligned APIC register + struct apic_reg + { + uint32_t u32; + }; + + struct apic_registers + { + apic_reg reserv1[2]; // 0000h - 0010h + + apic_reg lapic_id; // 0020h ID + apic_reg lapic_ver; // 0030h VER + apic_reg reserv2[4]; // 0040h - 0070h + + apic_reg task_prio; // 0080h TPR + apic_reg arbi_prio; // 0090h APR + apic_reg proc_prio; // 00A0h PPR + apic_reg eoi; // 00B0h EOI + apic_reg remt_read; // 00C0h RRD + apic_reg logic_dst; // 00D0h + apic_reg dest_fmt; // 00E0h + + apic_reg spur_intv; // 00F0h + + // In-Service Registers (ISRs) + apic_reg isr[8]; // 0100h - 0170h ISR + + // Trigger Mode Registers (TMRs) + apic_reg trig[8]; // 0180h - 01F0h TMR + + // Interrupt Request Registers (IRRs) + apic_reg irr[8]; // 0200h - 0270h TMR + + apic_reg error_stat; // 0280h + apic_reg reserv3[6]; // 0290h - 02F0h + + apic_reg lvt_cmci; // 02F0h + + apic_reg intr_cmd0; // 0300h ICR + apic_reg intr_cmd1; // 0310h ICR + + apic_reg lvt_timer; // 0320h + apic_reg lvt_therm; // 0330h + apic_reg lvt_perf; // 0340h + apic_reg lvt_lint0; // 0350h + apic_reg lvt_lint1; // 0360h + apic_reg lvt_error; // 0370h + // timer initial and current counters + apic_reg initial_cnt; // 0380h RW + apic_reg current_cnt; // 0390h RO + apic_reg reserv4[4]; // 03A0h - 03E0h + + apic_reg div_config; // 03E0h RW + apic_reg reserv5; // 03F0h + + bool x2apic() const noexcept { + return false; + } + + uint32_t get_id() const noexcept { + return (lapic_id.u32 >> 24) & 0xFF; + } + + }; + + void APIC::init() { + + const uint64_t APIC_BASE_MSR = RDMSR(IA32_APIC_BASE); + + // find the LAPICs base address + const uintptr_t APIC_BASE_ADDR = APIC_BASE_MSR & 0xFFFFF000; + printf("APIC base addr: 0x%x\n", APIC_BASE_ADDR); + // acquire infos + auto* regs = (apic_registers*) APIC_BASE_ADDR; + printf("LAPIC id: 0x%x\n", regs->get_id()); + + } + +} From d9af5907be2d2e5b0e66733b5d6204d155e10772 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Wed, 4 May 2016 17:31:33 +0200 Subject: [PATCH 276/311] util: Cleanup membitmap --- api/utility/membitmap.hpp | 144 ++++++++++++++++++-------------------- 1 file changed, 69 insertions(+), 75 deletions(-) diff --git a/api/utility/membitmap.hpp b/api/utility/membitmap.hpp index 8bbe6b5030..e08d4c0dca 100644 --- a/api/utility/membitmap.hpp +++ b/api/utility/membitmap.hpp @@ -25,81 +25,75 @@ * **/ -namespace fs +class MemBitmap { - class MemBitmap +public: + typedef uint32_t word; + static const word WORD_MAX = UINT32_MAX; + typedef uint32_t index_t; + static const int CHUNK_SIZE = sizeof(word) * 8; + + MemBitmap() = default; + MemBitmap(void* location, index_t chunks) + : size_(chunks) + { + _data = reinterpret_cast(location); + } + + // returns the boolean value of the bit located at @n + bool operator[] (index_t n) const + { + return get(n); + } + bool get(index_t b) const + { + return _data[windex(b)] & (1 << woffset(b)); + } + // return the bit-index of the first clear bit + index_t first_free() const + { + // each word + for (index_t i = 0; i < size(); i++) + if (_data[i] != WORD_MAX) { + // each bit + for (index_t b = 0; b < CHUNK_SIZE; b++) + if (!(_data[i] & (1 << b))) { + return i * CHUNK_SIZE + b; + } + } // chunk + return -1; + } // first_free() + + void zero_all() { - public: - typedef uint32_t word; - static const word WORD_MAX = UINT32_MAX; - typedef uint32_t index_t; - static const int CHUNK_SIZE = sizeof(word) * 8; - - MemBitmap() = default; - MemBitmap(void* location, index_t chunks) - { - _data = reinterpret_cast(location); - _size = chunks; - } - - // returns the boolean value of the bit located at @n - inline bool operator[] (index_t n) const - { - return get(n); - } - inline bool get(index_t b) const - { - return _data[windex(b)] & (1 << woffset(b)); - } - // return the bit-index of the first clear bit - index_t first_free() const - { - // each word - for (index_t i = 0; i < _size; i++) - if (_data[i] != WORD_MAX) - { - // each bit - for (index_t b = 0; b < CHUNK_SIZE; b++) - if (!(_data[i] & (1 << b))) - { - return i * CHUNK_SIZE + b; - } - } // chunk - return -1; - } // first_free() - - void zero_all() - { - streamset32(_data, 0, size()); - } - void set(index_t b) - { - _data[windex(b)] |= 1 << (woffset(b)); - } - void clear(index_t b) - { - _data[windex(b)] &= ~(1 << (woffset(b))); - } - void flip(index_t b) - { - _data[windex(b)] ^= 1 << (woffset(b)); - } - - inline char* data() const - { - return (char*) _data; - } - inline size_t size() const - { - return _size * CHUNK_SIZE; - } - - private: - inline index_t windex (index_t b) const { return b / CHUNK_SIZE; } - inline index_t woffset(index_t b) const { return b % CHUNK_SIZE; } - - word* _data{nullptr}; - index_t _size{}; - }; + streamset32(_data, 0, size()); + } + void set(index_t b) + { + _data[windex(b)] |= 1 << woffset(b); + } + void clear(index_t b) + { + _data[windex(b)] &= ~(1 << woffset(b)); + } + void flip(index_t b) + { + _data[windex(b)] ^= 1 << woffset(b); + } + + char* data() const noexcept + { + return (char*) _data; + } + size_t size() const noexcept + { + return size_ * CHUNK_SIZE; + } + +private: + index_t windex (index_t b) const { return b / CHUNK_SIZE; } + index_t woffset(index_t b) const { return b & (CHUNK_SIZE-1); } -} + word* _data {nullptr}; + index_t size_ {}; +}; From 69601b8b533913dfb56de815c0ed5fddab9dec24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Fri, 6 May 2016 12:21:08 +0200 Subject: [PATCH 277/311] inet: added defaulted dhcp timeout parameter to inet4 constructor --- api/net/inet4.hpp | 10 +++++----- api/net/inet4.inc | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/api/net/inet4.hpp b/api/net/inet4.hpp index 977f11f675..e07f8d1f6d 100644 --- a/api/net/inet4.hpp +++ b/api/net/inet4.hpp @@ -34,7 +34,7 @@ namespace net { class DHClient; - + /** A complete IP4 network stack */ template class Inet4 : public Inet{ @@ -96,17 +96,17 @@ namespace net { { dns.resolve(this->dns_server, hostname, func); } - + virtual void set_dns_server(IP4::addr server) override { this->dns_server = server; } - + // handler called after the network successfully, or // unsuccessfully negotiated with DHCP-server // the timeout parameter indicates whether dhcp negotitation failed void on_config(delegate handler); - + /** We don't want to copy or move an IP-stack. It's tied to a device. */ Inet4(Inet4&) = delete; Inet4(Inet4&&) = delete; @@ -117,7 +117,7 @@ namespace net { Inet4(hw::Nic& nic, IP4::addr ip, IP4::addr netmask); /** Initialize with DHCP */ - Inet4(hw::Nic& nic); + Inet4(hw::Nic& nic, double timeout = 10.0); virtual void network_config(IP4::addr addr, IP4::addr nmask, IP4::addr router, IP4::addr dns) override diff --git a/api/net/inet4.inc b/api/net/inet4.inc index dca96f1549..03936bc3e7 100644 --- a/api/net/inet4.inc +++ b/api/net/inet4.inc @@ -79,13 +79,13 @@ namespace net } template inline - Inet4::Inet4(hw::Nic& nic) + Inet4::Inet4(hw::Nic& nic, double timeout) : Inet4(nic, IP4::INADDR_ANY, IP4::INADDR_ANY) { INFO("Inet4", "Trying DHCP..."); dhcp_ = std::make_shared(*this); // 2 second timeout for DHCP-server negotation - dhcp_->negotiate(30.0); + dhcp_->negotiate(timeout); } template inline @@ -95,7 +95,7 @@ namespace net template inline void Inet4::process_sendq(size_t packets) { - + //////////////////////////////////////////// // divide up fairly size_t div = packets / tqa.size(); From 1c4dc6872e1cc2f11142fb9f01f79ac2e4b01e14 Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Fri, 6 May 2016 12:23:19 +0200 Subject: [PATCH 278/311] apic: Initialize lapic --- src/Makefile | 5 ++- src/hw/apic.cpp | 111 ++++++++++++++++++++++++------------------------ 2 files changed, 59 insertions(+), 57 deletions(-) diff --git a/src/Makefile b/src/Makefile index d9f52bf255..cde2fb681e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -67,7 +67,7 @@ OS_OBJECTS = kernel/kernel_start.o kernel/syscalls.o \ kernel/vga.o util/memstream.o util/async.o \ crt/c_abi.o crt/string.o crt/quick_exit.o crt/cxx_abi.o crt/mman.o \ hw/ide.o hw/pit.o hw/pic.o hw/pci_device.o hw/cpu_freq_sampling.o \ - hw/serial.o hw/apic.o \ + hw/serial.o hw/apic.o hw/apic_asm.o \ virtio/virtio.o virtio/virtio_queue.o virtio/virtionet.o \ net/ethernet.o net/inet_common.o net/ip4/arp.o net/ip4/ip4.o \ net/tcp.o net/tcp_connection.o net/tcp_connection_states.o \ @@ -203,6 +203,9 @@ install: $(CRTI_OBJ) $(CRTN_OBJ) @echo "\n" $(CPP) $(CPPOPTS) -x assembler-with-cpp $< -o $@ +%.o: %.asm + nasm -f elf $< -o $@ + # Bootloader ################################################### bootloader: boot/bootloader.asm boot/disk_read_lba.asm diff --git a/src/hw/apic.cpp b/src/hw/apic.cpp index eaa6c1d42d..6820a4872f 100644 --- a/src/hw/apic.cpp +++ b/src/hw/apic.cpp @@ -19,6 +19,36 @@ #include #include +#define LAPIC_ID 0x20 +#define LAPIC_VER 0x30 +#define LAPIC_TPR 0x80 +#define LAPIC_EOI 0x0B0 +#define LAPIC_LDR 0x0D0 +#define LAPIC_DFR 0x0E0 +#define LAPIC_SPURIOUS 0x0F0 +#define LAPIC_ESR 0x280 +#define LAPIC_ICRL 0x300 +#define LAPIC_ICRH 0x310 +#define LAPIC_LVT_TMR 0x320 +#define LAPIC_LVT_PERF 0x340 +#define LAPIC_LVT_LINT0 0x350 +#define LAPIC_LVT_LINT1 0x360 +#define LAPIC_LVT_ERR 0x370 +#define LAPIC_TMRINITCNT 0x380 +#define LAPIC_TMRCURRCNT 0x390 +#define LAPIC_TMRDIV 0x3E0 +#define LAPIC_LAST 0x38F +#define LAPIC_DISABLE 0x10000 +#define LAPIC_SW_ENABLE 0x100 +#define LAPIC_CPUFOCUS 0x200 +#define LAPIC_NMI (4<<8) +#define TMR_PERIODIC 0x20000 +#define TMR_BASEDIV (1<<20) + +extern "C" { + void apic_enable(); +} + namespace hw { static const uintptr_t IA32_APIC_BASE = 0x1B; @@ -31,70 +61,37 @@ namespace hw { } // a single 16-byte aligned APIC register - struct apic_reg - { - uint32_t u32; - }; + typedef uint32_t apic_reg; - struct apic_registers + struct apic { - apic_reg reserv1[2]; // 0000h - 0010h - - apic_reg lapic_id; // 0020h ID - apic_reg lapic_ver; // 0030h VER - apic_reg reserv2[4]; // 0040h - 0070h - - apic_reg task_prio; // 0080h TPR - apic_reg arbi_prio; // 0090h APR - apic_reg proc_prio; // 00A0h PPR - apic_reg eoi; // 00B0h EOI - apic_reg remt_read; // 00C0h RRD - apic_reg logic_dst; // 00D0h - apic_reg dest_fmt; // 00E0h - - apic_reg spur_intv; // 00F0h - - // In-Service Registers (ISRs) - apic_reg isr[8]; // 0100h - 0170h ISR - - // Trigger Mode Registers (TMRs) - apic_reg trig[8]; // 0180h - 01F0h TMR - - // Interrupt Request Registers (IRRs) - apic_reg irr[8]; // 0200h - 0270h TMR + apic(uintptr_t addr) + : base_addr(addr) {} - apic_reg error_stat; // 0280h - apic_reg reserv3[6]; // 0290h - 02F0h - - apic_reg lvt_cmci; // 02F0h - - apic_reg intr_cmd0; // 0300h ICR - apic_reg intr_cmd1; // 0310h ICR - - apic_reg lvt_timer; // 0320h - apic_reg lvt_therm; // 0330h - apic_reg lvt_perf; // 0340h - apic_reg lvt_lint0; // 0350h - apic_reg lvt_lint1; // 0360h - apic_reg lvt_error; // 0370h - // timer initial and current counters - apic_reg initial_cnt; // 0380h RW - apic_reg current_cnt; // 0390h RO - apic_reg reserv4[4]; // 03A0h - 03E0h - - apic_reg div_config; // 03E0h RW - apic_reg reserv5; // 03F0h - - bool x2apic() const noexcept { + bool x2apic() const noexcept { return false; } - uint32_t get_id() const noexcept { - return (lapic_id.u32 >> 24) & 0xFF; + apic_reg get_id() const noexcept { + return (read(LAPIC_ID) >> 24) & 0xFF; } + uint32_t read(apic_reg reg) const noexcept { + auto volatile* addr = (uint32_t volatile*) base_addr; + addr[0] = reg & 0xff; + return addr[4]; + } + void write(apic_reg reg, uint32_t value) { + auto volatile* addr = (uint32_t volatile*) base_addr; + addr[0] = reg & 0xff; + addr[4] = value; + } + + uintptr_t base_addr; }; + static apic lapic; + void APIC::init() { const uint64_t APIC_BASE_MSR = RDMSR(IA32_APIC_BASE); @@ -103,8 +100,10 @@ namespace hw { const uintptr_t APIC_BASE_ADDR = APIC_BASE_MSR & 0xFFFFF000; printf("APIC base addr: 0x%x\n", APIC_BASE_ADDR); // acquire infos - auto* regs = (apic_registers*) APIC_BASE_ADDR; - printf("LAPIC id: 0x%x\n", regs->get_id()); + lapic = apic(APIC_BASE_ADDR); + printf("LAPIC id: 0x%x\n", lapic.get_id()); + + apic_enable(); } From 920d5152973c2f468e477f94e269b6cee46f877b Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Fri, 6 May 2016 12:24:18 +0200 Subject: [PATCH 279/311] apic: Add apic_enable --- .gitignore | 1 + src/hw/apic_asm.asm | 14 ++++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 src/hw/apic_asm.asm diff --git a/.gitignore b/.gitignore index 1a9310d95c..301550c034 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ *.vmdk *.tmp *.d +*.pyc nbproject src/bootloader diff --git a/src/hw/apic_asm.asm b/src/hw/apic_asm.asm new file mode 100644 index 0000000000..516bbc1bcf --- /dev/null +++ b/src/hw/apic_asm.asm @@ -0,0 +1,14 @@ +USE32 + +global apic_enable + +apic_enable: + push ecx + push eax + mov ecx, 1bh + rdmsr + bts eax, 11 + wrmsr + pop eax + pop ecx + ret From 65eab936def5fc44a0cafc76732c6ca2ff7e338e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Fri, 6 May 2016 12:25:00 +0200 Subject: [PATCH 280/311] tcp: fixed multiple callbacks on writerequest on reset --- api/net/tcp.hpp | 14 ++++++++++++++ src/net/tcp_connection.cpp | 6 +----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index 0a7f0954e5..4f4c8d0934 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -679,6 +679,20 @@ namespace net { if(current == q.size()-1) current++; } + + /* + Remove all write requests from queue and signal how much was written for each request. + */ + void reset() { + while(!q.empty()) { + auto& req = q.front(); + // only give callbacks on request who hasnt finished writing + // (others has already been called) + if(req.first.remaining > 0) + req.second(req.first.offset); + q.pop_front(); + } + } }; // < TCP::Connection::WriteQueue diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index 14db6e7a3b..0227787105 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -250,11 +250,7 @@ void Connection::limited_tx() { void Connection::writeq_reset() { debug2(" Reseting.\n"); - while(!writeq.empty()) { - auto& job = writeq.q.front(); - job.second(job.first.offset); - writeq.q.pop_front(); - } + writeq.reset(); } void Connection::open(bool active) { From 726ec5f36d4d54136876a9ba489941825a403b3f Mon Sep 17 00:00:00 2001 From: fwsgonzo Date: Fri, 6 May 2016 12:27:35 +0200 Subject: [PATCH 281/311] apic: Fix construction --- src/hw/apic.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/hw/apic.cpp b/src/hw/apic.cpp index 6820a4872f..4007417d6e 100644 --- a/src/hw/apic.cpp +++ b/src/hw/apic.cpp @@ -90,7 +90,7 @@ namespace hw { uintptr_t base_addr; }; - static apic lapic; + //static apic lapic; void APIC::init() { @@ -100,9 +100,10 @@ namespace hw { const uintptr_t APIC_BASE_ADDR = APIC_BASE_MSR & 0xFFFFF000; printf("APIC base addr: 0x%x\n", APIC_BASE_ADDR); // acquire infos - lapic = apic(APIC_BASE_ADDR); + apic lapic = apic(APIC_BASE_ADDR); printf("LAPIC id: 0x%x\n", lapic.get_id()); + apic_enable(); } From f23459dd844966842f4b8029da29c5bd96f60454 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Fri, 6 May 2016 14:52:47 +0200 Subject: [PATCH 282/311] CMOS-test WIP --- test/cmos/Makefile | 20 +++++++++++ test/cmos/README.md | 7 ++++ test/cmos/run.sh | 2 ++ test/cmos/service.cpp | 78 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+) create mode 100644 test/cmos/Makefile create mode 100644 test/cmos/README.md create mode 100755 test/cmos/run.sh create mode 100644 test/cmos/service.cpp diff --git a/test/cmos/Makefile b/test/cmos/Makefile new file mode 100644 index 0000000000..14defe56c6 --- /dev/null +++ b/test/cmos/Makefile @@ -0,0 +1,20 @@ +################################################# +# IncludeOS SERVICE makefile # +################################################# + +# The name of your service +SERVICE = test_cmos +SERVICE_NAME = CMOS tests + +# Your service parts +FILES = service.cpp +# Your disk image +DISK= +LOCAL_INCLUDES= + +# IncludeOS location +ifndef INCLUDEOS_INSTALL +INCLUDEOS_INSTALL=$(HOME)/IncludeOS_install +endif + +include $(INCLUDEOS_INSTALL)/Makeseed diff --git a/test/cmos/README.md b/test/cmos/README.md new file mode 100644 index 0000000000..00e32646f9 --- /dev/null +++ b/test/cmos/README.md @@ -0,0 +1,7 @@ +# Test C runtime +Essentially this tests global constructors, which needs crti.o, crtn.o etc. to be linked in properly to work. + +Internal test, self-explanatory output. + +Success: Outputs SUCCESS if all tests pass +Fail: Panic on any failed tests diff --git a/test/cmos/run.sh b/test/cmos/run.sh new file mode 100755 index 0000000000..b49e3b012f --- /dev/null +++ b/test/cmos/run.sh @@ -0,0 +1,2 @@ +#! /bin/bash +source ${INCLUDEOS_HOME-$HOME/IncludeOS_install}/etc/run.sh test_cmos.img diff --git a/test/cmos/service.cpp b/test/cmos/service.cpp new file mode 100644 index 0000000000..fc80b84ab9 --- /dev/null +++ b/test/cmos/service.cpp @@ -0,0 +1,78 @@ +// This file is a part of the IncludeOS unikernel - www.includeos.org +// +// Copyright 2015 Oslo and Akershus University College of Applied Sciences +// and Alfred Bratterud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +//#include +#include +#include + +static const uint8_t cmos_out = 0x70; +static const uint8_t cmos_in = 0x71; + +static const uint8_t cmos_no_nmi = 0x80; + +static const uint8_t cmos_sec = 0x0; +static const uint8_t cmos_min = 0x2; +static const uint8_t cmos_hrs = 0x4; +static const uint8_t cmos_day = 0x7; +static const uint8_t cmos_month = 0x8; +static const uint8_t cmos_year = 0x9; +static const uint8_t cmos_cent = 0x48; + + +uint8_t cmos_get(uint8_t reg) { + hw::outb(cmos_out, reg | cmos_no_nmi); + return hw::inb(cmos_in); +} + + +using namespace std::chrono; + +void Service::start() +{ + + INFO("Test CMOS","Testing C runtime \n"); + + CHECKSERT(1 == 1, "CMOS exists"); + + unsigned short total; + unsigned char lowmem, highmem; + + lowmem = cmos_get(0x30); + highmem = cmos_get(0x31); + + total = lowmem | highmem << 8; + + printf("Total memory: %i \n", total); + + + hw::PIT::instance().onRepeatedTimeout(1s, [](){ + auto cent = cmos_get(cmos_cent); + auto year = cmos_get(cmos_year); + auto month = cmos_get(cmos_month); + auto day = cmos_get(cmos_day); + auto hrs = cmos_get(cmos_hrs); + auto min = cmos_get(cmos_min); + auto sec = cmos_get(cmos_sec); + + printf("(cent: %i) %i-%i-%i %i:%i:%i \n", + cent, day, month, year, hrs, min, sec); + + }); + + +} From 62d657fb29351453010f1f96128ef2e3a88e176c Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Fri, 6 May 2016 15:52:48 +0200 Subject: [PATCH 283/311] LOL - CMOS time represents decimal values with hex digits :-) --- test/cmos/service.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cmos/service.cpp b/test/cmos/service.cpp index fc80b84ab9..b68f33eff2 100644 --- a/test/cmos/service.cpp +++ b/test/cmos/service.cpp @@ -69,7 +69,7 @@ void Service::start() auto min = cmos_get(cmos_min); auto sec = cmos_get(cmos_sec); - printf("(cent: %i) %i-%i-%i %i:%i:%i \n", + printf("(cent: %i) %x-%x-%x %x:%x:%x \n", cent, day, month, year, hrs, min, sec); }); From 6d3051df311e5f6998e1bf825608a65fd878a514 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Fri, 6 May 2016 16:22:07 +0200 Subject: [PATCH 284/311] tcp: fixed crash on rtx timeout --- src/net/tcp.cpp | 4 ++-- src/net/tcp_connection.cpp | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/net/tcp.cpp b/src/net/tcp.cpp index ef7f3aa113..ef8782afb8 100644 --- a/src/net/tcp.cpp +++ b/src/net/tcp.cpp @@ -22,7 +22,7 @@ using namespace std; using namespace net; - + TCP::TCP(IPStack& inet) : inet_(inet), @@ -112,7 +112,7 @@ bool TCP::port_in_use(const TCP::Port port) const { return true; } return false; -} +} uint16_t TCP::checksum(TCP::Packet_ptr packet) { diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index 0227787105..b66d34cfc5 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -266,7 +266,7 @@ void Connection::open(bool active) { } void Connection::close() { - printf(" Active close on connection. \n"); + debug(" Active close on connection. \n"); try { state_->close(*this); if(is_state(Closed::instance())) @@ -613,8 +613,8 @@ void Connection::rtx_start() { [this, i, rto] { rtx_timer.active = false; - printf(" %i Timed out (%f). FS: %u, i: %u rt_i: %u\n", - local_port_, rto, flight_size(), i, rtx_timer.i); + printf(" %s Timed out (%f). FS: %u, i: %u rt_i: %u\n", + to_string().c_str(), rto, flight_size(), i, rtx_timer.i); rtx_timeout(); }); rtx_timer.i++; @@ -664,7 +664,8 @@ void Connection::rtx_timeout() { rttm.RTO = 3.0; } // timer need to be restarted - rtx_start(); + if(!rtx_timer.active) + rtx_start(); /* [RFC 5681] p. 7 From 7b75f16e653fa85c225688c2638c600655e0eac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Fri, 6 May 2016 17:14:18 +0200 Subject: [PATCH 285/311] tcp: fixed state transistion to correctly close --- src/net/tcp_connection_states.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net/tcp_connection_states.cpp b/src/net/tcp_connection_states.cpp index 133cc06d2e..f4ca0b9cc9 100644 --- a/src/net/tcp_connection_states.cpp +++ b/src/net/tcp_connection_states.cpp @@ -1083,8 +1083,8 @@ State::Result Connection::Established::handle(Connection& tcp, TCP::Packet_ptr i // 8. check FIN bit if(in->isset(FIN)) { - process_fin(tcp, in); tcp.set_state(Connection::CloseWait::instance()); + process_fin(tcp, in); return OK; } From 7b80dc894d19029674cf19adaf8b036fe24654b4 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sun, 8 May 2016 11:46:50 +0200 Subject: [PATCH 286/311] Added CMOS interface and basic RTC (wallclock) functionality --- api/hw/cmos.hpp | 183 ++++++++++++++++++++++++++++++++++++++++++++++++ src/Makefile | 2 +- src/hw/cmos.cpp | 43 ++++++++++++ 3 files changed, 227 insertions(+), 1 deletion(-) create mode 100644 api/hw/cmos.hpp create mode 100644 src/hw/cmos.cpp diff --git a/api/hw/cmos.hpp b/api/hw/cmos.hpp new file mode 100644 index 0000000000..d49faa5633 --- /dev/null +++ b/api/hw/cmos.hpp @@ -0,0 +1,183 @@ +// This file is a part of the IncludeOS unikernel - www.includeos.org +// +// Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences +// and Alfred Bratterud +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CMOS_HPP +#define CMOS_HPP + +#include + +/** Functions / classes for x86 CMOS / RTC interaction */ +namespace cmos { + + using port_t = const uint8_t; + using reg_t = const uint8_t; + using bit_t = const uint8_t; + + + // CMOS layout source: + // http://bos.asmhackers.net/docs/timer/docs/cmos.pdf + static port_t select = 0x70; + static port_t data = 0x71; + + static bit_t no_nmi = 0x80; + + // CMOS Time (RTC) registers + static reg_t r_sec = 0x0; + static reg_t r_min = 0x2; + static reg_t r_hrs = 0x4; + static reg_t r_dow = 0x6; + static reg_t r_day = 0x7; + static reg_t r_month = 0x8; + static reg_t r_year = 0x9; + static reg_t r_cent = 0x48; + + // RTC Alarm registers + static reg_t r_alarm_sec = 0x1; + static reg_t r_alarm_min = 0x3; + static reg_t r_alarm_hrs = 0x5; + static reg_t r_alarm_day = 0x5; + + + // Status reg. A + static reg_t r_status_a = 0xa; + static bit_t a_time_update_in_progress = 0x80; + + // Status reg. B + static reg_t r_status_b = 0xb; + static bit_t b_update_cycle_normal = 0x80; + static bit_t b_periodic_int_enabled = 0x40; + static bit_t b_alarm_int_enabled = 0x20; + static bit_t b_update_ended_int = 0x10; + static bit_t b_square_wave_enabled = 0x8; + static bit_t b_binary_mode = 0x4; + static bit_t b_24_hr_clock = 0x2; + static bit_t b_daylight_savings_enabled = 0x1; + + // Status reg. C ... (incomplete) + static reg_t r_status_c = 0xc; + static reg_t r_status_d = 0xd; + + + /** Get the contents of a CMOS register */ + inline uint8_t get(reg_t reg) { + hw::outb(select, reg | no_nmi); + return hw::inb(data); + } + + /** Set the contents of a CMOS register */ + inline void set(reg_t reg, uint8_t bits) { + printf("CMOS setting bits 0x%x in reg. 0x%x \n", bits, reg); + hw::outb(select, reg | no_nmi); + hw::outb(data, bits); + } + + /** Check if the CMOS time registers are being updated */ + inline bool update_in_progress(){ + return get(r_status_a) & a_time_update_in_progress; + } + + + /** + * A representation of x86 RTC time. + * With calculation of seconds since epoch and internet timestamp. + */ + class Time { + + public: + + /** + * Data fields of cmos::Time. + * (For initialization. Recommended practice by CG I.24) + **/ + struct Fields { + uint8_t century = 0; + uint8_t year = 0; + uint8_t month = 0; + uint8_t day_of_month = 0; + uint8_t day_of_week = 0; + uint8_t hour = 0; + uint8_t minute = 0; + uint8_t second = 0; + }; + + inline uint8_t century() { return f.century; } + inline uint16_t year() { return (f.century + 20) * 100 + f.year; } + inline uint8_t month() { return f.month; } + inline uint8_t day_of_month() { return f.day_of_month; } + inline uint8_t day_of_week() { return f.day_of_week; } + inline uint8_t hour() { return f.hour; } + inline uint8_t minute() { return f.minute; } + inline uint8_t second() { return f.second; } + + /** + * Populate with data from CMOS. + * + * @warning This is a very expensive operation causing several VM-exits + **/ + Time hw_update(); + + Time() = default; + Time(Time&) = default; + Time(Time&&) = default; + ~Time() = default; + Time& operator=(Time&) = default; + Time& operator=(Time&&) = default; + + /** Constructor with all fields. **/ + Time (Time::Fields fields) { f = fields; } + + /** Timestamp string in RFC 3339 format. Aka. Internet Timestamp. */ + std::string to_string(); + + static inline bool is_leap_year(uint32_t year) { + return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); + } + + /** Day-number of current year. **/ + int day_of_year(); + + /** + * POSIX seconds since Epoch + * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_15 + **/ + inline uint32_t to_epoch(){ + uint32_t tm_year = year() - 1900; + uint32_t tm_yday = day_of_year() - 1; // Days since jan. 1st. + return f.second + f.minute * 60 + f.hour * 3600 + tm_yday * 86400 + + (tm_year - 70) * 31536000 + ((tm_year - 69) / 4) * 86400 - + ((tm_year - 1) / 100) * 86400 + ((tm_year + 299) / 400) * 86400; + } + + private: + + Fields f; + + }; // class cmos::Time + + /** + * Get current time. + * + * @warning: Expensive. This is a very expensive operation causing + * several VM-exits. + **/ + inline Time now() { + return Time().hw_update(); + }; + +} // namespace cmos + +#endif diff --git a/src/Makefile b/src/Makefile index cde2fb681e..dc9eee7b28 100644 --- a/src/Makefile +++ b/src/Makefile @@ -67,7 +67,7 @@ OS_OBJECTS = kernel/kernel_start.o kernel/syscalls.o \ kernel/vga.o util/memstream.o util/async.o \ crt/c_abi.o crt/string.o crt/quick_exit.o crt/cxx_abi.o crt/mman.o \ hw/ide.o hw/pit.o hw/pic.o hw/pci_device.o hw/cpu_freq_sampling.o \ - hw/serial.o hw/apic.o hw/apic_asm.o \ + hw/serial.o hw/apic.o hw/apic_asm.o hw/cmos.o\ virtio/virtio.o virtio/virtio_queue.o virtio/virtionet.o \ net/ethernet.o net/inet_common.o net/ip4/arp.o net/ip4/ip4.o \ net/tcp.o net/tcp_connection.o net/tcp_connection_states.o \ diff --git a/src/hw/cmos.cpp b/src/hw/cmos.cpp new file mode 100644 index 0000000000..7cd15a5694 --- /dev/null +++ b/src/hw/cmos.cpp @@ -0,0 +1,43 @@ +#include + +cmos::Time cmos::Time::hw_update() { + // We're supposed to check this before every read + while (update_in_progress()); + f.second = get(r_sec); + f.minute = get(r_min); + f.hour = get(r_hrs); + f.day_of_week = get(r_dow); + f.day_of_month = get(r_day); + f.month = get(r_month); + f.year = get(r_year); + f.century = get(r_cent); + + return *this; +} + + +std::string cmos::Time::to_string(){ + std::array str; + sprintf(str.data(), "%.2i-%.2i-%iT%.2i:%.2i:%.2iZ", + (f.century + 20) * 100 + f.year, + f.month, + f.day_of_month, + f.hour, f.minute, f.second); + return std::string(str.data(), str.size()); +} + + +int cmos::Time::day_of_year() { + static std::array days_in_normal_month = + {{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }}; + + int res = f.day_of_month; + auto month = f.month; + while (month --> 0) + res += days_in_normal_month[ month ]; + + if (is_leap_year(year()) && f.month > 2) + res += 1; + + return res; +} From 6ce5b09c916397abbf22a4ccecf3c6fdc8896077 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sun, 8 May 2016 11:47:21 +0200 Subject: [PATCH 287/311] CMOS-test (WIP) updated to use new cmos interface --- test/cmos/service.cpp | 92 ++++++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 37 deletions(-) diff --git a/test/cmos/service.cpp b/test/cmos/service.cpp index b68f33eff2..475f5e8c4b 100644 --- a/test/cmos/service.cpp +++ b/test/cmos/service.cpp @@ -16,28 +16,10 @@ // limitations under the License. #include -//#include -#include -#include - -static const uint8_t cmos_out = 0x70; -static const uint8_t cmos_in = 0x71; - -static const uint8_t cmos_no_nmi = 0x80; +#include -static const uint8_t cmos_sec = 0x0; -static const uint8_t cmos_min = 0x2; -static const uint8_t cmos_hrs = 0x4; -static const uint8_t cmos_day = 0x7; -static const uint8_t cmos_month = 0x8; -static const uint8_t cmos_year = 0x9; -static const uint8_t cmos_cent = 0x48; - - -uint8_t cmos_get(uint8_t reg) { - hw::outb(cmos_out, reg | cmos_no_nmi); - return hw::inb(cmos_in); -} +#include +#include using namespace std::chrono; @@ -52,27 +34,63 @@ void Service::start() unsigned short total; unsigned char lowmem, highmem; - lowmem = cmos_get(0x30); - highmem = cmos_get(0x31); + lowmem = cmos::get(0x30); + highmem = cmos::get(0x31); total = lowmem | highmem << 8; printf("Total memory: %i \n", total); - - hw::PIT::instance().onRepeatedTimeout(1s, [](){ - auto cent = cmos_get(cmos_cent); - auto year = cmos_get(cmos_year); - auto month = cmos_get(cmos_month); - auto day = cmos_get(cmos_day); - auto hrs = cmos_get(cmos_hrs); - auto min = cmos_get(cmos_min); - auto sec = cmos_get(cmos_sec); - - printf("(cent: %i) %x-%x-%x %x:%x:%x \n", - cent, day, month, year, hrs, min, sec); + auto regB = cmos::get(cmos::r_status_b); + printf("RegB: 0x%x Binary mode/daylight: %i, 12-hr-mode: %i \n", + regB, + regB & cmos::b_daylight_savings_enabled, + regB & cmos::b_24_hr_clock); + + cmos::set(cmos::r_status_b, cmos::b_24_hr_clock | cmos::b_binary_mode); + + regB = cmos::get(cmos::r_status_b); + printf("RegB: 0x%x Binary mode/daylight: %i, 12-hr-mode: %i \n", + regB, + regB & cmos::b_daylight_savings_enabled, + regB & cmos::b_24_hr_clock); + + uint32_t wraps = 0; + uint32_t i = 0; + + while (!cmos::update_in_progress()) { + i++; + if (i == 0) { + wraps++; + printf("Wrapped %i times, still no update \n", wraps); + std::cout << cmos::now().to_string() << "\n"; + if (wraps > 10) + panic("CMOS time didn't update after 10 * 2^32 increments."); + } + }; + + CHECKSERT(1, "CMOS updated"); + + auto tsc_base1 = OS::cycles_since_boot(); + + hw::PIT::instance().onRepeatedTimeout(1s, [tsc_base1](){ + static auto tsc_base = tsc_base1; + uint64_t ticks_pr_sec = OS::cycles_since_boot() - tsc_base; + auto tsc1 = OS::cycles_since_boot(); + auto rtc1 = cmos::now(); + auto tsc2 = OS::cycles_since_boot(); + auto tsc3 = OS::cycles_since_boot(); + + printf(" Cycles last sec: %llu \n", ticks_pr_sec); + printf(" Reading CMOS Wall-clock took: %llu cycles \n", tsc2 - tsc1); + printf(" RDTSC took: %llu cycles \n", tsc3 - tsc2); + + printf("\n"); + printf("Internet timestamp: %s\n",rtc1.to_string().c_str()); + printf("Seconds since Epoch: %i\n",rtc1.to_epoch()); + printf("Day of year: %i\n", rtc1.day_of_year()); + printf("-------------------------------- \n\n"); + tsc_base = OS::cycles_since_boot(); }); - - } From 1859506811baec1d15ad0a9e176d847faa92cfda Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sat, 7 May 2016 12:52:09 +0200 Subject: [PATCH 288/311] Testing span bounds chekcing + span and std::regex --- test/GSL/run.sh | 3 +-- test/GSL/service.cpp | 38 +++++++++++++++++++++++++++++++++++--- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/test/GSL/run.sh b/test/GSL/run.sh index 3b2132d2cb..923937b16d 100755 --- a/test/GSL/run.sh +++ b/test/GSL/run.sh @@ -1,3 +1,2 @@ #! /bin/bash -source ${INCLUDEOS_HOME-$HOME/IncludeOS_install}/etc/run.sh - +source ${INCLUDEOS_HOME-$HOME/IncludeOS_install}/etc/run.sh test_GSL.img diff --git a/test/GSL/service.cpp b/test/GSL/service.cpp index 9a9a89e604..28478755ba 100644 --- a/test/GSL/service.cpp +++ b/test/GSL/service.cpp @@ -23,10 +23,11 @@ #include -#define OS_TERMINATE_ON_CONTRACT_VIOLATION +#define GSL_THROW_ON_CONTRACT_VIOLATION #include #include #include +#include int clock_gettime(clockid_t clk_id, struct timespec *tp){ (void*)clk_id; @@ -141,7 +142,7 @@ const lest::test test_basic_gsl[] = { } WHEN ("We use std::array") { - std::array my_array {'G','S','L',' ','l','o', 'o', 'k', 's', ' ', 'n', 'i', 'c', 'e'}; + std::array my_array {{'G','S','L',' ','l','o', 'o', 'k', 's', ' ', 'n', 'i', 'c', 'e'}}; THEN("we're perfectly safe"){ EXPECT( Mem::count(my_array) == my_array.size() ); } @@ -153,6 +154,18 @@ const lest::test test_basic_gsl[] = { THEN ("Span helps us avoid decay to pointer") { EXPECT( Mem::count(str2) == sizeof(str2)); } + + AND_THEN("Using a span we can't iterate too far") { + + gsl::span strspan{str2, 5}; + auto it = strspan.begin(); + for (; it!= strspan.end(); it++) + printf("'%c' ", *it); + + it++; + EXPECT_THROWS(printf("DANGER: '%c' \n", *it)); + + } } } @@ -182,10 +195,29 @@ const lest::test test_basic_gsl[] = { } } + } + },{ + CASE ("Using std::regex on a span") { + + std::string my_string = "GET /asdf%C3%B8lkj/&%C3%A6%C3%B8asldkfpoij09j13osmdv HTTP/1.1\n"; + gsl::span my_span {my_string}; + + for (auto c : my_span) + printf("%c",c); + printf("\n"); + std::regex re_get("GET .*\n"); + printf("Match: %i \n", std::regex_match(my_string, re_get)); + + /** + * WARNING: HORRIBLE HACK + * Unfortunately gsl::span is still not compatible with std::regex + * See: https://github.com/Microsoft/GSL/issues/271 + **/ + EXPECT( std::regex_match(my_span.data(), my_span.data() + my_span.size(), re_get) ); } - } + }, }; void Service::start() From d2348dd4d408ab2566f5f7a854f5d5ae61b182a7 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sat, 7 May 2016 12:52:27 +0200 Subject: [PATCH 289/311] Updated GSL reference --- mod/GSL | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/GSL b/mod/GSL index 85ffc8d222..a9f865900d 160000 --- a/mod/GSL +++ b/mod/GSL @@ -1 +1 @@ -Subproject commit 85ffc8d222957ca7d6d30fb75fa61fe1e01fa1d4 +Subproject commit a9f865900d28b854de5ead971aadb82e5ef9ed40 From 914cc80e9b92f2a00ec3d70e7c12e7619b63446a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Tue, 10 May 2016 17:32:26 +0200 Subject: [PATCH 290/311] tcp: now renewing instead of reseting read buffer --- api/net/tcp.hpp | 13 ++++++++++++- src/net/tcp_connection.cpp | 8 ++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index 4f4c8d0934..d9b80bd229 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -519,12 +519,22 @@ namespace net { return length > 0; } - inline void clear() { + void clear() { memset(begin(), 0, offset); remaining = capacity(); offset = 0; push = false; } + + /* + Renews the ReadBuffer by assigning a new buffer_t, releasing ownership + */ + inline void renew() { + remaining = capacity(); + offset = 0; + buffer = buffer_t(new uint8_t[remaining], std::default_delete()); + push = false; + } }; // < Connection::ReadBuffer @@ -720,6 +730,7 @@ namespace net { */ struct Disconnect; + // TODO: Remove reference to Connection, probably not needed.. using DisconnectCallback = delegate, Disconnect)>; /* diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index b66d34cfc5..17d9cdbd8d 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -78,8 +78,8 @@ size_t Connection::receive(const uint8_t* data, size_t n, bool PUSH) { assert(buf.full()); // signal the user read_request.callback(buf.buffer, buf.size()); - // reset the buffer - buf.clear(); + // renew the buffer, releasing the old one + buf.renew(); } n -= read; received += read; @@ -91,8 +91,8 @@ size_t Connection::receive(const uint8_t* data, size_t n, bool PUSH) { if(PUSH) { buf.push = PUSH; read_request.callback(buf.buffer, buf.size()); - // reset the buffer - buf.clear(); + // renew the buffer, releasing the old one + buf.renew(); } return received; From f394c60b7f6b8f97a0f97c875387b0d9d832d701 Mon Sep 17 00:00:00 2001 From: Martin Nordsletten Date: Thu, 12 May 2016 18:00:00 +0200 Subject: [PATCH 291/311] Added option to get only name of complete tests Used by jenkins to only run tests that are ready to run. This means that as soon as tests are complete they will be added to jenkins. --- test/validate_all.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/validate_all.sh b/test/validate_all.sh index ea772bf748..b0b11ecf3e 100755 --- a/test/validate_all.sh +++ b/test/validate_all.sh @@ -1,2 +1,8 @@ #! /bin/bash -for t in `ls -d */`; do ./validate_test.py $t; done +if [ $# -eq 0 ] + then + for t in `ls -d */`; do ./validate_test.py $t; done + exit +fi + +for t in `ls -d */`; do ./validate_test.py $t | grep PASS | rev | cut -d "/" -f1 | rev; done From 5ea68e079f02ab396ea8cea6e6732fc465ee0c09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Fri, 13 May 2016 12:25:49 +0200 Subject: [PATCH 292/311] tcp: fixed bug when chaining write calls --- api/net/tcp.hpp | 14 ++++++++------ src/net/tcp_connection.cpp | 2 ++ src/util/async.cpp | 3 ++- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index d9b80bd229..4049f4a475 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -621,6 +621,7 @@ namespace net { and "step back". */ void acknowledge(size_t bytes) { + debug2(" Acknowledge %u bytes\n",bytes); while(bytes and !q.empty()) { auto& buf = q.front().first; @@ -667,14 +668,15 @@ namespace net { auto& buf = q[current-1].first; buf.advance(bytes); - debug2(" Advance: off=%u rem=%u ack=%u\n", - buf.offset, buf.remaining, buf.acknowledged); + debug2(" Advance: bytes=%u off=%u rem=%u ack=%u\n", + bytes, buf.offset, buf.remaining, buf.acknowledged); if(!buf.remaining) { debug(" Advance: Done (%u)\n", buf.offset); - q[current-1].second(buf.offset); - current++; + // make sure to advance current before callback is made, + // but after index (current) is received. + q[current++-1].second(buf.offset); } } @@ -684,7 +686,7 @@ namespace net { */ void push_back(const WriteRequest& wr) { q.push_back(wr); - debug2(" Inserted WR: off=%u rem=%u ack=%u\n", + debug(" Inserted WR: off=%u rem=%u ack=%u\n", wr.first.offset, wr.first.remaining, wr.first.acknowledged); if(current == q.size()-1) current++; @@ -778,7 +780,7 @@ namespace net { case CLOSING: return "Connection closing"; case REFUSED: - return "Conneciton refused"; + return "Connection refused"; case RESET: return "Connection reset"; default: diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index 17d9cdbd8d..824a156e13 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -103,6 +103,8 @@ void Connection::write(WriteBuffer buffer, WriteCallback callback) { try { // try to write auto written = state_->send(*this, buffer); + debug(" off=%u rem=%u written=%u\n", + buffer.offset, buffer.remaining, written); // put request in line writeq.push_back({buffer, callback}); // if data was written, advance diff --git a/src/util/async.cpp b/src/util/async.cpp index 65bb9638e6..fdb67a3c53 100644 --- a/src/util/async.cpp +++ b/src/util/async.cpp @@ -26,7 +26,7 @@ void Async::upload_file( [length, next] (size_t n) { // if all data written, go to next chunk - printf("sock write: %u / %u\n", n, length); + debug("sock write: %u / %u\n", n, length); next(n == length); }, true); @@ -63,6 +63,7 @@ void Async::disk_transfer( fs::buffer_t buffer, uint64_t length) { + debug(" len=%llu\n",length); if (err) { printf("%s\n", err.to_string().c_str()); callback(err, false); From 3c2a3dbfc19c1e71db593ab4b1b70c169425bc6f Mon Sep 17 00:00:00 2001 From: Martin Nordsletten Date: Fri, 13 May 2016 15:12:57 +0200 Subject: [PATCH 293/311] Made validate_all.sh a little more easy to read Added an actual name to the option. --- test/validate_all.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/validate_all.sh b/test/validate_all.sh index b0b11ecf3e..620f15de59 100755 --- a/test/validate_all.sh +++ b/test/validate_all.sh @@ -1,8 +1,8 @@ #! /bin/bash -if [ $# -eq 0 ] +if [ "$1" == "-onlyNames" ] then - for t in `ls -d */`; do ./validate_test.py $t; done + for t in `ls -d */`; do ./validate_test.py $t | grep PASS | rev | cut -d "/" -f1 | rev; done exit fi -for t in `ls -d */`; do ./validate_test.py $t | grep PASS | rev | cut -d "/" -f1 | rev; done +for t in `ls -d */`; do ./validate_test.py $t; done From ca5cd48b3168984a62c3c18a9fcb89b22b16f6bf Mon Sep 17 00:00:00 2001 From: Martin Nordsletten Date: Thu, 19 May 2016 11:48:01 +0200 Subject: [PATCH 294/311] Added back shields Only build from bundle is done at the moment. These shields are based on the pipeline functionality in Jenkins and they will automatically perform all tests approved by the validate_test.py script in the test folder. --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c7c444d4f4..0f8112efd5 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,12 @@ IncludeOS is free software, with "no warranties or restrictions of any kind". ## Build status -We're working towards automating everything with our Jenkins CI server. Unfortunately he was recently hacked and is being cloned from DNA recovered from a mosqito in resin plus pig stem cells as we speak. He'll be back on his feet and just like before (ish) pretty soon. +We're working towards automating everything with our Jenkins CI server. The tests performed to generate these badges are taken from the tests folder. More tests are added regularly, so to see which tests have been completed to generate the results click the corresponding badge. + +| | Build from bundle | Build from source | +|--------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------| +| Master | [![Build Status](https://jenkins.includeos.org/buildStatus/icon?job=shield_master_bundle_pipe)](https://jenkins.includeos.org/job/shield_master_bundle_pipe/) | Coming soon | +| Dev | [![Build Status](https://jenkins.includeos.org/buildStatus/icon?job=shield_dev_bundle_pipe)](https://jenkins.includeos.org/job/shield_dev_bundle_pipe/) | Coming soon | ### Key features * **Extreme memory footprint**: A minimal bootable image, including bootloader, operating system components and a complete C++ standard library is currently 693K when optimized for size. From d10d7e01b7bb15d9e3ce4020fc71ce7b36dcb3eb Mon Sep 17 00:00:00 2001 From: Martin Nordsletten Date: Thu, 19 May 2016 15:36:24 +0200 Subject: [PATCH 295/311] Fixed virtio_block test It was complaining about: error: reference to non-static member function must be called; --- test/virtio_block/service.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/virtio_block/service.cpp b/test/virtio_block/service.cpp index bfce3b43d7..e528a4124b 100644 --- a/test/virtio_block/service.cpp +++ b/test/virtio_block/service.cpp @@ -57,11 +57,11 @@ void Service::start() // go through directory entries for (auto& e : *ents) { printf("%s: %s\t of size %llu bytes (CL: %llu)\n", - e.type_string().c_str(), e.name().c_str(), e.size, e.block); + e.type_string().c_str(), e.name().c_str(), e.size(), e.block); if (e.is_file()) { printf("*** Read %s\n", e.name().c_str()); - disk->fs().read(e, 0, e.size, + disk->fs().read(e, 0, e.size(), [e] (fs::error_t err, fs::buffer_t buffer, size_t len) { if (err) { printf("Failed to read %s!\n", e.name().c_str()); From 00c628f022e106e3d67f07bc7579775172c30513 Mon Sep 17 00:00:00 2001 From: Martin Nordsletten Date: Thu, 19 May 2016 16:56:59 +0200 Subject: [PATCH 296/311] Fix for #311 .tar.gz error Git command now performed in the source directory. Be careful with underscores after variable names in bash. This caused the second error. --- etc/create_binary_bundle.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/etc/create_binary_bundle.sh b/etc/create_binary_bundle.sh index d883c6c9f3..27364bb8eb 100755 --- a/etc/create_binary_bundle.sh +++ b/etc/create_binary_bundle.sh @@ -1,8 +1,11 @@ #! /bin/bash # Zip-file name +[ ! -v INCLUDEOS_SRC ] && INCLUDEOS_SRC=$HOME/IncludeOS +pushd $INCLUDEOS_SRC tag=`git describe --abbrev=0` filename_tag=`echo $tag | tr . -` +popd # Where to place the installation bundle DIR_NAME="IncludeOS_install" @@ -13,7 +16,7 @@ DIR_NAME="IncludeOS_install" echo ">>> Creating Installation Bundle as $INSTALL_DIR" -OUTFILE="$DIR_NAME_$filename_tag.tar.gz" +OUTFILE="${DIR_NAME}_$filename_tag.tar.gz" newlib=$TEMP_INSTALL_DIR/i686-elf/lib llvm=$BUILD_DIR/build_llvm From 80a19268261cb5427c7c1afa8676bda17589a4a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Fri, 20 May 2016 15:57:24 +0200 Subject: [PATCH 297/311] tcp: hotfix when limited tx is active --- api/net/tcp.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index 4049f4a475..de9a360ba4 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -1626,15 +1626,16 @@ namespace net { inline void reno_deflate_cwnd(uint16_t n) { cb.cwnd -= (n >= SMSS()) ? n-SMSS() : n; } - // TODO: Flight size goes from zero to max uint32 when limited tx inline void reduce_ssthresh() { auto fs = flight_size(); printf(" FlightSize: %u\n", fs); + auto two_seg = 2*(uint32_t)SMSS(); + if(limited_tx_) - fs -= 2*(uint32_t)SMSS(); + fs = (fs >= two_seg) ? fs - two_seg : 0; - cb.ssthresh = std::max( (fs / 2), (2 * (uint32_t)SMSS()) ); + cb.ssthresh = std::max( (fs / 2), two_seg ); printf(" Slow start threshold reduced: %u\n", cb.ssthresh); } From 4a2097cc7754fbf215c3d095f661aeccb9562754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=85kesson?= Date: Fri, 20 May 2016 18:23:57 +0200 Subject: [PATCH 298/311] tcp: silenced print --- api/net/tcp.hpp | 8 ++++---- src/net/tcp_connection.cpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/api/net/tcp.hpp b/api/net/tcp.hpp index de9a360ba4..12c8686ff2 100644 --- a/api/net/tcp.hpp +++ b/api/net/tcp.hpp @@ -1628,7 +1628,7 @@ namespace net { inline void reduce_ssthresh() { auto fs = flight_size(); - printf(" FlightSize: %u\n", fs); + debug2(" FlightSize: %u\n", fs); auto two_seg = 2*(uint32_t)SMSS(); @@ -1636,12 +1636,12 @@ namespace net { fs = (fs >= two_seg) ? fs - two_seg : 0; cb.ssthresh = std::max( (fs / 2), two_seg ); - printf(" Slow start threshold reduced: %u\n", + debug2(" Slow start threshold reduced: %u\n", cb.ssthresh); } inline void fast_retransmit() { - printf(" Fast retransmit initiated.\n"); + debug(" Fast retransmit initiated.\n"); // reduce sshtresh reduce_ssthresh(); // retransmit segment starting SND.UNA @@ -1655,7 +1655,7 @@ namespace net { reno_fpack_seen = false; fast_recovery = false; cb.cwnd = std::min(cb.ssthresh, std::max(flight_size(), (uint32_t)SMSS()) + SMSS()); - printf(" Finished Fast Recovery - Cwnd: %u\n", cb.cwnd); + debug(" Finished Fast Recovery - Cwnd: %u\n", cb.cwnd); } inline bool reno_full_ack(Seq ACK) diff --git a/src/net/tcp_connection.cpp b/src/net/tcp_connection.cpp index 824a156e13..d702cf4ab9 100644 --- a/src/net/tcp_connection.cpp +++ b/src/net/tcp_connection.cpp @@ -296,7 +296,7 @@ void Connection::segment_arrived(TCP::Packet_ptr incoming) { parse_options(incoming); } catch(TCPBadOptionException err) { - printf(" %s \n", err.what()); + debug(" %s \n", err.what()); } } @@ -615,7 +615,7 @@ void Connection::rtx_start() { [this, i, rto] { rtx_timer.active = false; - printf(" %s Timed out (%f). FS: %u, i: %u rt_i: %u\n", + debug(" %s Timed out (%f). FS: %u, i: %u rt_i: %u\n", to_string().c_str(), rto, flight_size(), i, rtx_timer.i); rtx_timeout(); }); From 9eb0ef800e490940a3d7bfd5cf9c947f2ebb9fd2 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sat, 21 May 2016 09:56:44 +0000 Subject: [PATCH 299/311] vmbuilder now builds with clang-3.8 --- vmbuild/Makefile | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/vmbuild/Makefile b/vmbuild/Makefile index db9281620e..7fc445c93f 100644 --- a/vmbuild/Makefile +++ b/vmbuild/Makefile @@ -1,4 +1,4 @@ -CPP=clang++-3.6 +CPP=clang++-3.8 CPPOPTS = -std=c++11 -c -Wall -Wextra -O3 -I. OBJS = vmbuild.o OUT = vmbuild @@ -13,6 +13,3 @@ all: $(OBJS) clean: $(RM) $(OBJS) $(OUT) *~ - - - From bbf057b59c9c2cdc8007044fb0121123fd003349 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sat, 21 May 2016 10:10:10 +0000 Subject: [PATCH 300/311] Fixed service.cpp to work with IP-constructor --- examples/demo_service/service.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/demo_service/service.cpp b/examples/demo_service/service.cpp index b16cdbbb6d..6a599011ec 100644 --- a/examples/demo_service/service.cpp +++ b/examples/demo_service/service.cpp @@ -72,10 +72,10 @@ void Service::start() { // Static IP configuration, until we (possibly) get DHCP // @note : Mostly to get a robust demo service that it works with and without DHCP - inet->network_config( {{ 10,0,0,42 }}, // IP - {{ 255,255,255,0 }}, // Netmask - {{ 10,0,0,1 }}, // Gateway - {{ 8,8,8,8 }} ); // DNS + inet->network_config( { 10,0,0,42 }, // IP + { 255,255,255,0 }, // Netmask + { 10,0,0,1 }, // Gateway + { 8,8,8,8 } ); // DNS srand(OS::cycles_since_boot()); From bfb17b48748f412b9a673c8d1a84718830846adb Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sat, 21 May 2016 10:21:38 +0000 Subject: [PATCH 301/311] Run example service with one command --- examples/demo_service/run.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/demo_service/run.sh b/examples/demo_service/run.sh index 3b2132d2cb..ca8b7d3193 100755 --- a/examples/demo_service/run.sh +++ b/examples/demo_service/run.sh @@ -1,3 +1,2 @@ #! /bin/bash -source ${INCLUDEOS_HOME-$HOME/IncludeOS_install}/etc/run.sh - +source ${INCLUDEOS_HOME-$HOME/IncludeOS_install}/etc/run.sh IncludeOS_Demo_Service.img From 4d01f530c4dca8f196fc4c036fdf69a84b656172 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sat, 21 May 2016 10:38:21 +0000 Subject: [PATCH 302/311] Fixed #531 --- etc/install_from_bundle.sh | 2 ++ etc/prepare_ubuntu_deps.sh | 26 ++++++++++++++++++++++++++ install.sh | 7 +------ 3 files changed, 29 insertions(+), 6 deletions(-) create mode 100755 etc/prepare_ubuntu_deps.sh diff --git a/etc/install_from_bundle.sh b/etc/install_from_bundle.sh index 5d14f79160..d89ab849fc 100755 --- a/etc/install_from_bundle.sh +++ b/etc/install_from_bundle.sh @@ -17,6 +17,8 @@ export INCLUDEOS_HOME=$INCLUDEOS_INSTALL_LOC/IncludeOS_install # Install dependencies +$INCLUDEOS_SRC/etc/prepare_ubuntu_deps.sh + DEPENDENCIES="curl make clang-3.8 nasm bridge-utils qemu" echo ">>> Installing dependencies (requires sudo):" echo " Packages: $DEPENDENCIES" diff --git a/etc/prepare_ubuntu_deps.sh b/etc/prepare_ubuntu_deps.sh new file mode 100755 index 0000000000..beb2815d6c --- /dev/null +++ b/etc/prepare_ubuntu_deps.sh @@ -0,0 +1,26 @@ +# Prepare Ubuntu for installing dependencies +# +# Older versions don't have clang-3.8 in their apt source lists + +INCLUDEOS_SRC=${INCLUDEOS_SRC-$HOME/IncludeOS/} +clang_version=${clang_version-3.8} + +UBUNTU_VERSION=`lsb_release -rs` +UBUNTU_CODENAME=`lsb_release -cs` + +if [ $(echo "$UBUNTU_VERSION < 15.10" | bc) -eq 1 ] +then + + DEB_LINE="deb http://llvm.org/apt/$UBUNTU_CODENAME/ llvm-toolchain-$UBUNTU_CODENAME-$clang_version main" + + LINE_EXISTS=$(cat /etc/apt/sources.list | grep -c "$DEB_LINE") + + if [ $LINE_EXISTS -lt 1 ] + then + echo ">>> Adding clang $clang_version to your /etc/apt/sources.list" + wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key|sudo apt-key add - + + echo $DEB_LINE | sudo tee -a /etc/apt/sources.list + sudo apt-get update + fi +fi diff --git a/install.sh b/install.sh index 67807af646..2e987b005c 100755 --- a/install.sh +++ b/install.sh @@ -35,10 +35,7 @@ export binutils_version=2.25 [ ! -v install_llvm_dependencies ] && export install_llvm_dependencies=1 [ ! -v download_llvm ] && export download_llvm=1 - - -# BUILDING IncludeOS -PREREQS_BUILD="build-essential make nasm texinfo clang-$clang_version clang++-$clang_version" +$INCLUDEOS_SRC/etc/prepare_ubuntu_deps.sh echo -e "\n\n >>> Trying to install prerequisites for *building* IncludeOS" echo -e " Packages: $PREREQS_BUILD \n" @@ -65,8 +62,6 @@ fi if [ ! -z $do_llvm ]; then echo -e "\n\n >>> GETTING / BUILDING llvm / libc++ \n" $INCLUDEOS_SRC/etc/build_llvm32.sh - #echo -e "\n\n >>> INSTALLING libc++ \n" - #cp $BUILD_DIR/$llvm_build/lib/libc++.a $INSTALL_DIR/lib/ fi echo -e "\n >>> DEPENDENCIES SUCCESSFULLY BUILT. Creating binary bundle \n" From a1d731911cc0c5dec857eef00740722fa165ac86 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sun, 22 May 2016 09:01:57 +0200 Subject: [PATCH 303/311] Fixed #533 --- etc/install_osx.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/etc/install_osx.sh b/etc/install_osx.sh index cb0de43691..fce3d682e8 100755 --- a/etc/install_osx.sh +++ b/etc/install_osx.sh @@ -170,6 +170,11 @@ echo ">>> Updating git-tags " pushd $INCLUDEOS_SRC git fetch --tags tag=`git describe --abbrev=0` + +echo -e "\n>>> Fetching git submodules " +git submodule init +git submodule update + popd filename_tag=`echo $tag | tr . -` From da6951141a35777622dd42d1d4e2c9981a3e2441 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sun, 22 May 2016 13:28:32 +0200 Subject: [PATCH 304/311] Added back dependency list --- install.sh | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/install.sh b/install.sh index 2e987b005c..daff967281 100755 --- a/install.sh +++ b/install.sh @@ -37,9 +37,13 @@ export binutils_version=2.25 $INCLUDEOS_SRC/etc/prepare_ubuntu_deps.sh +# BUILDING IncludeOS +DEPS_BUILD="build-essential make nasm texinfo clang-$clang_version clang++-$clang_version" + + echo -e "\n\n >>> Trying to install prerequisites for *building* IncludeOS" -echo -e " Packages: $PREREQS_BUILD \n" -sudo apt-get install -y $PREREQS_BUILD +echo -e " Packages: $DEPS_BUILD \n" +sudo apt-get install -y $DEPS_BUILD mkdir -p $BUILD_DIR cd $BUILD_DIR @@ -93,10 +97,10 @@ if [ ! -z $do_includeos ]; then popd # RUNNING IncludeOS - PREREQS_RUN="bridge-utils qemu-kvm" + DEPS_RUN="bridge-utils qemu-kvm" echo -e "\n\n >>> Trying to install prerequisites for *running* IncludeOS" - echo -e " Packages: $PREREQS_RUN \n" - sudo apt-get install -y $PREREQS_RUN + echo -e " Packages: $DEPS_RUN \n" + sudo apt-get install -y $DEPS_RUN # Set up the IncludeOS network bridge echo -e "\n\n >>> Create IncludeOS network bridge *Requires sudo* \n" From aca1ed4f1b1a684c76e8da1d08c84527541efb41 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sun, 22 May 2016 11:58:22 +0000 Subject: [PATCH 305/311] Updated GCC to 6.1.0 --- etc/cross_compiler.sh | 4 +++- install.sh | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/etc/cross_compiler.sh b/etc/cross_compiler.sh index 198c476053..24f18a3f72 100755 --- a/etc/cross_compiler.sh +++ b/etc/cross_compiler.sh @@ -4,9 +4,11 @@ mkdir -p $BUILD_DIR cd $BUILD_DIR +GCC_LOC=ftp://ftp.nluug.nl/mirror/languages/gcc/releases/ + if [ ! -f gcc-$gcc_version.tar.gz ]; then echo -e "\n\n >>> Getting GCC \n" - wget -c --trust-server-name ftp://ftp.uninett.no/pub/gnu/gcc/gcc-$gcc_version/gcc-$gcc_version.tar.gz + wget -c --trust-server-name $GCC_LOC/gcc-$gcc_version/gcc-$gcc_version.tar.gz fi # UNPACK GCC diff --git a/install.sh b/install.sh index daff967281..5b8b12ee6b 100755 --- a/install.sh +++ b/install.sh @@ -21,7 +21,7 @@ export llvm_src=llvm export llvm_build=build_llvm export clang_version=3.8 -export gcc_version=5.1.0 +export gcc_version=6.1.0 export binutils_version=2.25 # Options to skip steps From f4bf25a0f27b5c82c7879e29ada90625396f5237 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sun, 22 May 2016 16:54:11 +0000 Subject: [PATCH 306/311] Updated binutils to v2.26 --- install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.sh b/install.sh index 5b8b12ee6b..a2703b5491 100755 --- a/install.sh +++ b/install.sh @@ -22,7 +22,7 @@ export llvm_build=build_llvm export clang_version=3.8 export gcc_version=6.1.0 -export binutils_version=2.25 +export binutils_version=2.26 # Options to skip steps [ ! -v do_binutils ] && do_binutils=1 From 1beb37a496ac27546b51681055e38913d21d74c6 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sun, 22 May 2016 17:44:47 +0000 Subject: [PATCH 307/311] Updated newlib to v2.4.0. Fixed #534 --- api/sys/features.h | 27 ++++++------------ api/sys/math.h | 8 ++---- api/sys/time.h | 7 ++--- api/sys/wchar.h | 6 ++-- etc/build_llvm32.sh | 62 ++++++++++++++++++------------------------ etc/newlib_clang.patch | 12 ++++---- install.sh | 2 +- src/Makefile | 6 +++- src/seed/Makefile | 2 +- 9 files changed, 56 insertions(+), 76 deletions(-) diff --git a/api/sys/features.h b/api/sys/features.h index 8123fc2450..14d0bec648 100644 --- a/api/sys/features.h +++ b/api/sys/features.h @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -17,25 +17,14 @@ #ifndef SYS_FEATURES_H #define SYS_FEATURES_H - - // Newlib needs this switch to enable clock_gettime etc. - // Also, we'll need posix timers sooner or later -#define _POSIX_TIMERS 1 - -#ifndef __GNUC_PREREQ -#define __GNUC_PREREQ(A, B) 0 /* Nei */ -#endif +// Newlib needs this switch to enable clock_gettime etc. +#define _POSIX_TIMERS 1 -/** Apparently this is necessary in order to build libc++. - @todo : It creates a warning when building os.a; - find another way to provide it to libc++. - */ -#ifndef __GNUC_PREREQ__ -#define __GNUC_PREREQ__(A, B) __GNUC_PREREQ(A, B) -#endif +// Required to pass CMake tests for libc++ +#define __GLIBC_PREREQ__(min, maj) 1 +#define __GLIBC_PREREQ(min, maj) 1 -#define __GLIBC_PREREQ__(A, B) 1 /* Jo. */ -#define __GLIBC_PREREQ(A, B) 1 /* Jo. */ +#include_next #endif diff --git a/api/sys/math.h b/api/sys/math.h index 1117eae483..fca5d9b13f 100644 --- a/api/sys/math.h +++ b/api/sys/math.h @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -59,12 +59,10 @@ long double fdiml(long double, long double); long double fmal(long double, long double, long double); long double fmaxl(long double, long double); long double fminl(long double, long double); -long double hypotl(long double, long double); - long double expl(long double); long double ldexpl(long double, long double); -long double sqrtl(long double); + long double ilogbl(long double); long double lgammal(long double); long double llroundl(long double); diff --git a/api/sys/time.h b/api/sys/time.h index fc24390a5a..ea23f605ad 100644 --- a/api/sys/time.h +++ b/api/sys/time.h @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -18,13 +18,12 @@ #include "features.h" #include_next #include_next + #ifndef SYS_TIME_H #define SYS_TIME_H - // We might possibly need additions here. #define CLOCK_MONOTONIC 4 #endif - diff --git a/api/sys/wchar.h b/api/sys/wchar.h index 24d41af9ff..0e3b142168 100644 --- a/api/sys/wchar.h +++ b/api/sys/wchar.h @@ -6,9 +6,9 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -25,7 +25,7 @@ extern "C" { #endif /** @WARNING Loses precision **/ -static inline long double wcstold (const wchar_t* str, wchar_t** endptr) { +inline long double wcstold (const wchar_t* str, wchar_t** endptr) { return wcstod(str,endptr); } diff --git a/etc/build_llvm32.sh b/etc/build_llvm32.sh index e4f81b3c9a..6433782e53 100755 --- a/etc/build_llvm32.sh +++ b/etc/build_llvm32.sh @@ -9,16 +9,17 @@ trap 'echo -e "\nINSTALL FAILED ON COMMAND: $previous_command\n"' EXIT # llvm_src -> path to clone llvm repo # llvm_build-> path to build llvm-libs. (must beoutside of llvm) # INCLUDEOS_SRC -> InclueOS git source (i.e =$HOME/IncludeOS) +# newlib_inc -> Include-path for newlib headers # OPTIONALS (required the first time, but optional later): # -# $install_llvm_dependencies: required paackages, cmake, ninja etc. +# $install_llvm_dependencies: required paackages, cmake, ninja etc. # $download_llvm: Clone llvm svn sources IncludeOS_sys=$INCLUDEOS_SRC/api/sys - +libcxx_inc=$BUILD_DIR/$llvm_src/projects/libcxx/include if [ ! -z $install_llvm_dependencies ]; then @@ -27,34 +28,34 @@ if [ ! -z $install_llvm_dependencies ]; then fi if [ ! -z $download_llvm ]; then - # Clone LLVM + # Clone LLVM svn co http://llvm.org/svn/llvm-project/llvm/trunk $llvm_src - # git clone http://llvm.org/git/llvm - + # git clone http://llvm.org/git/llvm + # Clone CLANG - not necessary to build only libc++ and libc++abi - # cd llvm/tools + # cd llvm/tools # svn co http://llvm.org/svn/llvm-project/cfe/trunk clang # svn co http://llvm.org/svn/llvm-project/clang-tools-extra/trunk extra - + # Clone libc++, libc++abi, and some extra stuff (recommended / required for clang) cd $llvm_src/projects - + # Compiler-rt svn co http://llvm.org/svn/llvm-project/compiler-rt/trunk compiler-rt # git clone http://llvm.org/git/llvm compiler-rt - + # libc++abi svn co http://llvm.org/svn/llvm-project/libcxxabi/trunk libcxxabi # git clone http://llvm.org/git/libcxxabi - + # libc++ svn co http://llvm.org/svn/llvm-project/libcxx/trunk libcxx # git clone http://llvm.org/git/libcxx - + # libunwind svn co http://llvm.org/svn/llvm-project/libunwind/trunk libunwind #git clone http://llvm.org/git/libunwind - + # Back to start cd ../../ fi @@ -79,12 +80,6 @@ OPTS+=-DCMAKE_BUILD_TYPE=MinSizeRel" " OPTS+=-DCMAKE_C_COMPILER=clang-$clang_version" " OPTS+=-DCMAKE_CXX_COMPILER=clang++-$clang_version" " # -std=c++11" " -# -# WARNING: It seems imossible to pass in cxx-flags like this; I've tried \' \\" \\\" etc. -# -# OPTS+="-DCMAKE_CXX_FLAGS='-I/home/alfred/IncludeOS/stdlib/support -I/usr/local/IncludeOS/i686-elf/include -I/home/alfred/IncludeOS/stdlib/support/newlib -I/home/alfred/IncludeOS/src/include' " -# OPTS+='-DCMAKE_CXX_FLAGS=-I/home/alfred/IncludeOS/stdlib/support -I/usr/local/IncludeOS/i686-elf/include -I/home/alfred/IncludeOS/stdlib/support/newlib -I/home/alfred/IncludeOS/src/include ' - TRIPLE=i686-pc-none-elf OPTS+=-DTARGET_TRIPLE=$TRIPLE" " @@ -113,31 +108,26 @@ OPTS+=-LIBCXXABI_USE_LLVM_UNWINDER=ON" " echo "LLVM CMake Build options:" $OPTS +# CMAKE +# Using Ninja (slightly faster, but not by much) # -# WARNING: The following will cause the "requires std::atomic" error. -# (For some reason - the headers should be the same as in llbm/projects/libcxx/include - our mods causes this?" # -# -I/$IncludeOS_Source/IncludeOS/stdlib - -# Various search-path stuff -# -nostdinc -nostdlib -nodefaultlibs -ffreestanding -isystem /usr/local/IncludeOS/i686/ --sysroot=/usr/local/IncludeOS/i686 - - +# NOTE: It seems impossible to pass in cxx-flags like this; I've tried \' \\" \\\" etc. # -# CONFIGURE +# OPTS+="-DCMAKE_CXX_FLAGS='-I/home/alfred/IncludeOS/stdlib/support -I/usr/local/IncludeOS/i686-elf/include -I/home/alfred/IncludeOS/stdlib/support/newlib -I/home/alfred/IncludeOS/src/include' " +# OPTS+='-DCMAKE_CXX_FLAGS=-I/home/alfred/IncludeOS/stdlib/support -I/usr/local/IncludeOS/i686-elf/include -I/home/alfred/IncludeOS/stdlib/support/newlib -I/home/alfred/IncludeOS/src/include ' # -# Using makefiles -# time cmake -G"Unix Makefiles" $OPTS ../$llvm_src - -llvm_src_verbose=-v -libcxx_inc=$BUILD_DIR/$llvm_src/projects/libcxx/include - -# Using Ninja (slightly faster, but not by much) -cmake -GNinja $OPTS -DCMAKE_CXX_FLAGS="-std=c++11 $llvm_src_verbose -I$IncludeOS_sys -I$libcxx_inc -I$INCLUDEOS_SRC/api -I$newlib_inc -I$INCLUDEOS_SRC/src/include/ -I$INCLUDEOS_SRC/stdlib/support/newlib/ " $BUILD_DIR/$llvm_src # -DCMAKE_CXX_COMPILER='clang++ -std=c++11 +# Include-path ordering: +# 1. IncludeOS_sys has to come first, as it provides lots of C11 prototypes that libc++ relies on, but which newlib does not provide (see our math.h) +# 2. libcxx_inc must come before newlib, due to math.h function wrappers around C99 macros (signbit, nan etc) +# 3. newlib_inc provodes standard C headers +# 4. IncludeOS/api provides sys-specific paths such as "sys/time.h" +# 5. +cmake -GNinja $OPTS -DCMAKE_CXX_FLAGS="-std=c++11 $llvm_src_verbose -I$IncludeOS_sys -I$libcxx_inc -I$newlib_inc -I$INCLUDEOS_SRC/api -I$INCLUDEOS_SRC/src/include/ -I$INCLUDEOS_SRC/stdlib/support/newlib/ " $BUILD_DIR/$llvm_src # -# MAKE +# MAKE # # Using ninja # diff --git a/etc/newlib_clang.patch b/etc/newlib_clang.patch index 2d6f34822b..c9f9327984 100644 --- a/etc/newlib_clang.patch +++ b/etc/newlib_clang.patch @@ -1,6 +1,6 @@ -diff -Naur newlib-2.2.0-1/newlib/libm/machine/i386/f_ldexp.S newlib-2.2.0-1_patched/newlib/libm/machine/i386/f_ldexp.S ---- newlib-2.2.0-1/newlib/libm/machine/i386/f_ldexp.S 2002-12-20 22:31:20.000000000 +0100 -+++ newlib-2.2.0-1_patched/newlib/libm/machine/i386/f_ldexp.S 2015-11-01 17:00:59.215426521 +0100 +diff -Naur newlib-2.4.0/newlib/libm/machine/i386/f_ldexp.S newlib-2.4.0_patched/newlib/libm/machine/i386/f_ldexp.S +--- newlib-2.4.0/newlib/libm/machine/i386/f_ldexp.S 2002-12-20 22:31:20.000000000 +0100 ++++ newlib-2.4.0_patched/newlib/libm/machine/i386/f_ldexp.S 2015-11-01 17:00:59.215426521 +0100 @@ -27,7 +27,7 @@ SYM (_f_ldexp): pushl ebp @@ -10,9 +10,9 @@ diff -Naur newlib-2.2.0-1/newlib/libm/machine/i386/f_ldexp.S newlib-2.2.0-1_patc fldl 8(ebp) fscale fstp st1 -diff -Naur newlib-2.2.0-1/newlib/libm/machine/i386/f_ldexpf.S newlib-2.2.0-1_patched/newlib/libm/machine/i386/f_ldexpf.S ---- newlib-2.2.0-1/newlib/libm/machine/i386/f_ldexpf.S 2002-12-20 22:31:20.000000000 +0100 -+++ newlib-2.2.0-1_patched/newlib/libm/machine/i386/f_ldexpf.S 2015-11-01 16:58:23.646121581 +0100 +diff -Naur newlib-2.4.0/newlib/libm/machine/i386/f_ldexpf.S newlib-2.4.0_patched/newlib/libm/machine/i386/f_ldexpf.S +--- newlib-2.4.0/newlib/libm/machine/i386/f_ldexpf.S 2002-12-20 22:31:20.000000000 +0100 ++++ newlib-2.4.0_patched/newlib/libm/machine/i386/f_ldexpf.S 2015-11-01 16:58:23.646121581 +0100 @@ -27,7 +27,7 @@ SYM (_f_ldexpf): pushl ebp diff --git a/install.sh b/install.sh index a2703b5491..9aea62f534 100755 --- a/install.sh +++ b/install.sh @@ -13,7 +13,7 @@ export build_dir=$HOME/cross-dev # Multitask-parameter to make export num_jobs=-j$((`lscpu -p | tail -1 | cut -d',' -f1` + 1 )) -export newlib_version=2.2.0-1 +export newlib_version=2.4.0 export INCLUDEOS_SRC=`pwd` export newlib_inc=$TEMP_INSTALL_DIR/i686-elf/include diff --git a/src/Makefile b/src/Makefile index dc9eee7b28..fd93c32991 100644 --- a/src/Makefile +++ b/src/Makefile @@ -14,7 +14,11 @@ STACK_PROTECTOR_VALUE=$(shell awk 'BEGIN{print int(rand()*65536)}') # the compiler seems to be really dumb in this regard, creating a misaligned stack left and right CAPABS_COMMON = -mstackrealign -fstack-protector-all -fno-omit-frame-pointer -msse3 -D_STACK_GUARD_VALUE_=$(STACK_PROTECTOR_VALUE) -CAPABS = $(CAPABS_COMMON) -O2 -DNO_DEBUG=1 -DOS_TERMINATE_ON_CONTRACT_VIOLATION +# Various global defines +# * NO_DEBUG Disables output from the debug macro +# * OS_TERMINATE_ON_CONTRACT_VIOLATION provides classic assert-like output from Expects / Ensures +# * _GNU_SOURCE enables POSIX-extensions in newlib, such as strnlen. ("everything newlib has", ref. cdefs.h) +CAPABS = $(CAPABS_COMMON) -O2 -DNO_DEBUG=1 -DOS_TERMINATE_ON_CONTRACT_VIOLATION -D_GNU_SOURCE WARNS = -Wall -Wextra #-pedantic DEBUG_OPTS = -ggdb3 diff --git a/src/seed/Makefile b/src/seed/Makefile index f8e346bd34..d23786918a 100644 --- a/src/seed/Makefile +++ b/src/seed/Makefile @@ -47,7 +47,7 @@ all: CAPABS = $(CAPABS_COMMON) -O2 debug: CAPABS = $(CAPABS_COMMON) -O0 stripped: CAPABS = $(CAPABS_COMMON) -Oz -CPPOPTS = $(CAPABS) $(WARNS) -c -m32 -std=c++14 $(INCLUDES) -D_LIBCPP_HAS_NO_THREADS=1 +CPPOPTS = $(CAPABS) $(WARNS) -c -m32 -std=c++14 $(INCLUDES) -D_LIBCPP_HAS_NO_THREADS=1 -D_GNU_SOURCE LDOPTS = -nostdlib -melf_i386 -N --script=$(INSTALL)/linker.ld # Objects From b90689c4339088e97f7a9346c3a8977124841a9d Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sun, 22 May 2016 20:47:00 +0200 Subject: [PATCH 308/311] Removed unnecessary include-paths for libc++ --- etc/build_llvm32.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/etc/build_llvm32.sh b/etc/build_llvm32.sh index 6433782e53..62c4e75aae 100755 --- a/etc/build_llvm32.sh +++ b/etc/build_llvm32.sh @@ -121,9 +121,7 @@ echo "LLVM CMake Build options:" $OPTS # 1. IncludeOS_sys has to come first, as it provides lots of C11 prototypes that libc++ relies on, but which newlib does not provide (see our math.h) # 2. libcxx_inc must come before newlib, due to math.h function wrappers around C99 macros (signbit, nan etc) # 3. newlib_inc provodes standard C headers -# 4. IncludeOS/api provides sys-specific paths such as "sys/time.h" -# 5. -cmake -GNinja $OPTS -DCMAKE_CXX_FLAGS="-std=c++11 $llvm_src_verbose -I$IncludeOS_sys -I$libcxx_inc -I$newlib_inc -I$INCLUDEOS_SRC/api -I$INCLUDEOS_SRC/src/include/ -I$INCLUDEOS_SRC/stdlib/support/newlib/ " $BUILD_DIR/$llvm_src +cmake -GNinja $OPTS -DCMAKE_CXX_FLAGS="-std=c++11 $llvm_src_verbose -I$IncludeOS_sys -I$libcxx_inc -I$newlib_inc" $BUILD_DIR/$llvm_src # From 6f8b484fef9a38826ff048f2d6c73b7a58e031b6 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sun, 22 May 2016 21:11:52 +0200 Subject: [PATCH 309/311] Update README.md --- README.md | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 0f8112efd5..eb902d694c 100644 --- a/README.md +++ b/README.md @@ -26,20 +26,20 @@ We're working towards automating everything with our Jenkins CI server. The test * **Extreme memory footprint**: A minimal bootable image, including bootloader, operating system components and a complete C++ standard library is currently 693K when optimized for size. * **KVM and VirtualBox support** with full virtualization, using [x86 hardware virtualization](https://en.wikipedia.org/wiki/X86_virtualization) whenever available (it is on most modern x86 CPU's). In principle IncludeOS should run on any x86 hardware platform, even on a physical x86 computer, given appropriate drivers. Officially, we develop for- and test on [Linux KVM](http://www.linux-kvm.org/page/Main_Page), which power the [OpenStack IaaS cloud](https://www.openstack.org/), and [VirtualBox](https://www.virtualbox.org), which means that you can run your IncludeOS service on both Linux, Microsoft Windows and Apple OS X. * **C++11/14 support** - * Full C++11/14 language support with [clang](http://clang.llvm.org) v3.6 and later. - * Standard C++ library** (STL) [libc++](http://libcxx.llvm.org) from [LLVM](http://llvm.org/) + * Full C++11/14 language support with [clang](http://clang.llvm.org) v3.8 and later. + * Standard C++ library (STL) [libc++](http://libcxx.llvm.org) from [LLVM](http://llvm.org/) * Exceptions and stack unwinding (currently using [libgcc](https://gcc.gnu.org/onlinedocs/gccint/Libgcc.html)) * *Note:* Certain language features, such as threads and filestreams are currently missing backend support. * **Standard C library** using [newlib](https://sourceware.org/newlib/) from [Red Hat](http://www.redhat.com/) * **Virtio Network driver** with DMA. [Virtio](https://www.oasis-open.org/committees/tc_home.php?wg_abbrev=virtio) provides a highly efficient and widely supported I/O virtualization. Like most implementations IncludeOS currently uses "legacy mode", but we're working towards the new [Virtio 1.0 OASIS standard](http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.html) * **A highly modular TCP/IP-stack** written from scratch, still under heavy development. - * TCP: Just enough to serve HTTP - * UDP: Enough to support a high performance DNS service - * DHCP: Basic support, tested on VirtualBox and KVM - * ICMP: Enough to answer ping, no control messages yet + * TCP: Not all the RFC's are impelemented yet, but it's stable and usable, including congestion control and common opitons. + * UDP: More or less complete, enough to support a high performance DNS service + * DHCP: Basic support, tested on VirtualBox, KVM and OpenStack + * ICMP: Enough to answer ping, no integration with the rest of the stack yet. * ARP * Ethernet - * IPv6 support under active development + * IPv6 support under development A longer list of features and limitations is on the [wiki feature list](https://github.com/hioa-cs/IncludeOS/wiki/Features) @@ -70,14 +70,13 @@ You can now log in to the vagrant build environment and build and run a test ser $ ./test.sh ``` - ## Prerequisites for building IncludeOS VM's - * **Ubuntu 14.04 LTS x86_64**, Vanilla, either on a physical or virtual machine (A virtualbox VM works fine) + * **Ubuntu 16.04 or 14.04 LTS, x86_64**, either on a physical or virtual machine (A virtualbox VM works fine) * For the full source build, you'll need at least 1024 MB memory - * In order to support VGA graphics inside a VM, we recommend a lightweight GUI, such as [lubuntu](http://lubuntu.net/blog/lubuntu-1404-trusty-tahr-released) which runs great inside a virtual machine. + * In order to support VGA graphics inside a VM, we recommend a lightweight GUI, such as [lubuntu](https://help.ubuntu.com/community/Lubuntu/GetLubuntu) which runs great inside a virtual machine. * *NOTE:* Graphics is by no means necessary, as all IncludeOS output by default will be routed to the serial port, and in Qemu, * The install scripts may very well work on other flavours on Linux, but we haven't tried. Please let us know if you do. - * **Building on a Mac:** we have done a successful build from bundle, directly on a Mac. It's a work in progress, but see [./etc/install_osx.sh](./etc/install_osx.sh) for details. + * **Building on a Mac:** you can build IncludeOS (from bundle only) directly on a Mac by running [./etc/install_osx.sh](./etc/install_osx.sh). * You'll need `git` to clone from github. Once you have a system with the prereqs (virtual or not), you can choose a full build from source, or a fast build from binaries: @@ -89,7 +88,7 @@ Once you have a system with the prereqs (virtual or not), you can choose a full $ ./etc/install_from_bundle.sh **The script will:** -* Install the required dependencies: `curl make clang-3.6 nasm bridge-utils qemu` +* Install the required dependencies: `curl make clang-3.8 nasm bridge-utils qemu` * Download the latest binary release bundle from github, using the github API. * Unzip the bundle to `$INCLUDEOS_INSTALL_LOC` - which you can set in advance, or which defaults to `$HOME` * Create a network bridge called `include0`, for tap-networking @@ -107,7 +106,7 @@ About a minute or two (On a 4-core virtualbox Ubuntu VM, runing on a 2015 MacBoo **The script will:** * Install all the tools required for building IncludeOS, and all libraries it depends on: - * `build-essential make nasm texinfo clang-3.6 cmake ninja-build subversion zlib1g-dev libtinfo-dev` + * `build-essential make nasm texinfo clang-3.8 cmake ninja-build subversion zlib1g-dev libtinfo-dev` * Build a GCC cross compiler along the lines of the [osdev howto](http://wiki.osdev.org/GCC_Cross-Compiler) which we really only need to build `libgcc` and `newlib`. * Build [Redhat's newlib](https://sourceware.org/newlib/) using the cross compiler, and install it according to `./etc/build_newlib.sh`. The script will also install it to the mentioned location. * Build a 32-bit version of [LLVM's libc++](http://libcxx.llvm.org/) tailored for IncludeOS. From 199be2992e8dc15b3d8243108a01d8a435a3ef6e Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sun, 22 May 2016 21:17:25 +0200 Subject: [PATCH 310/311] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eb902d694c..fe4f764c90 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ We're working towards automating everything with our Jenkins CI server. The test * **Standard C library** using [newlib](https://sourceware.org/newlib/) from [Red Hat](http://www.redhat.com/) * **Virtio Network driver** with DMA. [Virtio](https://www.oasis-open.org/committees/tc_home.php?wg_abbrev=virtio) provides a highly efficient and widely supported I/O virtualization. Like most implementations IncludeOS currently uses "legacy mode", but we're working towards the new [Virtio 1.0 OASIS standard](http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.html) * **A highly modular TCP/IP-stack** written from scratch, still under heavy development. - * TCP: Not all the RFC's are impelemented yet, but it's stable and usable, including congestion control and common opitons. + * TCP: Not all the RFC's are impelemented yet, but it's stable and usable, including congestion control and common options. * UDP: More or less complete, enough to support a high performance DNS service * DHCP: Basic support, tested on VirtualBox, KVM and OpenStack * ICMP: Enough to answer ping, no integration with the rest of the stack yet. From 11a3238d465720cda5ee831815085af462292329 Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Sun, 22 May 2016 22:16:47 +0200 Subject: [PATCH 311/311] Fetching tags instead of pulling them --- etc/install_from_bundle.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/install_from_bundle.sh b/etc/install_from_bundle.sh index d89ab849fc..1e9e618cfb 100755 --- a/etc/install_from_bundle.sh +++ b/etc/install_from_bundle.sh @@ -29,7 +29,7 @@ sudo apt-get install -y $DEPENDENCIES echo ">>> Updating git-tags " # Get the latest tag from IncludeOS repo pushd $INCLUDEOS_SRC -git pull --tags +git fetch --tags tag=`git describe --abbrev=0` popd