I use SLiRP over SSH as a poor man's VPN. It's ancient. The bulk of the code is a userspace TCP stack that performs NAT. I can use any SSH host as full VPN with only basic user privileges. I spent quite a bit of time poking around the code to try to improve performance. Increasing the receive window was sufficient to achieve >1Mb/s over a high latency link, but I can't go much higher without <100ms latency. It turns out that SLiRP never implemented window scaling, it was unnecessary for the links back then. The code has been reused for virtualization applications like VirtualBox, etc; but window scaling was never needed for that since client-host latency is basically zero there. Digging through old network code gives an appreciation for how far we've come.
sshuttle is great too! Great for road-warrior applications where a basic SOCKS proxy won't do, but last time I tried it I found it unstable under heavy load and the iptables routing to a user process can be somewhat restrictive, still super cool though. I don't know why but network tunneling is just fun.
Operating System Design: Internet Working With Xinu by Douglas Comer (1987) is a nice explanation with lots of C code of how to add a networking stack to an operating system, in this case his educational unix-inspired XINU.
I actually can't find the book you are referencing. I do see:
"Operating System Design: The Xinu Approach" and also the books "Internetworking with TCP /IPvolumes1-3." Might you have a link to the title you are referencing here? I have read the Internetworking series which is excellent.
It looks the the second volume that goes with "Operating System Design".
I can't be 100% certain, as I didn't find a table of content for either of the 1st edition books, but the 2nd edition of "Operating System Design" includes a section in implementing ethernet, so perhaps the two volumes got combined into one for the second edition.
You can choose not to use it and allocate statically etc, but that does not mean that use of a GC does not introduce jitter.
Also don't confuse high performance with latency-sensitive. Highly performance-optimised code will still have issues with GC jitter if you or someone else is causing it.
There is a reason why the GC-enabled OSs aren't used for anything in reality.
BTW: There should be no difference between for and for-range loops given an optimiser thats working.
Hard real-time garbage collectors (including real-time reference counting approaches) can be used in such a way as to eliminate memory-management jitter.
Region allocation - a form of GC - can be used in such a way as to avoid memory-management jitter.
> GC-enabled OSs aren't used for anything in reality.
You might have a narrow definition of what you consider to be an OS. I would argue that things like the JVM, the Erlang BEAM, and even the browser are OS-like enough to qualify.
And the default is 100, which means a double in newly allocated memory space. I have written several servers that after starting up (and running uselessly the GC once), never need to run it again.
What you mean is it's a set of C macros, except built-in to the compiler. Great if it's exactly what you need. And you're prepared for severe WTF moments (e.g. equality on map values is ... not the same as equality on variables of the same type containing the same thing). Also, expect the whole thing to be useless if you need slight complexity (e.g. you can use strings as keys, but not bytes (either Bytes, or []byte, but you can use [5]byte for example).
Oh ... you actually need it to be a red-black tree, or a custom hash function ? Tough.
Not in general, though of course lots of production language runtimes do involve a certain amount of GC-related jitter. But even where such jitter is introduced, it might not be a very big deal for something like TCP/IP.
Does anyone know why you would use an unsigned char array to store the MAC address instead of uint8_t? Char is one byte but a but a byte is not guaranteed to be 8 bits yet MAC is defined as 48 bits
Unless you are adding TCP to your CDC6600 or PDP-8, bytes are 8 bits. Any suggestion to the contrary in standards is fantasy.
That said, since the next field is a uint16_t, you may as well stay in Rome and call them uint8_t. short really is variable on some live architectures.
(Ok, or some DSPs only address words larger than 8 bits, but there's no reason for your compiler not to pick up the slack.)
Also, TIL that __attribute__((packed)) assumes the struct can be malevolently aligned and for some architectures generates very large and slow code to handle that. If you must pack, also add the ",aligned(2)" or whatever you can get away with to mitigate this.
I tend to use int for loops (where I know there will always be less than 2^16 iterations!), return codes etc. purely because it allows the compiler to pick a fast word size everywhere (e.g. if somebody compiles your code for AVR, and your loops are all int32_t, your API returns int32_t, they're gonna have a worse time). Otherwise, I fully agree.
Maybe you could use int_fast16_t? (That means, pick the fastest signed integer type which is at least 16 bits.)
Of course, "int" is less typing than "int_fast16_t". But, int_fast16_t possibly makes it more obvious why you've chosen the type you did (i.e. you only need 16-bits, but aren't relying on any overflow so a bigger type can freely be substituted if that gives better performance.)
That's certainly a valid approach, but I've never actually seen those used in practice. I guess, like me, people are lazy and prefer typing just int, which is guaranteed to be at least 16 bits, and is generally the fastest int type (well, excepting some 8-bit archs.. :P).
Since the fixed width integer types are optional, and if available must be 8, 16, 32 and 64 bits (and two's compl) I don't think CHAR_BITS > 8 is allowed if stdint.h types are supported since sizeof(uint8_t) must be 1.
Written three TCP/IP stacks and the first was pretty bad as wrote off of RFCs before the Comer books.
But then purchased the Comer books and made it so much easier. Highly recommend buying the Comer books if really interested in writing a TCP/IP stack.
Also if you really want to learning something you write an implementation. To this day makes it so much easier to deal with IP problems, configuration, buying products, etc.