 So welcome back today. We're gonna take on a relatively ambitious project. We're gonna implement TCP For those of you aren't aware TCP is basically one of the fundamental protocols of the internet. It's the way that Basically enables two different hosts on the internet to talk to one another in a reliable way so that you can send data In such a way that you're guaranteed to not lose anything that you send and that the receiver receives things in the same order You sent them the internet does not generally guarantee this and so TCP is a protocol that the basically Sequences data across the network and make sure to do things like retransmissions if if packets are lost There have been a couple of questions in chat just before we started About like how much of TCP are we trying to implement the goal is to implement basically something that can talk to a real server Now how we defined real server will we'll get to in a while But but the idea is that we want the ability to talk to a real host on the internet So talk to some TCP implementation that is not our own This means that we're not going to implement any of the sort of advanced extensions to TCP or any of the sort of Any of the Advanced congestion control algorithms for example, we're just going to implement sort of the basic probably new Reno And so what we're going to be working for is RFC 793 Remember correctly this one I guess actually I want this one So TCP so This one is the RFC for TCP the transmission control protocol as you saw from Twitter I think I posted out here There are a couple of other RFCs that are handy to follow In particular In particular, there's sort of this tutorial. I'm not going to read through it This is just good background for people who want to understand how TCP works I'll give a very brief overview sort of drawing some figures and such But I'm sort of assuming that you roughly know how what TCP is I don't expect you to know the protocol by heart or what all the headers are but you sort of know what it's doing So I will not go through this particular RFC This document we're probably gonna refer to a lot so RFC 7414 is basically a list of other RFCs you probably need to implement We're not going to implement anywhere near all of them in particular We're gonna focus on the things that are listed as core functionality Which is basically things that you must implement to be a TCP host on the on the internet And that is basically 793 which is the core TCP protocol 1 1 2 2 defines a Couple of other things like additional extensions you need to support and from memory some like initial values You need to set for different bits We're gonna ignore this because we're not going to support IPv6 This I think is basically possible to ignore and this one is basic congestion control so we need to set up like basically Reno which is Pretty much slow start would be my guess And there's like some stuff on retransmission timers and segment sizes So these things down here will be relatively short extensions to the core thing which we're gonna do in 793 so my guess is that for this particular stream our hope is to get somewhere decently far with 793 and Whether we actually get there or not we'll have to see But the hope is that we get 793 and then we can do all the Extensions may be in the next stream and then hopefully at that point we can talk to other hosts So hopefully that gives you some rough idea There's also 2398 so 2398 Gives a bunch of tools for testing TCP implementations My hope is that we'll get to try some of these after a while But that's sufficiently far down the line that I'm just gonna close it for now because it's not terribly important This RC 2525 is it's just a really handy way to debug TCP implementations because it gives a number of sort of known problems with past implementations and what what the problem probably is if If you experience one of these particular issues, so we might end up referring back to this So I'll keep it open although the core thing is going to be 793 Before we dive into that there are a couple of small things I want to talk about so first There's the live coding voting site. So this is how we ended up doing implement TCP this time There are a bunch of other proposals too for upcoming streams So here if you go to the site you just put in a unique username and then you just drag these Ideas according to which one you would rather like to see me do and it basically runs a It runs a now I can't even remember what it's called Ranked choice voting To determine which one is the next upcoming stream and then also to figure out things like runner-ups so that we can keep running Running basically elections even if people only vote once Okay, so that's the live coding stream Voting site the other thing I want to mention is the last sequence of streams We did was porting flame graph to rust And so we ended up with this tool called inferno and inferno has actually been doing really well there've been a bunch of people contributing we now have full color support and So if you look here, we already have nine different people contributing So we have Jason has been doing a lot of work for doing things like Supporting additional features like name attributes and stuff BC Myers has been doing some work on Adding sort of cleaning up the interfaces Some performance hacking Geordi has been doing a bunch of work in coloring And so this has just been a really cool project and there are still lots of open issues So if you want to try to contribute to something that is sort of simpler than what we're going to be working on today Then inferno is a really good place to start And all the past streams are of course up on YouTube as always All right, so let's get started with TCP In the tweets where I announced this I announced we were going to use this crate So peanut is basically a way to do low-level networking I so Normally, I don't do any research before I do my streams in this particular case I knew that there were some weird things we were gonna have to run to run into when we start dealing with low-level Networking in particular once you want to do things like implement TCP yourself you run into the issue of the kernel already implements TCP and You sort of need to steal packets from the kernel But the kernel needs to know which packets you're gonna steal from it So you end up in the sort of weird position where the packet sort of go to the kernel and to you And it's just a little bit of a pain and so we're actually not gonna use the peanut because it uses As far as I can tell it uses Raw sockets and raw sockets are nice if you're implementing your own protocols But not so great if you're implementing TCP because the kernel is still gonna send Basically the kernel is still gonna run its own TCP stack and that might interfere with the things that we're trying to do So instead we're gonna use this Linux feature. Actually, let's put this here. There's Linux feature called the tun tap so tun tap are basically User space so not in the kernel than the user space a way to write What essentially looks like a network to the kernel? And so what you're gonna do is you construct you tell the kernel to create a network interface for you Actually, let me draw this it's gonna be easier And If you have any questions at any point during this The getting sort of the basics of this is pretty important. So if you feel like there's something you're stuck on then like Just give me a shout Okay, so in normal applications what we usually do is we draw the kernel as a thing down here And then user space sort of on top of the kernel Wow, this one is not great for writing. Let's do pen And then you can imagine the like down here is the big scary internet And they're gonna be a bunch of packets and they sort of arrive up down here at its thing called the nick a network interface Probably the link to that kernel patch. It's sorry. It's not a kernel patch. Actually, it's a It's just a description of tongue tap So if you search for just tongue tap dot text, you should find it, but I can post it to chat as well, I guess It is My chat is on a different gene over there. So I can't put anything there that one So I don't know if you got that but Let's go back to this So there's sort of a network interface And that receives all the packets that come from the network and the kernel sort of internally has a bunch of data structures that it uses to run things like TCP and it's gonna send responses here if User space wants to talk over the network. They create a socket by calling into the kernel The kernel allocates some kernel memory for that socket that represents that TCP connection And then the the user space thing is really just a pointer to the thing in the kernel And so this is how normal networking works that if you want to say read or write from a network connection Then you just give this identifier that the kernel gave you that's normally just a number like a file descriptor And you say like write these bytes to that file descriptor that goes to the kernel The kernel then knows how to talk TCP and send stuff back on the on the interface card So what's gonna happen in our case? is that we still have this sort of user space and kernel divide Like so and what we're going to do is we're going to have the kernel Create what is basically a virtual interface for us. I'm gonna draw that here So this is a ton interface And it's gonna treat that as if it's its own network card So it's gonna treat anything that comes out of this as something that sort of came from the network, right? It's gonna treat this as a nick as a network interface However any it basically is gonna consider this sort of the wire of that network So any time it time it tries to send on this network interface That's really just gonna appear out of here into the user space program so the user has like a process running here and Basically any send the kernel does turns into a receive in the user space program and Similarly anytime the user space program writes something that's gonna sort of go through that and appear to the kernel as though That was a packet that came from the network. This basically lets us emulate a network inside of user space So that's what a ton device does and effectively what it gives you is So there's the command IP that lists all the interfaces on your machine IP if we create a ton interface is gonna show that there's an additional interface like ton zero that has like Some IP who knows what it's gonna be And like a bunch of other information and if we try to send something on this What's gonna happen is that the kernel is gonna look up which which process owns this tunnel Or this ton and then it's gonna take whatever the kernel wrote into this interface Whatever raw bits of a packet it wrote into here Those are gonna be redirected into user space and whatever user space writes back is gonna be treated as if it came back onto this network socket and This allows us to implement TCP pretty nicely right because we on here all we have to do is just like implement our TCP stack and if we receive a packet then What really happened was the kernel sent a packet to this address and we're just gonna interpret it as a TCP packet And we're gonna send responses back to the kernel and the kernel is gonna think it's talking to some host on the internet Okay, so does that roughly make sense we're gonna get into a lot more detail about how exactly we end up using ton But does that rough idea make sense that the ton that we create is basically a user space network Yeah, that the link posted by by Wilkins is basically the same document Okay And that means that instead of using the peanut package, we're actually gonna use this ton tap crate So luckily there's a rust crate for this Hello So luckily there's a crate for this and it's pretty straightforward, right? What you do is you have a ton tap interface Ignore tap for now and You can create a new one you can give it a name Or you give it a name it can be empty and then the kernel just generates one for you You can choose the mode for it and we're gonna ignore mode for now And that gives you an interface and once you have an interface You can call receive to receive a message and you can call send to send a message, right, which is sort of what you want Why is this not I have to scroll down anytime someone sends a message, which is not ideal Try that instead Yeah, so so all this gives us is a receive and a send and what these recieves and sends are are basically ip packets So anytime we receive anytime the kernel sends an ip packet to us So anytime the kernel bases that's network traffic our way The receive is going to give us back those the bytes contained in that packet And similarly we can send bytes out and the kernel is going to receive those as an ip packet What this means unfortunately is that we also need to implement the ip protocol because We need to be able to send packets to to the internet. Luckily the ip protocol is is um A little bit simpler It's basically just you name the remote machine Don't you risk freezing the entire system if you mess something up Ask him because I would like to follow along without my pc crashing every attempt at running the thing It's unlikely that the entire system is going to freeze like the kernel It is not like you're not going to crash the kernel for using a ton interface However, what you might do if you screw things up is the You might set up the routing tables on your host machine so that you can't talk to the internet anymore Usually all you have to do in that case is like reboot or restart your network interface I'm hoping that this will not happen to me because then the stream will be cut off um But in theory at least We should be fine But the the biggest concern is that your network traffic is it can no longer be routed like imagine that all of Basically, if your entire network connections started going over the ton interface Then nothing is going to go to the internet every one everything every packet you send is just going to go to the um It's just going to go directly to the process you're writing which doesn't know how to talk to the internet Um, it might be better to work in a vm Although again, I don't think you can really break anything this way Um, and I don't particularly want to work in a vm, but I agree you you totally could and it it might be better Um, I just don't want to Um, yeah, so this gives us basically the interface we need. There's one thing that's been missing and that is the rfc for the ip protocol which is 791 And uh, luckily the ip protocol is very very straightforward I don't need all the description Basically when you send an ip protocol message, it looks like this um So there's like a bunch of fields that we basically can ignore Um, well, we're gonna have to set them, but they're they mostly have constants And then there's a source address and a destination address the source address is going to be the um ip address of sort of us as in who we're pretending to be on the Uh on the user network that we're creating and the destination address is going to be the the remote host that we're talking to Uh, I don't think we're going to need any options and then following this header is just going to be the contents of the packet um, do you need to be root so Generally, you need to be root to create these things But there is a capability specifically cap net admin that you can see this is a Basically is that thing you can tell the kernel to give a particular process or binary You can say that when this program runs, it's going to have this capability, which means it's going to be able to do these things Um without having to be root Uh, so we should not need to be root for this you do have to be root to grant this capability um Okay, so let's get started. I think the way to go I think Step one of this is going to be just being able making sure that we're able to send and receive packets at all um, and so as before We're going to go into streams We're going to cargo new lib Actually, is it going to be a lib or a bin? Let's make it a bin for now Start simple Um, we're going to call it. Where are we going to call it? Thanks, um, what are we going to call this user space tcp thing? It's going to be It's going to be trust tcp rust All right, and we're of course going to depend on the ton top crate zero one two And source main is going to do an extern crate ton tap and then I guess what we're going to do here is something like um Ton tap This is just to to see that we can get anything working um Mode what's the we specifically want ton mode I don't worry too much about the difference between ton and tap I mean, I can explain it if you want to but I don't think it's relevant Uh fail to actually now main is allowed to return a result, right? I think that's true Thunder is pretty funny actually although Oh, you're sorry. You're right. I don't need extern crate. Thanks um Fun, I like thunder Wait, that's a great. Actually I I agree. Let's switch it to thunder Well So the reason trust is nice is because tcp basic it doesn't actually establish trust But it does mean that you can trust that what you send is what the other person receives um Actually, let's keep it thrust for now and then we can we can figure that out later um I was planning on using stable although who knows I don't remember what my default is my my default is beta. So we're on beta Okay, so we're gonna do Oh We're gonna create a new interface and then we are going to do Um Buff is going to be a 1500 and I'll explain why soon I think we need packet info Yeah, let's do with that packet info Now this is a new find for for now um Zero u8 Oh, it's the other way around right u8 this um And then we're going to do nick dot receive Into buff And we're going to do Read this many actually Yeah And then I guess we're gonna x this Uh How many bytes we read I guess is n bytes And this is going to be buff n bytes Let's just like see whether that works at all Just so we have a place to start It in fact, uh, it almost guaranteed will not. Ooh Ton tap not found Oh, it's Oh, they've done it properly nice Oh, yeah, tsunami was great. Um, it was a good good crate name too. Oh, I face And what else we missing What's I guess like this Don't need both Um, and then because we're going to be able we're going to be doing like uh networking things We're also going to do sudo set cap What was it capability called cap net admin on Target dare release trust Uh, you don't need a use statement because all the with uniform paths. Um any Uh any identifiers any Identified to the left of all the colons is considered. Uh considers anything that is in scope and all external crates um So why can't I do this a set cap Dash h dash r dash what help man set cap Um, oh, is it like Has to be lowercase or something cap net admin Apparently not equals eip What is the equals for? Man cap from text Each clause consists of a list of a common separate capability names and actually this consists of secrets Okay, what do the flags mean? Secret flags indicate the list of capabilities of recordings must have to be raised for example Except p means lower every capability effective and inheritable. Oh, we just want to set them for all of them sure Equals eip great And now I think in theory we should be able to run this thing Okay, it did an error So let's look at what ip addresses we have. Okay, so we now have a ton zero interface Um It doesn't have an address or anything so we can't we don't actually know how to send anything to it yet um So let's do ip adder set um 6801 Slash 24 Dev 10 zero All right, so This still hasn't received anything at least as far as we can tell but now And then also set Link Set up dev ton zero Great, so here it got a packet. I have no idea what packet this is but this is indeed a packet that it got Um One thing we're gonna so as you notice this just got a bunch of bits now, right? So clearly it is receiving some stuff like when we brought this link up it received an ip packet of some kind I don't know what kind of ip packet. Maybe a ping packet or something But it did receive an ip packet And so it suggests that our sort of our basic setup is working And now you see ton zero is gone, right? Um, what we're probably going to want because building running this thing is a little annoying is we're going to Want to do something like have this in a script Um And that's going to do cargo be release It's going to do that Then it's going to do what we did over here Uh, and also what we did up here to set the address This is basically so that we don't have to run this every time This is just waitpid. I think it's waitpid Oh, maybe it's just wait Yeah, it's just wait So what the script is doing is it's building setting the capability running the binary in the background keeping the process ID of that around setting up the network and then Waiting on that process to finish Which in this case is going to read the 52 bytes As you've observed though, like this is a little weird In the sense that we don't know what these bits are So we're going to want some kind of tool that can help us interpret what these are And we will probably want our program to not just exit to right something like Loop So now if we do runsh Then now it's going to continue. So now the ip this is still up and now let's try to do something like ping On interface ton zero, we're going to ping Some address on that subnet So this now received a bunch of more bytes Right, if we you'll notice that it keeps receiving bytes and these are in this case ping packets, right? and so now We're going to have to interpret these in our program so that we can like parse them as tcp packets, for example And so what we're going to do is use there are a bunch of tools You can use here. I'm going to use one called tshark. So this is a terminal version of of wire shark And notice that it gets to sort of watch this interface and see what's going on and specifically see this 20 the 52 bytes thing was a ipv6 router solicitation that sounds like something we should ignore And then All of the other ones are requests and of course there are no responses because our program doesn't do anything It's not responding to anything Okay, so what we're going to want is basically our program needs to sort of parse out the packets and know what to look for So we're going to kill that program for a second. And so this means we're going to have to figure out how to parse these bits If we go back to This you'll notice that what receive says Is you get the mtu which is basically just the packet size in your network We're going to assume it's 1500 and you get plus four for a header that packet info is propended So this is what the difference between new and without packet info is um specifically in this case Um, there's a description somewhere here The frame format that you get is you get two bytes of flags two bytes of protocol and then you get the raw frame So if we look at the bytes that we received this is going to be um like flags this See we can probably do flags is um Probably won't bite already here, but um, isn't there a Didn't we recently get like read big endian or something in rust Might not have landed it might not only be nightly um This is going to be very handy regardless uh be Yeah From b so we're going to have a u16 from ne u16 from any bytes um Yeah, so this lets us basically parse out um a u16 from bytes in Oh native end in this That's not what I want. I want le Because network what is network? I can never remember Uh Big endian is network. Okay, great. So what we want is from be bites Um, so flags is going to be a is going to be u16 from be bytes This is on beta Probably isn't is it? Oh, yes from be bites And this is going to be above zero one Uh, and then what was the next thing? um here proto This is going to be two and three and this is going to be foreign onwards Oh All right, we need to do some cleanup here What's the bash term? Uh, the inline warnings is something that recently landed in uh rust uh in the uh Neo vim language client. It's actually a little bit annoying because the default styling is pretty terrible um capture term capture kill trap that's what I want Specifically I want trap term I basically want the I wanted to terminate the program normally when you do a control c Um I can never remember what the syntax is for this We're going to kill this so it tears down this and then we're going to run it again. Ooh In valid signal specification That's interesting And didn't tear it down Hmm Well, that's obviously not working Isn't there a way to like do nicer traps? I can never remember how this actually works This is a sig term What it was just killpid. I thought that was all you needed Oh, maybe I need this needs to be bashed, doesn't it? Yeah, okay great um Okay, so now Run as H is gonna when we kill it is also gonna kill the underlying program And crucially in theory now we're gonna get we're gonna parse out flags and proto And we're gonna print them here flags Okay, so proto 8 6 dd um So I guess we're gonna have to figure out what these different protocols are Where is the That's unhelpful I think it's from the ip frame ip protocol Numbers What did we get? proto's 8 6 dd So 8 6 dd is an ipv6 packet, right? And my guess is if we start doing pings um Then now we're getting things that have protocol zero. This is 0 8 0 0 and 0 8 0 0 is ipv4 And so the first thing we're gonna do is ignore any packet that is not an ipv before packet Right, so that's gonna just tidy up our stream a little so um if proto not equal to This Continue So at this point now notice there's nothing printed when we first started because the those packets went away um And indeed if we now start pinging those packets do in fact show up Okay, so now we've parsed out the the beginnings and what now follows is an ipv4 header um And so what we're gonna do is we basically have to encode this structure the ipv4 header in our rust code somehow um, I wonder if someone has already done this just to save us the work ipv4 network structs Seems great ipv4 header great That seems fine. Let's use that The reason the reason i'm using a package for parsing ip is because it's not really what we're focusing on So there's no reason for us to really redo that work uh ether parse is 0 8 And in main um here we're gonna do This is gonna be ether parse ipv4 header slice from slice um buff 4 to n bytes And if this error is in some way, then we don't really care right that just means we're gonna skip the packet Um, and so we're gonna do a match on this Um, and if it's a packet then we do whatever we want with the packet and if it's an error Then we're just gonna ignore that packet Ignoring packet Weird packet And then here what we're gonna do is print out the packet instead of the buffer And now let's see what that gives us All right, let's see what now happens if we do some pinging Okay, so now we're getting oh, I guess the slice isn't really helpful, but at least it parsed it correctly Right, so that's pretty promising. Um, so let's now have it Instead of just do that. Let's try to actually print out some stuff particular What we probably care about from the ip packet are things like the total length of the payload So instead of all of the stuff we've done so far, we're gonna do Got ipv4 packet Bites of ipv4 packet payload And that's going to be what p dot payload len Um What else do we want? I think we're probably going to ignore all these other fields Um But protocol we're going to care about we're probably also going to care about Source and destination So we're going to do source is going to be p dot source adder Um And destination is going to p Destination adder and what else do we have? Protocol And notice that this this protocol is different from the other protocol So the protocol we get up here these are for the ethernet frame that we got Um, and so this is sort of set by the the link level protocol Um, and that we're not really going to care about down here Oops, what do you do? Uh, this on the other end is the ip level protocol which should be set to tcp Um, so let in fact, let's print this out in a similar format to this, right? Just so we So this is going to be the source The destination, uh the Uh protocol So I guess this is going to be bytes of Protocol this This is going to be source destination Proto and that So let's see what this gives us Uh, is there a way to debounce that nevim plugin so it isn't checking out for every new character? I don't know. I really want that and I I haven't looked into it enough. It's a fairly new feature Uh, but it it's really annoying Um, you probably need time to live Yeah, I'm just going to assume that it's fine like There are things that we should do that we're not going to do um Yeah, you it's really really distracting while typing Um The macros we don't actually need because we're at the the data link layer sort of the ip layer So we don't need anything like ethernet frames. All we need to know is where to like respond to the packets This is failing for some reason though Why is it failing? Don't think it should be failing Great. So now if we ping what's it going to do? Great. So we got one byte of protocol 64 Okay, so time to look up the protocol. So 64 Oh, that doesn't look right protocol. Oh, are we printing this in hex? We're not printing this in hex But how about we print it in hex instead? Also, let's get rid of these warnings Don't need this And don't need this protocol 0x40 So ip protocols Oh, am I printing these in reverse order? Oh, you're right. Wow Yes That is the payload length. This is the protocol. Okay better So now if you ping uh Protocol one and protocol one is indeed the ping protocol. Okay, great. Thanks for catching that Um Yeah, so now at least we know that we're getting our ip packets and we know that whatever is left the sort of tcp So the question now is what happens if I try to connect Using a tcp client to whatever port it's not important So i'm gonna try to do that. Okay, so it got 40 bytes of protocol six Protocol six is tcp. Okay, so we got a tcp packet of some kind and we got 40 bytes of it So this is where we really need to start getting into what are we going to do at this level? One thing we also have to decide is whether we are going to implement the the packet parsing ourselves or whether we're not So this is actually sort of up to you There's a lot of stuff in tcp and most of it is not about parsing right like parsing the tcp header is not particularly Um Is not the core part of the tcp protocol, but it is a bunch of like bit fiddling ether I think the ether parse Thing also supports tcp headers Um, so we can use this to do the parsing for us that way We don't have to spend a bunch of time doing the bit fiddling, but i'm also happy to do that Um, so would you prefer to see me start working on like the tcp protocol side? Or do you want to also do the tcp header parsing? What would you prefer to see to give an idea? If I stop this for a second Uh, if proto not equal to zero x zero six Uh Just while you're thinking I'll write up the the one that uses ether parts So this parsing is just the same as the ip parsing I did above tcp to port this And I guess that's going to be wait for me to get the length from this I wonder I guess that's um It's going to be p Slice dot len and p dot uh destination Destination port Let's see Protocol I think I'd prefer to not see parsing just a protocol parse protocol protocol Skip parsing parsing might be interesting protocol Skip parsing. Okay, so it sounds like protocol then great. So we'll just do the protocol So I've now done the parsing. This is why the parsing is nice to skip Basically because ether parses the parsing for you Um, if you're curious about like low level parsing, um, I would look at the source of ether parse It's mostly just like reading out. So you have a you have a byte string, right? And then you do things like this sort of u 16 from b bytes You ate from b bytes You just like read out the different fields according to what the specification says that the header formatting is Um, you get out the fields and then you sort of parse them in the appropriate way um And my guess is if you read the ether parse source code that is all it does when you use this from slice business Um, why is this stopped? Um, all right So if I now run this what happens Oh, I need to type my password apparently It's fine All right, so now this is running Um, oh, eventually we're going to need all the fields of the tcp header. I just didn't particularly care about Um, printing it right now. Um, so let's now try to First let's try to ping you'll notice that nothing gets printed because we notice that it's not a tcp packet And then if we try to send a tcp connection, you'll say we get 40 bytes of tcp to port 80, right? If I stop this and say 443 instead, it's going to say 40 bytes of tcp to port 443 Okay, so at this point we are receiving tcp packets Um And so now the question is what do we do with them, right? So at this point now we sort of know that there's some there's something going on here Um, and so now we need to figure out what we're going to do sort of in order to implement the protocol um The thing to keep in mind is that in tcp um, a connection is or in in Well everywhere a connection is basically a a quad of source ip Source port destination ip and destination port Man these warnings are so annoying. What's the thing for turning them on again? Sorry, I just need to uh Didn't I fix this at some point? Thought I did Apparently not All right, well Uh, any of him language client I could write it as comments. I just don't want this feature to be on like ever Um, it's far too annoying the way it currently is virtual text This how do I turn this off this Excellent, it's gone beautiful, um I can still put in a comment though So we basically want this quad like this this identifies a single connection And anytime you run sort of the tcp protocol you basically want to run it on this quad like all the state is associated with that quad um And so what we're what we sort of need is is almost like a map from this quad to the state for that connection All right, so we're going to end up constructing something like tcp state Uh, and that's going to contain a bunch of fields and then we're going to have something like connections, which is going to be a hash map Um, well actually let's make it This is going to be a hash map from a quad to a tcp state And a quad is going to be um A source ip I guess actually we could Uh, oh, I will I'm not gonna I don't think you should generally use this for anything No, this is building more because it's interesting not because we're going to use it for anything um, so the source is going to be a Uh, I guess this at this point We need to figure out what this return type is for the It's a tcp. Uh, it's a what? Oh, where's the source center ipv4 adder which comes from standard net So we're gonna use standard net ipv4 adder ipv4 adder and a u16 right so this is uh source ip and and uh port and destination ip and port This of course we're going to derive like all the things for so the hash eke impartial eke And probably also debug and probably also clone and copy um Right so we're going to keep this sort of connection state and that's going to be from one of these To whatever we end up putting in the in the tcp state And just to make our lives easier. We're probably going to do a mod tcp um tcp.rs and that's going to have this So this is going to be a tcp state And so the question is what do we do when we get a tcp packet? Well In all likelihood what we're going to do is We're going to do connections dot entry Quad Right, which is going to be the source is going to be the source address and the p source port And the destination is going to be the destination address and the destination port um And the question is what do we do if there is no connection? Well We probably want or default like there's going to be some it's going to be some uh Default state that every connection starts up in um and then What this so the dot entry API is really nice because what it will do is basically If there's already something with that quad it's going to give us a reference to that thing To the the corresponding state and if not it's going to create one for us and then give us a reference to that So what we end up with after this or default is basically uh Is basically a Um Always what we end up with is a mutable reference to a state and so at this point we're going to say something like On packet and we're going to give it uh the p And we're going to give it Actually, that's a good question Why is there no way for me on this? to Get out Right data offset is the one Uh, so p is the header and then in addition We want where does the data start? Well the data starts at four plus How far the number of 32 bit words in the tcp header, right? Um, so actually that's not even true um So the ip header size Is p dot slice dot len Oh, actually this slice That's even better So the data starts at the ip header size Plus the tcp header size Right tcp header sizes is that last value Actually, how about we don't overwrite these and say this is ip Uh This is the ip header And this we can just inline just to make the code easier to read That way here we can use iph dot slice dot len iph dot slice dot len this is give us going to give us a tcp header Instead of just p tcp header tcp header I should just say port All right, so on packet we're going to give it the ip header the tcp header and also the The slice of the payload which in our case is then Buff from Let's give this a helpful name data i From data i to the rest of buff, right? So from the point where the headers stop and the rest of the buffer is the contents of the packet And that's sort of the end of what main has to do right There's going to be there's going to have to be some way to like send responses And who knows how that's going to work There's going to be timers and stuff involved, but at sort of the heart of it This is the way packets get into the tcp state Okay, so now we need to actually implement that right so we're going to have to implement default for state And we don't quite know what that looks like yet We're also going to have to impulse state and have something like a On packet that takes a An ip header, which is going to be a what was it ether parse ipv4 header A tcp header, which is going to be an ether parse tcp Now these are actually this is ipv4 header slice. This is tcp header slice and data Which is going to be just a bunch of bytes And we don't really know what we're going to do in there, but for the time being We're sort of just going to Print this out iph dot source adder iph destination adder Now we're going to I guess just show the port's numbers directly in here And so it's going to be source adder then tcp header source port And then the same but destination And then finally we're going to give data dot lend This is mostly just a tidy up our interface, right? Oh, I probably did something stupid, didn't I? Um an inner attribute. Oh, I have messed up. Don't I this should not be that And this should be pub Well crate, but whatever they're the same Actually, I also want my run script to If compilation fails, I don't want it to run anything Why does compiling This makes no sense. Oh, that's not what I wanted This is what I wanted great Um, all right, let's see. What else no method on packet That's because this has to take mute self Right and the the lifetime ticket here is the lifetime of the basically of the packet itself Which is basically a the lifetime of this buffer, right? All right, so now this runs Uh, and again if we ping nothing shows up because we're filtering those if we try to connect to a given port It's going to say oh, we got a bunch. Oh, that looks wrong No, actually that might be right Um, so this is saying that the body of that request is 1440 bytes that doesn't seem right. Oh the data is until n bytes, of course This also is n bytes Because remember, um, when we fill up buff We only actually like buff is this long, but we only read this many bytes So we should only be looking at that many bytes Um, so let's try that again. Now if we do this Zero bytes, right? So the first packet we get is basically a header only packet. It contains no payload Great, but this at least means that the math sort of worked out Um, so what this first packet is in fact if we Start this again if we start our our t-shark Um, and then do this you'll notice that that message Um, if I can kill them again Is and let's also kill this and also kill this This packet that got sent is a syn packet and it has a bunch of like header fields And so the question is what do we do in response to that? Well, This is basically the first part of the tcp handshake. Um, and there's a pretty decent Description of that in I don't want this don't want this These go away This goes away So this is when it starts to be time for the rfc Um, there's a Operation is that what they do it? It's a diagram somewhere in this document, but I can never remember where it is Uh arguably I could just scroll through Yeah, so this is the stuff that we no longer have to parse because ether parsed does it for you Um, but where's the thing that shows the state? Oh, yeah, there's a there's a lot of stuff we're gonna have to get to here Okay, so this is the diagram I'm thinking about So this is the tcp connection state diagram and so we're basically gonna have to implement all of these states Um, initially when you start out a new um Well, so there are two states a socket can sort of or a tcp connection can start out it It can even start in the here. I think they specify it further up too um Yeah, so there are a bunch of different states that a connection can be in. There are these states, um And tcp here is sort of the tcp state And so that is there is no connection currently Um, so that's what this closed here is um And so the idea here is that if you're closed So if you're not expecting to get any connections like there's no state for a given connection then like Even if someone tries to connect to you, you're not going to reply, right? If you're not listening on a given port, you're not going to reply Whereas if you're in a listen state and someone tries to connect you then you are going to reply So what we're doing here actually if you look at the The code up here this sort of on packet here We're saying that if someone senses a packet if we haven't talked to them before we're just always going to answer them Right, or we're always going to deal with that packet Now that might not be the thing that we want to do In particular, uh, this means that basically every port is listening And this might not be reasonable going down the line, but for now, let's just like stick with this Like if someone tries to connect to us, we're just going to respond. Yep, we're here And so we're going to ignore this closed state and basically Assume that every every port is going to be listening Um, so if you notice that listen, there are a couple of different things we can do We can either receive a sin If we so this is you should read this as if this happens, then we do this So if we receive a sin so as soon as this is the first part of the handshake Then what we send is an act which is an acknowledgement of the sin And a sin because we want to establish a connection the other way So the handshake establishes a two-way connection in tcp So this is the other person reaching out saying, hey, I want to talk to you. Do you want to talk to me? And this is saying yes, I want to talk to you. Do you want to talk to me? At this point, we sort of note that we're in the state of we have received the sin from the other side Uh, and at this point one of two things can happen either the connection can be closed In which case we just like terminate the connection or we receive a Um No here Or we receive an act of the sin that we sent in which case we don't send anything But now the connection has been established. So this is sort of the initial tcp handshake And so getting through the flow from here to here to here is basically how you do a server Right. So this is how you receive connections on the other hand If we wanted our library to establish a connection it would start out enclosed and then it would do an open Which creates the state for the connection and then it sends the sin Right. So this is sort of the the opposite end of this receiving a sin Confession is fun Yeah, so so if you're a client you're going to go through this path of sending a sin to the server And then being in the state sin sent at that point. Hopefully You're going to so if you receive a sin from the server It means the server was trying to connect to you at the same time In which case you can just act and then everything proceeds as normal But in the common case you send a sin and you receive a sin act This is the sin act that the server sent here at that point You're going to send an act to the server saying is I do indeed want to talk to you at which point the connection is established You might wonder why you need this like two-way acknowledgement And there are many reasons for that the primary one is to make sure that the hosts are actually talking to one another that does not Sort of some other host in between that's trying to do weird things We're not going to get too much into the weeds of exactly why the protocol works the way we are We're sort of going to naively implement this as if it were the what? 1981 Sound good We're going to assume that the internet is a safe place Um, and so as you can see there are sort of two different paths here for whether you're a server or a client But as far as tcp is concerned, it doesn't really matter All that matters is how you end up using that state So I think what we're going to do is we're going to do the sort of tcp server part first And then we can implement the client part later the client part is what we're going to end up using for talking to other servers online Uh, what happens if the final act from the client is dropped somewhere? Ah, so there are all sorts of ways for this protocol to be weird Um, basically there are there are a lot of timeouts in this protocol of things like, um You try to resend if you don't hear back We'll get into all of that sort of leading dealing with retransmissions as we get later um But in general tcp assumes that either you will receive an act eventually Um, or the connection is eventually going to time out and close Or it just stays open forever Um, okay So in this case all we're doing is receiving a packet and this this this diagram gives us a pretty good idea of What we probably want to do specifically what we probably want to do is have this be an enum Right, we sort of want to encode the state diagram and the default state is going to be closed Now this does mean that we're still going to sort of create an entry here For things that are closed and we might want to sort of prune those like there's no reason to keep this around if it's closed But it's it's a good way to start to approximate the diagram Um, when we're closed, we're also going to be able to go into listen mode Um, and in fact what we're going to do for the time being so this is going to be state closed But starting out we're going to say that we're always going to listen on all ports um The other things we're going to need are um Sin received I guess named these the same as in there um And we're also going to need established And let's just like stick with those for now. There's a bunch of state We're going to have to keep for these two but let's sort of start out in the very simple case of if we receive a packet um if It sort of depends what state we're in um So if we are in state closed Uh, then all we're going to do is return There's nothing more for us to do If we're in state listen Then the only packets we expect to get in state listen is a packet that has a sin set Right? That is the only thing we're expecting to get um And so If tcph dot sin So if the sin bit is set Sorry, or the other way around if sin is not set then I guess here we could do some logging and stuff, but here um Got unexpected sin uh Only expected sin packet So in this case two we just return Right um Otherwise though if you go down here, we got a sin and now We need to start establishing a connection And so what that means is we're going to have to parse out the stuff from that sin packet And then we're going to have to send this sin act Okay, so we need to cook up a message that's going to be the response we send And here too like we're basically cooking up a tcp header Um, and so for that we can we might as well just sort of reuse this uh the ether parse because they also have Sort of the opposite of a tcp header now here It's a little awkward This is going to need some way to send a message. So I think on packet It's going to be have to be some way for it to know how to send packets again But let's just construct the packet in the first place. Okay, so we're going to have to create one of these Uh, so we're going to send a sin act Uh, and in order to do that we're going to have to set all of these question is how can we create one? New great So we're going to do new Uh, and it's going to go In the opposite direction, right? So we received a sin act from someone else and now we need to respond to them So when it says source port that's going to be the destination port of the packet we received Right, that's where we're sending from the destination port is going to be Uh, the source port of the packet we received Uh, the sequence number We don't know yet and the window size. We don't know yet. We'll have to figure out what those are Um, then we're going to have to Specifically again, we're going to read the the rfc more closely But specifically when I have to set sin and set act right because we're Sin is going to be true And act is going to be true Right, so we're acting their sin and we're also sending our own sin Uh, and then we're going to have to wrap that in ip packet because we're sending it back to them, right? Uh, and so in order to do that We're going to end up creating an ipv4 header So It's going to be ether pars ipv4 header new Uh payload len is going to be Uh sin act dot slice dot len Um time to live 64 protocol It's going to be tcp What else do we need? Source and destination Okay, so the source is going to be the iph dot Destination right so we're responding so we have to invert them So if we're giving source then that has to be destination address um and similarly the Destination is going to be the source address source adder And then ultimately we're going to have to send these packets out. That's a lot of things um Shouldn't be one for sin act Yeah, so okay, so there are a couple of questions in chat. The first one is Shouldn't it be one? Oh, yeah, these parameters. We are going to be set to something. They're not just going to be zero Um, I just haven't done it yet And it is totally true that as as you've already observed right We're keeping state for every connection And so in theory you can make the server do a lot of work with doing very little work yourself And this is often known as a sin flood attack and it's something that's modern kernels are actually pretty Defended against because what they'll do is they won't actually Set up any state locally. They won't allocate any state locally until the connection is actually established And so there are defenses against this. We're just not going to care about them right now because they they complicate the implementation So you're you're totally right that this is this is a problem in sort of real implementations Um, okay, so we've we've constructed this packet. Um, there are still some things we don't know like What is this going to be? Uh, what is this going to be? And also how are you going to write out this? packet right like there has to be some way for For us to sort of send a reply here Where this is going to get particularly tricky as was is when it comes to, um Being able to send Uh Being able to send Packets like if there's a timeout for example that we're waiting for Uh, and I don't have a good idea for how to do that. I think what we're going to do for the time being Is just uh to give this guy a writer Um, specifically it's going to end up with Something like an eye face Now, of course, this is its own kind of stupid. Um Because ultimately we're going to want to for example have uh, we're going to want to be able to send packets Uh, even if this is not active, but let's just for now We're just going to give it a mutable reference to the eye phase Which we're going to call nick And what this means that is that we can send packets ourselves right just by writing out this nick Uh Okay buff Now this is also not as not what is referred to as zero copy often You want the kernel to not you don't want to not have to write things into memory more than once We're going to ignore that as a concern. So this will not be highly performant. Um, But it should be fine. Um, so at this point What we want to do is sort of write in The ip header then the tcp header and then any payload that we have Um, I guess here we're going to do something like let me Written is zero So we're going to do, uh ip dot write Oh, what's the difference between right and right raw? I wonder I think right is what we want What is it that implements right again for like things that are slices? For mutable references to u8 the writing updates is nice to put to the yet unwritten part Yeah, so Here we're going to have Hmm unwritten Is going to be a mute to buff to the entire buff And then we're going to write into unwritten And then uh, yeah, and then we're also the syn act is going to be right written to unwritten And the payload is going to be empty And then at this point we're going to write out the actual packet using send Right, so we're going to do Nick dot send and that takes basically a buffer and that buffer is going to be buff Oh, I don't know how that's going to work It's going to have to be this I think Written is going to be Let's see how much have we rewritten we're written Uh Unwritten is going to be this And so we're going to write up until unwritten Right, so this might seem a little weird, but um Out the headers We construct the headers then we write those headers into buff And what this trick is going to do is basically we create a slice the point to the entire buffer And every time the a header gets written the start of that buffer gets moved And so this line down here is how much is remaining in that buffer how much space is remaining And however much space is remaining is how much we haven't written Right, which means that the stuff we have written is everything up to that point, which is what this is doing And I guess this means that on packet is going to have to return an IO results I guess maybe use size I'm clear that it matters and I guess we're going to have to use standard IO Let's see whether this makes any sense We're going to need prelude probably higher right is not Implemented for u8 Where is it saying that? Okay, there are a couple of issues first this expects a u8 of size 4 Which is not where we're giving it I guess this is going to have to be destination and this is going to have to be source It's probably still going to complain about that Um specifically I wonder whether we're going to have to do like This which is a little awkward, but maybe And this is going to be Source source Nothing found for ipv4 header This we're going to have to use uh total Len All right, what else is it complaining about this and also this Now what is it complaining about It's complaining in main about this that's fine So now a question mark It takes four parameters, but three were supplied. That's because we also need to give it now the The network interface so that it can send additional things Okay, what else do we have? uh expected mutable reference Oh, this should come first You could use iter chunks to get that slice from destination source Is that oh because there's like a fixed size chunks thing now, huh chunks Chunks exact I think is the one but I don't know if it gives you that I think it just gives you an iterator um Where's the implementation of Implementation of iter yeah, it still gives you a slice So it doesn't give you a u4 Which is what we need Uh tcp line 29 Oh, this is okay zero This is okay zero Oh total len found for tcp header It's because it's just header len is what we want Because there's no payload Uh, what else is it complaining about? The size for values of type u8 cannot be bound. Maybe it's this We don't need These we haven't done anything with yet. So they're unused All right. So now we have something that's sort of running Uh and in theory, it's gonna write back the appropriate act. So let's um Start up our t-shark And then let's try to connect on a port and see what happens Well, something crashed Not yet. Oh, it's because It's not terribly surprising. Okay. So we haven't actually figured out what we want to set these for this is why un-implemented is nice Um, so when we try to create this we need to set a sequence number We need to set a window size and in order to understand what these are we need to actually read the rfc um So the place to start for this Is We want to start for this Um, no, no No Here, okay, so header format. That's fine Here is where we're gonna need to actually start reading and talk about what some of these fields mean Uh, just give me a second. I need to get some water. Okay, so Let's look at what actually is in a tcp header There's a source and destination port we've already talked about and there's a sequence number and an acknowledgement number And there's a bunch of stuff down here. Let's talk about these two because they're relatively important for how the protocol works Um, and the protocol is pretty good at describing how they work So the sequence number is the first data octet in this segment Um, so specifically it is sort of the index in the data stream um of the first data part of that segment and you can sort of think of A sin as a byte of its own Right, so if sin is present the sequence number is the initial sequence number which we're going to get back to Uh, and the first data octet is one beyond that. So the sin sort of counts as the first byte Uh, and the ac the acknowledgement number Is the value of the next sequence number that the sender is expecting to receive Right, so, um, there's a diagram further down that makes this a little bit easier to follow Where is it here? Yes, so this the this statement is basically entirely correct in order to understand tcp Like you just need to understand sequence numbers acknowledgement um, there are there are a bunch of variables that need to be stored and they're sort of stored Almost no matter what state you're in And so what we're going to probably have to do Is basically have a a struct tcb. So this is what they call the transmission control block This is sort of the state that has to be kept for every connection And a tcb is going to contain the fields that we give down here and my guess is that we actually want Here's probably what we want state Um, that's going to have to contain these fields Uh, and in addition it's going to contain something like Well, I sort of want to call it state, but Let's make this connection So instead of calling me the state it's going to be connection Uh And this is going to hold the state So this is the state that that connection is in So this is going to be For now, we're just keeping that But let's look at what is in the tcb Um, among them are things like socket numbers. We can ignore that Presidents of security we can ignore for now and then pointers to receive buffers. We don't particularly care about yet Retransmit queues in the current segment. This basically has to do with TCP is intended to provide Reliable transports a reliable sends and receives across an unreliable connection So the internet is prone to just like randomly dropping your packets or rearranging them Which means that sometimes TCP is told to like hey, I never received that packet and it needs to send them again Which means that tcp actually needs to keep a queue of things that it has tried to send in the past So that it can remember to send them again um And this is what's known as the tcp. Oh This is what's known as the tcp retransmit queue um And so the the way to sort of think about this is we're going to keep all the bytes that the user wants us to write And then we're sort of going to remove them as needed So we're sort of going to keep a buffer of everything we've tried to write um In addition, there are a bunch of variables that are related to the send and receive sequence numbers that are stored in the tcp um, so There's a diagram down here that we're probably going to spend a bunch of time looking at so it's useful to spend some time um The send sequence space is basically The bytes of data that we have sent um And there are a couple of points in that data stream. So send.una is What we have sent but that has not been acknowledged Send next is what we're where we're going to send from the next time we send Uh send.window is how much we're allowed to send so tcp has this notion of As a receiver you can sort of limit how much your sender is allowed to send So that they don't overwhelm you with traffic And so the how much we're allowed to send is the last point that was Acknowledged plus the size of that window. So send up next can never go beyond Sorry, um, we can never send bytes beyond this boundary even though we might have them locally. We're not allowed to send them yet Uh And these are used for updating windows which are going to change in all sorts of ways There's also a notion of an initial sequence number. Uh, the initial sequence number is What we choose when we started the connection That doesn't have to be zero. So basically you can think of this as we don't have to name the very first byte um As one Right, like we don't have to start counting at one as long as both sides of the stream know Know what we call zero, right? And similarly we keep a similar sort of values for the receive buffer specifically we keep track of Where What we are expecting to be the next byte we receive And the window for receiving and also the the sequence number that the other side has counting as zero Right, so this is why these segments are labeled So everything that's in one so everything before this line is data that has old sequence numbers that have been acknowledged Two is uh sequence numbers that we have sent but that the other side has not yet said that they have Three is so everything between here and here Is sequence numbers that we're allowed to use in some sense, right? Because This is the first bit of data we haven't sent and we're allowed to send up to this much Right, like a window more than where we got acknowledged And so all of this we're allowed to send if we if the user gives us data And four is stuff. We're not yet allowed to send And so three is referred to as the send window. This is where we're allowed to send And the receive space is sort of similar in that Everything before receive dot next is stuff that we have received from the other side Um And we like we we're sort of done with that. We've passed it to the user space Hopefully or we're about to but there's like nothing. This is just data that we have received two is uh Sequence numbers that the other side is still allowed to send us So it's within the window that we have announced to them and three is stuff that they're not allowed to use those sequence numbers yet And so we're gonna have to keep all of this state for every For every connection and so we might as well just sort of keep it already so we're gonna have A struct which is going to be a send sequence And that's going to have This which I guess is going to be a u-size Next which is going to be a u-size Window which is going to be a u-size Uh urgent pointer Which I think is like a boom I think the urgent pointer has even been like deprecated. So I think we can probably just ignore it But let's keep it just in in conformance with the spec Uh w1 in fact, let's uh also just for our own sake do this I like it when documentation like keeps data Keeps comments from the protocol specs because it makes it really easy to Refer back and forth to them to someone trying to read the code and trying to understand it later Um, and in fact for own sake So this is a u-size this is going to be a u-size And iss is going to be a u-size And then in fact this Is probably useful to include as documentation on this struct. So this is something like Uh state of the send sequence space And then I guess we can also refer to 3.2 This is rfc 793 Section 3.2 and just For our own sanity. We probably don't need this to be So And this is figure 4 So this might help us later when we're like looking back at documentation things. In fact, these can arguably be Proper documentation so to speak And similarly we're going to have a receive sequence Actually, we could maybe call this send sequence space And this is the receive sequence space and the receive sequence space is a little simpler. It's uh next which is a u-size Window which is a u-size Uh up which is a bool And irs which is a u-size And here too we'll sort of keep the docs Um one reason this is nice is because it means that we're going to have to switch back and forth a little less um at least One might hope This is the receive sequence space So we'll do the same here This is rfc 793 s3 2 figure 5 um And similarly here You don't need that this can be this And this will be this Okay, so now we have the Those set up and in addition, um, there are a bunch of variables that are That are used Um Sort of as we discuss the protocol further down Um, they talk about segments and we'll get back to that later Um So the idea basically for us as as sort of a tcp client Is that we're going to make sure that or we're going to Want acknowledgements for these um So these are things that we have sent but have not been acknowledged and if we have to send more data We're going to use the space of sequence numbers Right Uh, so now the question becomes like what are going to be defaults for these right? So a connection is certainly going to have a Send sequence space And a receive sequence space But we don't really know what's going to go in them And so down here, I guess we have the diagram Um, and so this is where it goes into sort of discussion of the sequence numbers And this is also something we sort of need to walk through Um, so every octet so every byte of data that's been sent has a sequence number Um, and because we want to make sure that the receiver receives all of them in the right order Because every byte is sequenced every one of them sort of can be and should be acknowledged Um, and the idea is that it's cumulative So if I say if basically if I send you an act eight, it means I have received all the bytes up to eight And notice that it's not inclusive Right, so if I say if I act eight, it means everything up to but not including eight has been received the sort of of the first numbered bytes um Numbering within a segment As the first data octet immediately following the header is the lowest numbered. Yeah, so If you receive a packet that has a bunch of bytes in them, then the first byte after the packet has the Sequence number of that packet So this is when they talk about segment the segment is basically just one packet So this is the sequence number from the header of a packet that we received And that gives the sequence number of the first byte of the data in that packet Uh, and the sequence number space is finite, which is important to remember So specifically it's 32 bits long Um, and this means that like the sequence numbers are going to wrap around if you send enough data um uh Okay In response to sending data that tcp will receive acknowledgments the following comparisons are needed to process the acknowledgments Let's see Yeah, so the idea is that we as a sender we're going to send data to the other side and it's going to send us acts back Uh, and in order to do that, um Yeah, so this is going to be the Last sequence number we have sent but that has not been acknowledged, right? So this is the values from before um This is the acknowledgement field in the header when we get a packet from the other side Yeah, so this is the so again, this is up to but not including right So they are expecting to get something with the sequence number next Uh, and this is this is these are on segments, right? So these are headers of the current packet So this is saying that the first byte of the current packet has the sequence number And len is the the number of bytes Contained within this packet And so necessarily the If you add these two and subtract one that is the sequence number of the last byte in a packet And so here they sort of define this notion of what an acceptable ak is and if you look at it It's actually not that surprising, right? It's saying that um if the um As long as the value they are acknowledging is one that we're expecting an acknowledgement from right So we believe we have not received an acknowledgement yet. We receive an acknowledgement and uh that acknowledgement is Uh something that we have actually sent right So next is what we're gonna the sequence number we're gonna assign to the next byte we send Which means that if they try to act something that is greater than this It means to try to act a byte we haven't sent If they try to act something that is before Before this it means we've already received an acknowledgement for it. So we don't really care about it And If you have a packet that's like on the retransmission queue so something you might have to say again You should consider it acknowledged if um Basically if the last byte the sequence number of the last byte in that packet Um Has been acknowledged Yeah, so these these um these sort of checks here are things we're gonna have to add later They're not important for the setup, but they are important to do Uh, so we're gonna end up having to look at these. I'm gonna ignore them for now So because the very first thing we have to do is the handshake, which is this part. Um, so Sorry Yeah, so part of the part of the problem is that tcp Allows you to like establish many connections, right? So we have these quads and there's nothing stopping you from like starting another connection with the same quad But tcp sort of has to detect that this has happened Uh, and the way it does that is by Basically randomizing what you call the first byte of a stream because that means that if someone because you randomize it every time When you start randomly, um You're unlikely to start on something that's valid for the other For for some connection the other side is still remembering from before Right, like they're remembering this part of the sort of sequence number space You pick randomly you're going to pick like somewhere Out here because it's a very large space And that is far outside their windows So they're just going to go no, this is not a part of my stream And they're sort of going to detect that something went wrong and probably terminate the connection Um Specifically they want to assure this even if tcp crashes and loses all knowledge of sequence numbers Um, and so this is why when you create a new connection you choose a random initial sequence number And imagine that it's just like actually random In reality, they sort of want it to be Uh, not quite just random, but so that it increases over time to makes it Sort of maximally unlikely that you end up in the same sequence space as someone else There's a bunch of assumptions here that probably they're unclear whether hold on the internet today But we're just going to start with this being Uh I think actually random is probably what the current recommendation is but it's not important Yeah, so there's the initial send sequence number that's chosen by The sender and the initial receive sequence number, which is learned during connection establishment So this is going to be in our case because we're first implementing the server We're going to receive a sequence number from the other side. This is the sequence number of their sin packet So that is going to be where they're going to start transmitting Right and in response we have to send them a sequence number, which is the sequence number that Uh, we are going to start transmitting from So at at the beginning the two tcp hosts are going to have to synchronize and this is done in the The sort of handshake protocol that uses sin for synchronize and that includes the initial sequence numbers Um, right. So this is the this is the actual handshake protocol and so a tells b that they started this Uh, and then b response. Okay. I got your message like I got your sin and then it sends my I'm starting at this location And a says, okay, I've heard that and these two can be combined because they're both being sent from b to a And that's how you end up with this handshake Right. So this is the three-way handshake So, uh, now that we have that before we start digging into sort of actually sending data, let's try to now, um Figure out how you're going to start a connection Um, I feel like these we sort of want to be We're going to have to figure out what to do about this on the I I don't think this can be default Um, but let's figure that out a little bit later Let's not do this highlighting. So the question then becomes what goes in this unimplemented part, right? So this is where we're writing a tcp header. We need to give the sequence number and the window size Well the sequence number so because we're we're receiving a sin and sending a sin act, right? So the sequence number we choose really just has to be random Right. We have to pick some number, which is where we're going to start transmitting from and that number we have to give to The other side So we're going to match on self dot state, I guess And zero is random. So we're going to start at zero Ultimately, we're going to change this value to be something that is actually random the way the spec says But for now, we're just going to say zero Uh, this other thing is the window size, right? And this is how many bytes are we allowed to have outstanding? And if we look further down Oh quiet time. There's a lot of stuff in tcp There's like a suggested window size somewhere, but I don't remember So the tcp spec is actually pretty easy to read if you sit down and read through it and it is pretty interesting They talk about a lot of different interesting challenges that can come up There's the place where it's said Window management suggestions Let's start with a window size Seems fine Again, like there are protocols for that basically determine how you're supposed to set this But for us, it doesn't really matter in this initial setup phase This is more for us to understand what's going on What we could do here is something like have a function that determines where to start Now the other thing is keep in mind that they just sent the other sides just sent us a sin that we're acting Right, which means that we need to acknowledge their sin And the way we're going to do that is by setting the acknowledgement number Right and remember that the acknowledgement number is the next byte we are expecting to get from them Right and so that's going to be Where's the sequence number so The sequence number they sent us is the sequence number of the sin We have now received the sin and so therefore the next thing we're expecting is the next byte So that's the next thing we're expecting in addition oops The other thing we're going to have to do is set the So our sequence number we already set to zero above But now we're going to have to establish a bunch of state for ourselves right so specifically The for the send state we're going to have to send set a bunch of stuff And for the receive stuff we're going to set a bunch of stuff So First we need to keep track of sender info So this is the receive window the the other side Sent so in this case, let's call us the server and then the client The client sent us information about their sequence number and like their initial sequence number and also sent us stuff about Their window size and we need to keep track of that in order to keep track of their window Right so in self dot receive We have a receive sequence space So that's next window this urgent pointer and irs And so the irs is just the sequence number that they just sent us Right because that is the sequence number of the sin, which is the first thing they sent us The other thing is the the next Byte we're expecting from them. Well, I guess let's do these in order The next byte we're expecting from them is the The Sequence number plus one right because we've received the sin The window Window size And the window The one indicating the acknowledgement field, which the sender is willing to accept Right, so that is their window size The urgent pointer we don't actually care about Which means that here we have all of this sender info Right, so this is all the stuff that they sent us that we need to keep track of and now of course you'll notice that the acknowledgement number Is really just the next right So in fact, we can just do this in fact we can we can take advantage of this further further down in the protocol In that it will always be the case that the acknowledgement number is just the next thing We're expecting to get from them and so this might be something we can sort of factor out later on In addition we need to decide on stuff we're sending them Right, so we have to establish our send sequence space Right In particular we're going to have to do something like the Last thing we sent them that is unacknowledged is whatever the sequence number we choose for our sin is right That is the thing that we've sent them that they have not acknowledged The next one we should send oops The next sequence number we should use Is this one right so it's one past the sin The window size we're going to use is I guess 10 right that's what we chose further down The urgent pointer we don't care about the WL1 I don't know what we initialize to it's used to basically compute how Aggressive we should be about sending things So I think we're just going to not set it for now And the Iss is zero So the reason I said iss here first is because the iss is the sequence number of the sin Right, so this is why arguably this should go here As well And so now of course we can use here The sequence number here is going to be the iss And then 10 this is going to be our window size And at this point We now sort of have ooh these are in These are in send All right, what am I missing sequence number is probably a function No field receive on state Oh, right. This should all be on connection The sequence number let's do as you size Well, it's going to be all sorts of painful All right, let's stick to the types they use which is The sequence numbers are u32s the windows are u16s So this is u30 this is u32 this is u32 this is u16 Uh, this is u32 The reason I use to use size is because there are there are tcp extensions that basically Increase the size of these values to Accommodate for having more data in flight Um, we're probably not something we care about right now Uh self dot send Oops send And this is send dot and this is send dot All right, how's that To right so this is for the defaults Yeah, so this is why it's a little weird actually to um Set up a connection in the first place Oh Specifically what makes this weird is um if a connection is closed So here's where this is weird. Um If we're in the closed state, we have no state for any connection if we're in the listen state We also don't have any state for a connection. All that means is that we're sort of willing to accept connections Um, which means the connection doesn't really have a default because if you're not if you're listening you don't have a connection It's a little weird for this to even have a default Which is why I wonder whether Um We should not have default And instead have something like Which gives you a self and what that will do Is actually this So we're gonna have a an accept which is how you accept new connections So that assumes that you have no current state is going to produce a state right I guess maybe option so this is going to be okay none Uh, so here we're going to create a new connection Its state is going to be Uh Well presumably we received the sin So according to the diagram We're going to be in the sin received state sin received Uh receive is going to be uh Receive sequence space And send is going to be a send sequence space Yeah, this is actually probably nicer So Great So that then gives an okay some c What am I missing? So send has some other fields specifically Up wul1 and wul2 So I guess up is false wul1 is Zero wul2 is zero I don't actually know what these should be Um, and what does receive sequence space have? Up which is false So let uh Iss is zero This is plus one Beautiful And this is a comma Right, so this is here We're creating the entire state for a new connection because we received the sin right which is represented by the state Um, and then we send the AC Let's see So in main now this changes the Set up a little basically what we're going to do is we're going to match on entry So I guess here we're going to use Collections hash map entry And if we get an entry occupied Then that is an existing connection And if we get an a occup vacant Then we do something All right, so if we get an occupied one Then we call on packet If we get a vacant one Then we're going to do if let some Connection is equal to Uh tcp connection except Nick iphd These things And if that is some then we're going to insert that connection So we still want an on packet Right because there are going to be cases where we actually receive a packet and we have some current state In which case this will probably do something like u size actually probably won't even do that I'll return nothing And currently that function does nothing unimplemented What this means is that initially um if if we get a connection for Uh if we get a connection from a quad that we don't yet know about then we try to accept that connection Uh wouldn't random but decreasing be better though Is the sequence numbers increases as you send bytes? Uh so um This part of the rfc for choosing initial sequence numbers has been like obsolete by later rfcs So I would just like sort of ignore what it says because if you look at the 74 14 Some of the other things I think it's 11 12 11 22 already Goes into a bunch of details of like all of the ways in which that is broken And what you should do instead you get mute all this has to be mute This probably also has to be mute all right Let's see what happens now Send a packet Well that doesn't look great so The packet went to us and we sent Something in response Not entirely clear what Uh then we panicked at not yet implemented at 140 at 149 Okay, so I think what that means is we got the first packet and then it tried to connect to us again and then we crashed um But this though is not very promising that suggests that whatever it is we're writing back is not correct um Also, how is it? One four five six And something is not right here Um, let's take a look at what the Responding with These bytes Buff So it's responding with A ton of bytes at least why are they weird? Um, let's look at so what we're supposed to respond with is an ip header So the ip rfc It's like rc 791 Let's see header format Version Actually, that's another good question. Let's uh compare that to what we received So Up here, let's do Got header sent header Just so we can sort of compare the stuff we got in and what we sent out um, so this is going to be uh, ip h and ip Oh, is there even a way to get this out? Probably not So let's just do that. Oops. What do I do tcp header? Is it complaining about I don't think it's complaining about anything good Oh tcp h All right, so let's see what happens now So What it got in for the ip header was 45 00 And then so the question becomes what are these bytes? Uh back to this So these bytes are Version is the first so version is four Which is what we also what we respond with So four five is correct Then it's zero Zero and then this is length So that's fine Identification is 24. What is identification? Okay, that's fine It's fine for that to not be helpful flags We are not setting any flags. Are we? Total length Okay, so this is this Then total length is the next Oh man, the scrolling is going to be annoying is 003c and we give 0028 so that's fine Identification is next So this is oh man uh 24 cd and we give Nothing So what are the flags next down here? Okay, that's fine. Time to live and protocol flags and fragment offset Time to live we do set Specifically, I think if we set it to what was already there Protocol follows that so protocol So they send 40 0040 06 Okay 40 00 40 0 6 That doesn't seem right Let's try it again 45 00 003c 24 cd 40 00 40 006 So there we give it the same and then their header checks them is 94 9b And ours b9 7c the checks them is sort of unimportant Source address So we're setting our source address We're not reversing them Or maybe we are so their source address is these four bytes Our source address is These four bytes. Okay, so we are reversing them Right, so ours is zero two. There's a zero one. So that's inverted So that looks like the ipv4 header is correct So I wonder why Hey, that's not Looking right. Huh, let's see what This says for send Unsuccessful send the number bytes sent in the packet is returned. Okay. What about our tcp headers? So ours start with zero one That seems maybe problematic But the weird thing is this couldn't even parse out the ip addresses Saying raw packet data, which is a little odd Also, we're sending on an awful lot of zeros Which doesn't seem right Um Oh, wait, this isn't right This is how many bytes we didn't write Which is this is not what we want we want, uh Buff dot lend minus unwritten I think I mean it's still still crashes, but at least now we're writing out fewer bytes um So the first part we still have Right, so that goes up to there And then we're sending It looks like an extra zero one 0001, this is the end of the ip packet and then we're sending zero one bb And then ba 86 So we're inverting these values. Oh, so these are the tcp ports Okay, so that is correct. We are supposed to invert the tcp ports um Then we're sending All zeros Which is our sequence number is that right? Um, which is Is our sequence number. Yeah, so our sequence number is all zeros Uh, and then we send our acknowledgement number, which is this part. I wanted to scroll Um, so starting at zero f which should be the same thing as they sent us their sequence number Right And what they sent us is their sequence number Was this value Zero f 60 d 172 zero f 60 d 173 right so plus one so that's correct Um, there's a bunch of other stuff that shouldn't matter And I think our length is the same as theirs Also, oh, I see and then check some an urgent pointer It's like the last bit that they're Including here specifically following the um So they sent that then the acknowledgement number, which is all zeros then One two three four bytes of stuff where the last one is their window Right, so these are their window f af zero Then check some an urgent pointer So the urgent pointer is zero and they're sending a bunch of tcp headers So why is ours differing from that? So we're sending This is the sequence number Then No, this is the acknowledgement number then these are the data offset and reserved This is the window So zero a there is our 10 Uh And then we send Check some and then we'd say an urgent pointer that checksum is wrong though I don't think we're allowed to send a checksum of zero But certainly I think it's I think it's not true that the checksum is zero more more importantly Um Oh interesting Okay, so I think we yeah, we need to manually compute this checksum as my guess as well. So specifically, um Down here We're gonna have to do Check some is gonna be uh The sin ac dot Calculate checksum for ipv4. We're gonna give the ip header Uh the one we're using to send Uh and the payload is gonna be empty and that Should give us available to compute Check some Okay, so that should give us the checksum which should be set on the sin ac Check some it's gonna be equal to that Let's see if that makes a difference Oh What's going on here? What did I miss out? Oh, this should be a semicolon great Now shark And then try again Raw packet data is still what it says Actually, let's have it Stop trying to Crash here because it's a little annoying interesting Why does it just say raw packet data though this packet looks entirely fine Um specifically, why does it not think it's a valid ip one? send Must be a valid representation of a packet I wonder whether there's a um here Time tap dot texts. Maybe we need to include these as well. Actually, that's probably true Um So we need to set flags and proto And I think what we're going to do there is um Yes, remember that will we get in here? Oh, I wonder whether I can just turn that off No, I don't really want to do that Hmm Specifically this is like if no pi um Which the question is whether we have to put those four headers at the beginning Uh When we send as well I don't think we care about that. Okay, so let's make this Um, let's make this Without packet info And now these are going to go away There's no longer going to be these four bytes at the beginning And in theory we shouldn't have to write them when we write back either packet ip okay, that's fine And now if I do this, what's it gonna do? Oh, how about that? Okay, so now Look what happened. So um our client Yeah, so it's basically Uh, why not model this as state machine with transition between states? So the okay, so that's how I started it out, right with connection being an enum The reason I didn't do it this way was because there's a bunch of state that's shared between almost all of the states um in fact the the The things related to sequence numbers and acknowledgement are actually associated with all of the states that are where the where there is a connection um And so that's why we have the state enum But there are some fields that are not a part of that enum because they would be in every variant So we will still use an enum for the actual state machine um Yeah, so here what happened was this program Okay, so for what is worth netcat is a program that just like connects to here and then just whatever bytes you give it to standard In it's going to send over the network um And so it's connecting to zero two and indeed we see that connection here and then we see that we sent a response here right and it looks to be Sent to the right port right. So this was the source port. This is the destination port. It has sin ac it has a sequence of zero It has a an ac of one Which is correct because the sequence number they used was also zero And we have a window of 10. They have a window of 64 000 And a length of zero because we're sending no bytes And then they sent us an ac So this ac is supposed to be um Well, basically this ac is saying I got your sin and at that point the connection is established So that is the next packet we now have to handle Right, so this means that now actually our our initial part of the handshake worked out correctly Um I suspect that we might not even need this. I think the kernel does this for us Um, but let's double check Yeah, the kernel does that for us Kernel is nice and does this for us Now we don't actually need to print these bytes anymore, which is going to be make the stream a little nicer Let's also do Let's also do this because we don't care about it um All right, so now at this point We're going to do c dot state Oh, we already set the c dot state, right? So down here. This is where the state machine comes into play We're going to match on self dot state um, and if the state is Well, so let's just imagine that state closed doesn't exist Right, if if it's closed then like we have no state Listen as well is a little weird because If you're in the listening state, you also don't have any state, right? You don't have any connection yet And so in some sense, it's a little weird to think of it as a As a state that you can be in So let's ignore that and rather think about established because in theory what we're going to do is move from this to this um So if we're in syn received That's where we're sort of Expecting to be right now How do you feel about the rust mascot? I like the crab um If we're established then this is something that we haven't we don't know what to do with yet But if we're in syn received now the question becomes now, what do we do? well It will tell us So specifically if we're in the received uh If we're in this state expect to get an act For our syn Right, that's what we're expecting right now I think one thing we're going to want here is almost to keep track of this ip header um Just we don't have to repeat it every time Yeah, I wonder whether this is something we actually want to stick into the um Into the state of the connection Well, actually I guess here is going to be an ether parse ipv4 header that we're just going to Keep around there in such a way that Here Because we're going to be using basically the same ip header every time There's no reason for us to um There's no reason for us to have to go through the steps of like parsing out the Source and destination fields each time the one thing we will have to be careful about though is um Uh ip dot Um What's that field the payload len? How do we set? payload len to be syn act Dot What do we have it set to header len Uh plus zero bytes for the data on receiving you strip the first byte from the ton slice need to boom back yeah, so so um We no longer need to do that now because I Added this without packet info because we're now constructing with without packet info. We don't have those four bytes anymore If no So because we're ignoring the packet info we don't have to do that Right, so we need to set the payload len of the ip ip every time we're going to use it, but apart from that we're probably fine Um, there are probably some other things like we could have a convenient method on Here on connection that's something like send Right, um that does this trick down here for us um But we're probably not going to be able to actually use this most of the time because the retransmit queue Um, it's gonna well the retransmit queue means that we might have to send things later So we actually have to keep track of the bytes Um c.ip And this is also c.ip What's he complaining about now? expected u size phone u16 All right, um, so what do we do when we get a syn act? Well, uh if the Uh So here there are a couple of things we need to do right so if you remember from from the rfc um, they talked about this Uh, where is it down here somewhere? This acceptable act check right which we basically have to do for any packet we receive Check Which is to make sure that this is an act that we shouldn't be ignoring because it sort of Is something that's unrelated to us or was sent incorrectly by the sender Um, and so we need to do that basically regardless of what state we're in So we're going to do if tcph dot acknowledgement number Um So here one thing that's tricky is all of this is uh wrapping it's wrapping arithmetic. Um, so specifically if um tcp acknowledgement number is Right, so remember that because we can wrap around right this is 32 bits You like it it doesn't really help to just do to do this sort of stupidly right of self dot send dot una minus this and tcp uh h dot act number um Less than equal to self dot send dot next If we did this This would not actually do what you want Wait, what what's it complaining about? Oh, wait, what am I missing? Why is this happy with me? Oh Double exclamation mark So, uh, this check writing it out like this will not actually work because of wrapping arithmetic, right? Both of these need to consider wrapping so the check really is that this is between those when considering wrapping arithmetic Uh I'm I'm not creating a socket server per se and this is implementing tcp Um, it might let you write sockets, but it's not a socket server I don't really know what you mean by socket server This is implementing the ways that sockets work sort of under the hood in some sense um It's a really what we want here is sort of a a comparison that Checks, let's see if So there let's first do uh ak n is tcp h dot acknowledgement number just because um If ak n is more than self send una But remember wrapping Okay, so if ak n is more than una then we require that it is Less than or equal to next or or rather actually if if it's less than una it might still be fine, right because um How do I even visualize this? Um, let's try it here So Um We have this space where there's uh, there's una Right, uh, and then there's the ak we got Um, and then there's next Right, and we want to check that uh, ak is greater than una and that it's less than or equal to next It's very unimplemented. Yeah, um, but of course because because, uh The 32 bit space wraps around um So at some point like imagine that this is zero um, it sort of goes like This way and then comes back around here. So this is also a very large number So imagine that there are a couple of cases that we sort of need to think about um, so For example, we might have that Like so the simple case is that you have This U a n Right, this case is simple because you can just do straight comparisons where it gets harder um Is when you have something like Like Here is you Here is a and Well, that was a stupid example I should have done wrapping the other way. Uh, let me Oh man Erasing of this program is really annoying, but I think there's a Yeah No Erase That's awful. Can I get a bigger thing? Like brush But this Yeah So Let's draw that again. Shall we So zero is here And then the numbers go this way, but here, of course we wrap around to zero So now the simple case is, um You have U You have n You have a you compare them straight. Everything is fine Where it gets weird is if you have U n a Oh, man, this should be sorry should be let me clarify. I wrote the letters in the wrong order um, so specifically Um My thing, uh, so if This is a and this is n similarly Um, this is a and this is n Right, so the red case is trivial the green case is harder because here if you just compared una you're that's not good enough Right because u is greater than a which is not what this requires Right, this requires that u is less than a but in a wrapping space they are And the same you have the same problem, of course between um Between here right like if there's a wrap between here, then you would have the same problem with that comparison And so this is the trick that we're going to have to overcome for this check That this check is not just going to be um This check is not just going to be a straight comparison Specifically, I think the trick here is going to be to compare them pairwise so specifically if um una is less than ak n right if So if u is less than a then either we're in this case Or we're in this case Or there's an error right so here if uh Sorry, it means we can't be in this wrapping case Correctly because u is greater than a so for this to now be correct. We now need to do the comparison of a to n um, so if ak n is less than self dot sen dot next Less than or equal Right, so this is this first case is the trivial case no wrapping Right, so we're all good So it's u less than a less than or equal to n So all good In this case, uh, we have u is less than a Uh, and a is greater than n So can that happen with wrapping? Well, you so let's think about it. Um U is less than a So we have u a and a is greater than n So n is somewhere over here Well, that's fine As long actually is that always fine? Isn't this check just broken so specifically When would this ever not be true? right like I'm imagining Here for example um Like u So currently we have u is less than a right Isn't this true for any n? like If n is here then n is Greater than or equal to both of them. I think the requirement is that n is less than u Right, I think the requirement is that a is between u and n and u and n are not overlapping Right because if n was here that just seems wrong Right, I think specifically the case we're looking for is we want a to be between u and n Which means that we can't do all the way around the wrapping um So I think what we want to do is this Right that that is the case. We're trying to guard against We're trying to do the the knot of this right? um No wrapping So in this case, uh n may have wrapped Check that Right, so in this case u is less than a and we now need to make sure that uh n isn't between a and u Right looking at our picture here. We have that u is less than a so what we're really checking is that n isn't between these two As long as that's not the case then everything is fine um So actually we can write this as uh Check is violated if and only if um n is between u and a so if uh self.send.next Is greater than self.send.una and self.send.next is less than akn And we're specifically allowing We're specifically allowing uh act to be equal to next right So a is allowed to be equal to next So if n is here, then we're all good If n is here, then that's obviously Who actually is that fine? I don't know that needs to be strictly greater Uh We need next to be This is an error even if next is equal to una Great If you compare u to n, don't you know if you are wrapping or not? The problem is you can have wrapping in both directions You can have wrapping between u and a you can also have wrapping between a and n Right and so specifically what we're dividing this into is two cases either If u is less than a then the if u is less than a right Then the invariant is violated if and only if n is between the two of them Right if n is anywhere else either to the right or to the left then it's fine Because if it's still the right then it's more than a and if still the left it's just wrapped around and is more than a So that part is fine Uh promoting to a bigger type wouldn't help because you still you can't do the unwrapping right is the problem Um in this case, so let's draw this other case out All right, um So let's draw the other case out with Pretty blue colors um So this other case is that we have um We have a and u right a is less than you Right that was This is if u is less than u is less than a right. So this is a is less than you or they're equal This check is violated if and only if Uh If n is in between here No, this is okay. Only if n is between here Otherwise it's not okay right if if n was here If this was n yeah um If this was n Then we would have a problem right because now a is not between u and n So if a is less than u, this is a problem if n is between a and u um Okay, if Check is okay if and only if n is between u and a so that is a nice symmetry to it um Back in and self dot send dot next is less than this Else this um, and for the equalities um, the requirement is that Next is allowed to be equal So the check is okay if n is equal to a So self dot next is greater than or equal to a that's fine And it has to be strictly less than u Which this check is here as long as those two are both true then we're fine So we're not returning. Otherwise we are returning Okay So when we get to this point, we now know that we what we have is an acceptable act who This is for This is when you receive data, which we're not really doing. Well, I guess technically we've received data Uh When data is received the following comparisons are needed Oh, this is for right. So this was for checking the act and now uh, check that so this is the uh Valid segment check Right, this is to check that the the bytes that are in this packet Including the sin the sin counts as a byte to check that those are within the range of things we're willing to accept So I guess let's actually give a 3.3 referencing here Uh First check that Uh Sequence numbers are valid 3.3 So this is r of c seven nine three section 3.3. Right. So the valid segment check Is similar, right? It's very similar to what we did above specifically it's that um It's not what this is um So going back to our picture here. They're really just swapping out the These values for Instead of una it's going to be They want next. Oh, why is this pen different? Oh They want next To be less than or equal to The sequence number from the packet Which should be less than Next so this is next in case that was unclear next plus window Um, so what we could probably do is just have a function that does this kind of wrapping arithmetic, right? Because we're going to need this check in multiple places Um because the check is pretty much the same So let's down here do Uh do something like Fn Is between wrapped Uh, so we're going to have a u size b u size c u size And this is going to be start It's going to be end It's going to be x And it's going to return a bool And we sort of want this to be Uh, so the question is should this be inclusive or non-inclusive? Let's write it as non-inclusive Um Okay, so we can read this as Uh If the start is less than x If end is between Start and x So I think this is going to actually make this a lot clearer, right? So if we because these cases are sort of weird, we're just going to call this start This end and this x Right, so now it becomes a lot more intuitive So if we find that the start is less than x Then it's wrong if the end is between them Otherwise if we find that the Start is after x then it's correct if the end is between them Right, so you see how this is the I've just relabeled the markers, but now it's a lot clearer why this is correct Um So this is end This is start This is end. This is x So if the there's probably a like a way you could do this without all this branching But I find this easier to reason about Um, yeah, so if start is x then it's violated if and only if the end is between start and x Uh And specifically If we want this to be non-inclusive For both sides Then we require in this case we require that n is not in between here And is it allowed to be equal to start? Uh So what we're doing is s less than x less than e Not sure if start in less than x and We're doing non-inclusive Then n has to be Greater than x Which means that it's Not okay For it to be equal to x Yes It's not okay for it to be equal to x great and that's indeed what we have here similarly If the end So we want this to be true. We know that this is less uh If x was So what I don't think the comparison with start matters actually I think all that matters is a comparison with end Although it might matter for for this case So If the start We want to check this right so we're writing the non-inclusive version um If it is the case the start is less than x Then we require that then I think it It should fail Even if the end is equal to start Right because if the end is equal to start Then this is not true Yes, if the end is equal to start, this is not true So If the end is equal to start Yeah, so if the end is here or up to but not including x Then we're going to say that x is not between start and end If end is Equal to x No, that's also not okay. Yeah, so these are both equal So if n if the end has any of these values including start and end then it's not okay Otherwise it is so if end is here then we're fine Right start is there e is here x is here and so x is indeed between start and end um If end is here then we're also okay because x is indeed between start and end If end is here e is not between start and end and if he's here isn't it's not between okay um Otherwise so this is if start is Greater than or equal to x. So this is this case, right? uh I guess this is going to be If start is equal to uh x Then we give false right If Oh, we could even here do Uh match start dot Um Does it compare the thing that gives me an ordering? That's what I want. It gives me an ordering great. So match pair x that way we don't have to do it multiple times. Um So we're going to use Uh Compare or an ordering Uh, if we get ordering equal Then false Right if start is equal to x. There's no way in which x lies between start and end um If start is less than x than this If start is greater than x Then this case, uh, and otherwise Okay, so let's look at the greater case It might actually help for us to draw this out here We have Okay, so we have some timeline I'm sorry timeline, uh number line where start is somewhere And x is there if uh, let's see x is between s and e if and only if uh and If it's not the case that This holds Oh, I don't need a word. Yeah, you're probably right, right? So I think this drawing makes a lot of sense in the sense that uh In these cases Let's make it really explicit for ourselves So that's fine This is also fine But not in these cases That's funny. Uh, I don't know how to Mark this now I guess this is gonna be like plus e Or in other words Great So comments help Hopefully these diagrams explain a little better what's going on We have So in this case We have the opposite of above So I guess here we want Raps wrap around I sort of want this to say zero so here We have this where we have x and this is s um x is between s and e In these cases, right? So here we have x s and e Uh, and in fact, it's only between them in those Only in this case But not in these cases I guess that would be This case for example Right because then in this case Oh, did I remove the case? That was kind of stupid. Where did I put? There Um x is between s and e only in this case Right, not if e is more than s not if e is less than s Than x right then x is not in between and if x and e are both there or is s and e are both there Then it's also not the case that x is between s and e Uh Or in other words, uh, if and only if Uh, yes, uh or in other words If and only is if Uh This case So next Was end No, this is x This is end This is start Or in other words If So only in the case where end is less than start and end is greater than x Great and now we can use this Up here specifically If not Is between wrapped self un a Send dot un a self Ack n self dot send dot next And we want this to be inclusive. So this is wrapping sub Uh wrapping add one Right Because if we if we want it to be Is between but you're it's allowed to be equal to the end We're just going to increment the end by one and it needs to be wrapping because we want it to go around So it's not between then we're going to return. Okay Uh the valid segment check which we can now do The valid segment check Is this So we're going to do the same thing Uh Let seek n is tcph dot sequence number and if Receive dot next Uh dot wrapping sub because we want to allow equality Uh seek n to self dot receive dot next Wrapping add self receive Window It's not between those then we have a problem Expected Uh As you 32 Great and also or or what does this mean? Did they give this? Oh, I see So this one's kind of tricky Okay, if it acts at least one byte Which means that At least one of the following is true Specifically notice that the reason that we use these both checks is we're basically checking Uh the first byte of the segment and the last byte of the segment and if Um, if any of like if if one of them contains something that we that was within the window We want to accept those bytes so the sender doesn't have to send them again Uh, so in this case, this is still wrapping sub This is going to be not second, but Well second plus tcph dot Um, what was the name of the tcp header payload length again? Uh, oh, it's just data dot len minus one Window end is going to be that So that's going to be this Why is this not formatting my file? Oh, I did something stupid 196 Oh expected usize found u32 Oh, yeah, these have to be u32, of course, because that's what we're operating on Um Cannot add It's u32, I guess All right, so now that we've made both of those checks in accordance with this Yeah, exactly Do you zero into its length say in three four cases? So there's actually more than this It's also Hmm, what is the receive window here? I see so there's basically special rules for Oh man Uh if Both of these are for if data dot len is zero And not tcph dot ak Sin and not tcph dot fin Because these also count as bytes zero length Segment Has its own Has separate rules for acceptance Yeah, exactly So this is acceptable if sec n is equal to self dot receive dot next if If self dot receive Actually, this is if Ah It's like Okay is equal to this But uh So it's if The receive window Is equal to zero then if sec n Is Not equal to self dot receive dot next Then it's not acceptable else Uh, then it's this check Which is basically just This check We still want this up here else If self dot receive dot window is equal to zero then it's never acceptable According to the spec else this business And of course this can become an else if And this can become an else if Whoo All right And now I have a syntax error somewhere there And also there Okay So we did the thing This is also not true because The seg dot len Also counts in and fin So Let s len is data dot len Uh If tcph dot fin then s len plus equals one And oops And if it has a sin Then s len plus equals one And now anything that looks at That This is a u32 Whoo Is equal to zero Great Okay, so now So this was just the check we have to do For whether or not we are even willing to look at this packet So to take a step back from for how we got here. This is we have The other set plays the other host sent us a sin We accepted it that was the function we wrote before And in response we sent it an ak for the thing that it sent us and a sin for it to send its part of the handshake and now And now what we want to do is um Take the ak that it sends to our sin and parse that and hopefully Hopefully we should get into here Uh So at this point Hopefully we should now be receiving a Ignore all of this for now stop using a connection Right, so we are at the point where Um, so we're we're basically b in this case, right? We were in listen. We got a sin So we entered sin received we sent this and now we're about to receive this packet And now if all the checks work out Um in theory Well, so first of all, uh, we should check that tcph.ak is set If that's not true Then like something was weird. We didn't get an ak to our sin. So That doesn't really help as much Um Yeah, this seems like a really weird packet to get. Um, okay, so if this is an ak packet um It must have act at least one unact byte Which means that this must have act our sin because it's the only thing that we have sent And so therefore we're gonna say that our state is now established. Uh, must have Um must have our sin Uh, since We detected at least one act byte and we have only sent one byte the sin So at this point we're in the established stage and at this point in theory we can start sending and receiving data Um instead what we're going to do is we're just going to immediately try to terminate the connection Uh Now let's terminate the connection Right, so, uh tcp has a field returning okay when something's wrong. I agree. Um Although in this case It's like a little weird to return an error too The reason for that though is the way that main is written Right, if it errors, it's just going to error out entirely. Although Like maybe we actually do want to do that Um But this is like these errors are like the client sent us something weird Um But yeah, I guess I guess you are right. Um I mean we could do like IO error New IO error kind Um This is like oh there are many reasons but I guess What do we even want to give here? It's like Okay, let's do broken pipe Uh and call this um Ack had tried to act Unsent byte Okay, so the reason it's a little weird to error here too is that this could just be like Uh a delayed act So just because it doesn't delay any relevant bytes doesn't really mean there was an error It just means that the act was delayed for a bunch of time Um, and so there's nothing useful for us to do with it. It might be an error too But it it's more likely that it's just not something that's worthwhile for us to deal with Um, so it is a little weird to return an error Yeah, exactly. It's like We're accepting that the client did something wrong But it's not really bad for us So yeah, I I think we're gonna I think we should keep that as okay I agree with you though. It is a little weird In some sense like what we should probably do there is like log that something went wrong So down here right now, we're in the established face and the client the other side is also going to know that we're in the Uh In the that face at least once they get our act Um They might send us an additional syn act though. We're just gonna Ignore that case for now Uh Okay, so at this point, uh, what we're gonna do is just tear down the connection again Um for now The one thing that's weird here is we sort of want to Um Yeah, there's certainly a lot more stuff to do with timers here. They're gonna That we're gonna have to come back to like for example Um, actually, you know, this is fine. Okay, uh, so we're gonna terminate the connection And so what we're going to look at then is Down here somewhere for my connections reset generation Yeah, so this is where so to to get to your point where Uh, about like what do we do in these cases? This is where you're supposed to generate a reset Um, whenever a segment arrives that is not intended for the current connection Uh, and that is so this of course in the In the closed case, right where we're not listening So that doesn't matter to us if we're in a non-synchronized state So if we're in like one of these initial stages, uh, and it tries to acknowledge Something not yet sent so that would be Up here Let's add here to Imple state is Non-synchronized And that's going to be true for Uh state sin Sin received Is non synchronized and state established is Actually, I guess this is is synchronized is nicer false Because that way down here we can say if not self dot state dot is synchronized Uh, if we're not synchronized then according to reset generation a reset So specifically this case So it acknowledges something that has not yet been sent, right? That's when this check fails Um On a security level of compartment, which is not no, I don't know what these compartments are Then we should send a reset if we're soon Okay, so in this case we should send out a reset packet send reset That's going to be It's really just going to be the nick So we're going to have this Sort of helper function that is going to send a reset packet actually I think we want to buffer a TCP header here too Because like the port numbers aren't going to change either right, so Wherever we made this Yes, so this is going to be iss and this is going to be window So now we're going to be able to in Send reset we're going to do self dot TCP dot Set Oh It's another good. I think it's just rst is true And what else like? Uh, there's probably some like some rules for What these should be like These should probably all be zeros Oh, you're right. Uh, send reset does not need a lifetime parameter Uh Set payload lin it's going to be self dot tcp dot um This and then we're going to have Actually, here's what I we probably want. We're going to have something like a send which is in fact going to take a lifetime It's going to take a Nick Actually, it doesn't need a lifetime. That's fine. Uh, it's going to take a payload Um of bytes and that's going to do specifically Self dot tcp dot sequence number So the sequence number is going to be self dot send dot next The acknowledgement number is going to be self dot receive dot next um And The ip Set payload len is going to be self dot tcp dot header len plus payload dot len Is there anything else it needs to set? I don't think so This is uh as u-size And then it's going to do this And I guess whenever you call send we sort of want this And we're going to do u-size Because we're going to tell you How much we wrote So specifically send I guess this is really right This is really we're implementing right. Uh, it's a little sad that this buffer Has to be separate. Basically, this is where our program is no longer zero copy Right, we're because what we're going to do is uh, Right, didn't we change this? Feel like we ended up changing this Didn't we find that this was wrong that it wasn't to unwritten but it was buff dot len minus That changed like get lost somewhere Uh, so this is going to sort of send the the things we're always going to have to send whenever we send data And then It's going to create Well, this isn't right. This will be self dot ip self dot tcp Uh, and then self dot buff No And I guess this will be unwritten dot Right, I don't know if that's going to work, but Right, um So let's see We're writing out the headers and then we're writing out as much of the payload as we can into buff Right, that might not be all of the payload um And then Um unwritten is going to be unwritten dot len And then what we're going to send out is However much we did do yes, I think that's about right And now up here This no longer needs to do that And self dot send dot next Is already the iss Actually, that's not quite right We haven't written the send byte yet Yeah And then the hope of course is that this is now going to be just c dot right to the nick with No extra bytes And then this Is going to be Um, there's one thing that's missing here and this is We're missing The incrementing our sequence number So self dot Send dot next is now going to be plus equals payload bytes and if tcp dot ak if self dot tcp dot ak no dot sin Then uh Then we also have to add one And fin we also have to add one See how it would ever fail. These should also be question work. It's like ether parse right error It's not really what I want this to be but No, we're just gonna do that and then just ignore this for now as u32 And this is going to have to be a wrapping add same with this And same with this I feel like this has bitten me in the past That that does not assign So in other words here, uh, yeah great And if this is the case then self dot tcp dot sin is going to be false And fin is going to be false And ak is basically always true Wrapping add is really convenient. It's true Um Okay, so now we have write which means that send reset can probably also do that um Specifically it just sets these Does not have to set payload anymore probably Oh, this is kind of awkward. We don't know how much of that we can fit Actually, we do Fit is self Uh Size is going to be tcp header len plus ip dot header len Uh It's going to be standard min of buff dot len And this plus this plus payload dot len Because we can't write out more than the size of the buffer basically Um 16 plus use surface So that's going to be the size That's going to write however much it can That's going to be And this of course is just going to call self dot write With nothing Oh and with nick, I guess So now we have a function for just sending data out Oh self dot tcp Uh for sending just data out we have one for sending resets and in this case we have to send a reset Um Before we return there's also some like precedence level stuff Uh If the incoming segment has an act field The reset takes its sequence number from the act field of the segment Is tcp h dot Act number Why is the resource sequence number zero? Because it's sequence number Which is really just self send Next is equal to this No, actually that's not what we want This get sending this gets really quite weird Uh It's going to be some to do Uh fix sequence numbers here Because we already have Write already uses like the state of the connection to fill in that Which is not what we want So let's just leave this as a Note for ourselves for the future Any unacceptable segment So this is something that we're going to have to deal with down here probably Uh, this is going to be uh Another to do Handle Synchronized reset It's going to be this business Which i'm also going to leave for later because uh, so resets are basically um Resets are basically for if something goes wrong and we're going to just assume that That it does not go wrong Unwritten is not the same as buff Unwritten is a Mutable slice pointer to all of buff This means that when you write into it it shrinks it Removes stuff from the start so that the next right will only write to parts that we haven't written to yet So it's actually not the same, okay This should be state Um Closing a connection right so this is what we want to do now We want to close the operation close the connection to the To the other side Which is basically saying like I have nothing more to send if you close the connection you might still receive more data You just can't send any more data um Yeah Yeah, so close is simplex as opposed to duplex Okay, so Also, keep in mind currently we're not dealing with retransmissions at all Like retransmissions is something that will also have to be done here But currently we're not doing them in the in the slightest um So specifically Because we want to terminate the connection what we do is we send a packet that has a fin segment So just has the fin bit set Uh, and we enter fin weight Okay, so that's going to be self dot tcp Dot fin is true We're probably have it so what we're we're currently sort of abusing the uh The the stored tcp header here a little bit because it also stores information about like whether we're in a fin state Bullets, I guess to do Needs to be stored in the retransmission queue The reason why this is important is imagine that we have a bunch of data that we haven't sent yet Um, when you send that data the fin bit should not be set It should only be set set for the very last data packet you're sending out Uh, whereas here we're just like setting it on the header for all tc all subsequent tcp packets, which is not okay And then we want to write uh to the nick no bytes Um And then self dot state is going to become fin weight one Which is a synchronized state Of course, currently this looks a little stupid, right? We're setting establish and then immediately moving on but That's still what we Like normally you would not do this right normally this operation to close would be user triggered It's just that in this case we're choosing to trigger it immediately All signals proceeding and including fin will be retransmitted Yep, there's also a question of what happens if we receive a fin So this is sort of in the established case if not tcph dot fin Then unimplemented Or tcph dot, I guess actually or data dot Or so if there's any data in the packet and it's not a final packet, we're just going to throw up our hands and go So if we an unsolicited fin arrives Then what that means is that we want to basically we want to act their fin And then we want to terminate ourselves, but we've already sent a fin. So like this is unlikely to happen Right, this is going to end up being a simultaneous close um But in either case If so, I guess in this case, this is the same as state being fin Being fin rate one. Okay, but in this case we receive that We can act it until the user connection is closing. Okay, so we're going to do self dot right To the nick So this is going to act that act that fin right Usually we'll respond with a close upon which the tcp can send a fin to the other Okay, so in this case, all we really do is we just like act that they wanted to fin um So the question is what happens here. Okay, so in this case, uh, we're b Ooh What's close weight though? So this isn't mentioned that but it looks like if you receive a fin You should enter close weight. Oh, this is rls. RLS works totally fine for me um Sometimes a little slow, but that's about it. Um, okay. So in this case, we do want to go state is close weight Okay, so close weight is another state Um And it is also synchronized. Uh, so this is going to be state close weight and in this case Oh, I see See this is where we're sort of hijacking the the setup a little um specifically We're sort of we're cheating a little here, right because Because of this You're going to enter we know that you'll be in fin weight like this cannot happen Because you must you must get this first To get the connection to be established So we're just going to do this and say this is unimplemented Because currently it can't happen and then if we're in fin weight one Um, and so that's this case, uh, we close we're in fin weight one. We send um We send our fin And now we're waiting for them to act and at some point they're going to act our fin And We're not going to let them send us any data. That's not something we support yet Um, when we eventually get that Then we enter closing Okay, so we're going to ignore close weight, but we are going to have closing So this is um, so here Sequence number 100 Sorry sequence number 300 is where we sent our fin Which means that our fin is 301 because the fin is its own bite So when they hear act 301 that means that now we know that we should be closing Right. So down here, uh, actually this this should be closing So down here when we get fin weight and this turned out to if this check was true That means that the only thing they can possibly have act is our, um, our fin Right because there's no other data They This is the same argument as here that they must have act our fin This is we detected at least one act bite and we have only sent one bite, which is the fin Let's make these wrap the same Um, how did I double exclamation mark this again? Um, and so in this case, what are we supposed to do we're supposed to Act their fin, which we do with this Do we include fin in that we're not supposed to include fin in that that's going to be awkward I guess that means self tcp fin is false And now we enter closing And now What is this though? Are we receiving anything here? Like why are they? What is this act at the end that seems really odd Um I'm just going to close and we can send a fin to the other tcp The tcp then waits until its own fin is acknowledged where upon its deletes the connection Okay, so at this point we now enter time weight So we're there's also not a closing. That's just a lie Well, I guess sort of It's like if it's closing even in the diagram The like giant diagram Yeah, then you send an act and if you receive anything you go to time weight. I see So if we're in closing Uh, how did this work? So we were in established We sent a fin and then we entered fin weight one Yes, yes in fin weight one We receive an act of fin Yep, so it has fin set right otherwise unimplemented And it is hacking at least one byte because of our check up there um ah then I see that's if we receive a fin, which is not we're going to receive We're going to enter then I see so in this case We're going to go self dot state is fin Fin weight two These are excellently named, but that's what they're called in the spec. So, you know Uh state fin weight two Okay, so all we really do is when we get that act is we go to fin weight two Um, and then if we're in fin weight two Then at some point we're going to receive a fin from them Oh, I see I don't think this check necessarily means that they must have act at least one byte I think it means that they act a valid byte They could still Ah no, if they act no bytes, we would not get here I think that's true, but that makes it a little weird because it means that um That fin that we get here is not going to act anything that we have Uh sent so it's not going to act any bytes So let's think about this right so Uh if what are we requiring up here? We're requiring that um They act Yeah, they have to be acting at least one byte because of this check Also, doesn't right have to increment that? Oh, I see So here we should also update Uh, is it saying right here that how we update these? Yeah, so my guess is they go through this in more detail here um Once the connection is established data is communicated by the exchange of segments Uh retransmissions sender data keeps track of the next sequence number to use in the variable send next Yes, we already have that in our write function that makes sure to modify send next Uh The receiver of data keeps track of the next sequence number to expect in the variable receive dot next Okay, so here Uh, we're gonna do something like What's that? I'm gonna be self receive next Uh Is going to be I think w end No, that's the end of the window It's gonna be Seek and oh, I see an error This Should be wrapping Add of that And I think in fact This is what the next This is the next So if we get through this check that means that we received at least one byte, uh, and now the uh Next thing we're expecting to receive is whatever follows that right? So the sequence number of the first byte plus the length Of the segment, which is going to be the first index that we haven't seen Okay, so that's this sentence The sender of data keeps track of the oldest unacknowledged sequence number Right, so up here at this point. We know that something got acknowledged And so therefore our unacknowledged is going to be Again The data flows momentarily idle and all The data's sent has been acknowledged and the three variables will be equal Okay, so, uh, is this true Ac so the ac value is the Um The next byte they're expecting Which means it's the first byte that is unacknowledged. Yes, so this is true When the sender creates a segment and transmits it the sender advances send dot next Yep, so that's here When the receiver accepts a segment it advances Received dot next That's here And sends an acknowledgement, right? So in theory here, we should also acknowledge that, right? But we don't currently have a process for sending data or for doing things like timeouts like We don't know that we need to act this but we happen to act it because we write right here um So I guess like here Make sure this gets Uh When the data sender receives an acknowledgement it advances una. Yep Uh, just for some measure of delay The amount by which the variables are advanced is the length of the data in the segment Sure. Okay, so retransmissions communication of urgent Managing the window is not currently so then we're doing it all That's fine Interfaces we're going to ignore for now That's fine is talking about how send receive and close should work So that's something we'll end up implementing as a sort of higher level interface after a while Event processing Yeah, so this is like a possible way to structure your implementation of tcp Um That's fine. This doesn't seem particularly important I mean, this is probably useful, but it's just not what we want. So this this does uh, give us all of the, um All of the state transitions are explained here, right? Like if you are given an open call and you're in the closed state then do the following um Which is pretty nice And so in our case um here We're in Uh, we're in these like accept. I guess But if receive in this that's fine This is not what I want In fact, what is it we want? What are we missing? Uh here Finway two I think that's the last part we were at So Where's our big diagram? Of all the things here So finway two here at this point. We now have to make sure that our Fin has been act No, sorry Fin weight one as we wait for a fin to be act And so the observation is that we will never get to here because up here um We're gonna get a message that isn't acting anything Um, which is a little weird Wait if act is send dot next. No, that's fine Yes, it's not necessarily acknowledging Okay, it's not necessarily acknowledging it bite because it's allowed to be equal to next but What if these values are equal? They can't be I see They're gonna be acting This is weird. Um Okay, so what i'm trying to figure out is um in this case What we want is for Um If we get an act it should be acceptable for that act to not be acting any data because we might not have sent any data right Which I think this check allows for uh assuming that Unacknowledged is always less than next Because if if unacknowledged is equal to next now, there's no value you can give to act that would be okay Because it wouldn't be greater than unacknowledged So the question becomes what is unacknowledged set to if all your bites are acknowledged The oldest unacknowledged sequence number Actually, maybe this specifies what we should do So specifically I want um What happens on Segment arrives If the state is listen Sin that's fine Yeah, so this is all the stuff that should be happening in our except Okay, so this is actually kind of handy to read through um Set okay. So this is someone who's trying to connect to us basically set receive.next To be The sequence number plus one. That's what we have IRS is at the seek. That's what we have Any other controller text should be queued for processing later ISS should be selected and a sin segment should be sent of the form Uh Sec is is s act is receive.next which our right takes care of uh Sequence numbers should be ISS which is uh our sequence number is set to send.next and send.next is sent to ISS Uh, and we set both sin and act in the fields Um Then sin.next is send set to plus equals one Which will be true for us because the payload is zero bytes and sin is set. So we add one Uh UNA to ISS And then okay, so self dot Send dot Oh, UNA is already set up here for the sender to ISS great connection state should be sin received great So now we are receiving stuff in the sin received state First check sequence number Okay Oh interesting first check the sequence number So not check acts first Even though the acceptable act check comes first Initial test on arrival There are four cases for acceptability Okay, so This is okay If Yeah, it's fine So I think what we really need to do is just move This check down. So the first thing that should happen is do Uh A sequence number check So that's the check we already have it just that should happen before the act check If an incoming second segment is not Acceptable an acknowledgement should be sent in response Oh, that's interesting So to do if not acceptable Send Uh act After send the act drop it and return So as idealize segment being next does not exit the window Let's find second check the reset bit That we oh, it's not set and then secure in presence which we ignore then check the sin bit Oh interesting. So the order here is really weird Um Yeah, that's an error fine So now check the act field If the act bit is off drop the segment and return What is how do you look for that bit even? Oh I see So down here we're going to do According to this If Not tcph.ac Then return okay, uh, otherwise if we're in sin received Ah, so this check is not even gonna happen Hmm. Yeah, see here. So these states don't check for the Don't do the act number check That's what I thought sneaky. Okay. So if we're in sin received Uh So this is going to be if let this or State Established Is self dot state then we're going to run the act check Right because this is done for Both of these Oh and soon received The check is actually different Interesting Okay, fine. So in sin received we're going to do This If not is between Here we're going to allow this to be wrapping sub one If let this Self dot state so, uh If this then okay The same job is not acceptable for my reset to do reset So that means this check is actually just like Not what we should do Um, all right, so we'll leave that up there and now Uh Processing continue processing mean though, I guess here So now we're going to match on self dot state And if we're in state established Great. So that means that this let's let's deal with this a little bit later So this is the part where we want to close the connection Right, um specifically this means that here It shouldn't be possible for us to be in this state If we're in established Then we're going to make sure that this was a Valid thing for us to get act And then we're going to set that equal to act in great and then There's a bunch of stuff we have to do here That we're not going to do For now Except we are going to assert that Data is empty Sin windows are offset. Yeah, so this is recomputing the window sizes And I guess actually here is what where we want to do this Then we're going to fin and enter fin weight If we're in fin weight In addition to the processing for the established state Oh interesting Okay, so this So I guess this is actually just if let Huh, it's interesting that these are actually sequential as opposed to uh As opposed to doing all of them at once Okay, and now Um We're going to match self dot state if we're in fin one For fin is now acknowledged So if uh self dot Send dot e on a Is equal to self send Iss plus two Yeah, so the reason this check has to be like this is um We want to check that we have an acknowledgement for both the sin that we initially sent and the Uh fin that we sent following it Right, which means that the unacknowledged should be the byte following that Our fin has been act Uh and in that case Oh, this is also if let This is equal to the self dot state Then self dot state is state fin weight two and then up here it's If Fin weight two Then in this state If the retransmission queue is empty the user's clothes can be acknowledged, but do not leak the tcb Okay, that's fine. So we won't actually do anything in the In this case what we will look for is presumably down here Yeah process segment text Uh, so somewhere down here it's going to be like if tcph dot fin Um Then here it really depends on self dot state We're only going to deal with the case where State is fin weight two Uh And in that case We're done with the connection at least in theory And we shouldn't need to send anything more There is the question though of when we send our axe Which I think is going to be basically on time out instead, I think we're going to eagerly act that right here By doing this Where's our right this resets fin great So this is going to put us into time weight Which is a thing that we don't have yet Um Okay, so in theory we now have like a full I think we have a full circle now of Being able to basically set up and tear down a connection There's no data being sent But it it does do the entire sort of handshake protocol Including both set up and close So let's see what happens if we try to oh, that's not too bad compare Wait oh 86 Anything else we're gonna Say is unimplemented Oh I mean, I have no idea whether this actually works, but Let's see what happens if we try to start this Huh Okay, so we're gonna need some logging here But It did get the sin act Oh interesting Why is it resending the sin? That's very interesting That that makes it seem as though We're like doing something wrong Specifically, I wonder whether the Pretty sure that act should be one That's interesting I wonder if we should um try to fire up wire shark here and see what it gives us So if we start this up on 10 zero Okay, and see what This gives us So GCP aha sequence number zero Acknowledgement number zero IPv4 total length exceeds packet length. Oh, okay. Well, that's the first mistake um It looks like The oh the payload size should not include the IP header That is totally true Um, huh, but it sort of has that's awkward Uh Minus self IP header length As you size so the um the reason this is awkward is the The size of the packages cannot exceed buff including the IP header But when we set how large the payload of the IP is it should obviously not include the header um That's fine. So let's run that again and then Restart this Why does wire shark not let me Ah, no this no I think it's confused It's not what I wanted it to do Apparently that's not helpful Huh That is very weird Why is why does starting wire shark bring me to this? wire shark is not running here Okay, let's try that again. So starting this uh watch ton zero And then send a packet And then kill this Okay, so now this is right and here this sent Sequence number zero act number zero here the act number one And send number zero with our sin Huh And it could be the window is too small, but This is an act of the segment of frame two Yeah So that makes it seem like This act is correct But why is it not acting back? See oh we have um Might be that this document can help us here Uh, no that doesn't seem helpful Hmm all the values seem right I mean, I guess it could be that the windows is like too small, but I don't think that should make a difference Also, why is our program not responding to that act like when it gets the sin retransmission I think it should really just respond to that which it's not So that suggests that in here Let's do a good old print debugging Wait what? So it never gets there So when we get a packet Oh, we probably throw it away because we think it's Yeah Okay, so We throw it away. So this is the case where If it's not acceptable when the word is supposed to act Um, so here I guess what we could do is uh What we really want is like, okay True No false This is false. This is false This is false This is true And this is true this can probably be simplified. This is more because I want to see What happens here? Uh If not, okay Then we want to act And then we want to return what we want to do here. We want to do Send out next So I think this is just a right What do I do? All right So let's see if we now start sending those acts Yeah, like it's even recognized them as duplicate acts So why is it not accepting our Is there like a D message for this? I don't think so Huh, I don't know what's going on. I don't know why it's doing that I don't know why it's doing that either um Hmm, it's a very good question. Actually, let's do let's try this first Um, instead of doing this do like Yeah, that's gonna do it back Um A thousand that seems fine And now we're gonna do this to 8,000 on on twos 127 001 And let's look what that looks like Okay So that's what it looks like when you have a real one And this is what it looks like When you're trying to do it to us So what's the difference between these here? Oh, it's the sequence number of the That's what's wrong Right like this needs to point to the first byte that we are sending and the sequence number of the First byte we are sending. Why is that not zero though? Oh the first byte in the payload Oh, that's awful. So that doesn't include the sin I see so that's where we're wrong. Um, so Specifically what should happen is um When we initially do this The sequence number we should include Is actually This Plus one So next up here is This plus one Yeah, let's try that Oh man Let's try that again So watch that and then this No Okay, how's it different this time? Seek is still zero Did I like not save the file? The sequence number is so sent to self dot send dot next Self Send next Iss plus one What am I missing? Why is that still zero? Self dot tcp dot sequence number Is equal to self dot send dot next Check that again Also, why is there seek zero? Like why up here? Oh wait, no No, even in the loop by case It's zero zero one one one So the old behavior was the correct one Question this is like why is this not working? I wonder if this is like The linux kernel Because we are interacting with linux here, right? Like the The kernel is probably Like requiring you to include some of this business and because we're not Specifically it's this like secret value Whatever the secret value is Yeah, apparently not Yeah Something something weird going on here what we're comparing is like this packet Which is what the real server sends To Well, this packet number two. So of course there's a bunch of like more TCP headers that are being set in the other one, but the fundamentals seem to be right Specifically we replied to the correct port To the correct IP address We set seek equals zero ac equals one We set our own window length is zero So what are we missing? Like there are other values here, but they shouldn't matter Oh, it's window scaling like almost positive. It's window scaling specifically I'm just thinking back to This right which says things you must implement um rfc one one two two talks about or is it transport protocols tcp um well known ports push window size urgent pointer TCP options must implement both sending and receiving the maximum segment option Should send to nemesis segment must implement both sending and receiving Yeah How interesting there are also errors in the state diagram Uh, yes, this is indeed using rls Um closing a connection getting a communication This is like congestion control stuff retransmissions managing the window Okay, that's fine Okay, that's probing. This is all None of this is stuff that matters Okay, so it seems like the only thing we're not supporting that this says that we must support is is um maximum segment sizes Ha, okay. There's an alternative explanation here, which is very stupid Uh Which is that we need to compute this I don't think that's the case I mean If that were all that'd be great, but I don't think that's enough That was all What Why did this not give me an error saying the checksum doesn't match Okay so In theory Oh, I forgot to We start the server We monitor it We send this and now Okay, now we correctly get the ac So we act them they act us we send a fin ac Uh No, they send a fin ac. Oh interesting. Why did they send a fin ac? Why aren't we the ones sending the fin ac? Oh wait. No, this just means that Did we send it first? I thought we sent it first They send an ac And they send a fin ac. Okay, so that's not actually something that we Implemented which is specifically If we are in the established state And they send a fin We're established And got stuff And then I sort of want to do something like debug self tcp fin and probably also tcp h dot fin So we never get to that, huh? Wait, this shouldn't be a yes. This shouldn't be a no That's why great Try that again Okay So if we try to listen again now what so Oh Okay, they sent a sin to connect. We sent a sin ac. They send an ac We send a fin and an Ac of nothing They ac are fin They ac are fin and in theory Wait, why is this? Why is anything running on that right now? Let's try that again They send a sin. We send a sin ac. They send an ac. Now the handshake is done Uh, we send a fin ac. They send an ac And then they send a Fin ac that in theory we should respond to But it looks like we do not Or we probably just don't print anything actually is what's going on specifically In this case we enter fin weight and in this case here They've closed No, they've Act our fin And this is They finned to help ourselves with a little bit of Okay, let's see what happens Establishing got stuff So there's something Still something we're missing specifically We're not handling their fin Right so here Is where we end Here is where they act that we finished. Here's where they tell us that they have finished And now we're supposed to act them and yet we're not Um, so the question is why not So we do get a packet there. Are we just like throwing it away? Because that would be unfortunate We're not throwing it away This is the good old print debugging, right? Okay So we got packet and then we did five ones We could did one two three four five So the question is do we go in here? Well, we didn't do this So this suggests that fin is not set In the packet we got from them Although that seems odd because wasn't that the whole point? Oh, that's that act. Oh, I see This is just dealing with their act But then the question is why are we not getting Why are we not getting this fin? In fact, isn't this wrong? Why shouldn't they be acknowledging too? But regardless Why aren't we seeing the packet because we're also not crashing So So what's going on here? Oh Okay, so here I just turned off Um, here I just like terminated, um The sender and then we did indeed get true And then we panicked at 315 Because we weren't in finway two How are we not In finway two though I sort of want to compare this and this Because it seems like we're not doing that correctly So if we do this What do we get? We get We basically only receive two packets. Okay, so what are those two packets? The first packet we got was This one. I don't think that's wait. That's here. It's just confused. Let's try that again Okay, so we got two packets We got this packet and this packet. Both of them do not have fin So the first packet is this one The second packet is this one And it's true that this is not hacking our fin But why are we not receiving this packet? When we send this we should still be receiving that But it's as if we just never get that packet And in fact it's sent again later And we still don't receive it Yeah, I don't know why we don't receive that one I mean the only thing I can think of is that main is dropping it, but we could try Seems a little odd Yeah, see there's no no packet is being ignored And so we're just not getting We're not getting This packet. I don't know why Like we're not receiving it all after we send this We don't receive anything There's no error either What does work though is if I If I connect and then I sort of terminate that connection intentionally Then Then we get a packet with true That's very weird I don't have a good answer for that Here we do get a fin packet though. Okay, so Here what I'm doing is I'm starting it and then I'm pressing control D Which immediately terminates the input Um, and so at this point you'll see What wait did I not start that I thought I did So if I do this It's gonna do a bunch of stuff And then it crashes This act we don't get and the fin act we don't get Or rather Yeah We don't get either of those see we get one Ah We get one two We get two packets before this Unexpected one which is a A nice the version six packet and then we get one packet Which means we get one two And then we don't get either of these but then we get this one I don't know why we're not getting these in between. Oh to 8,000 So that's an old one Huh. Oh, I wonder whether this is just like old left over stuff Like if I now do Like 9001 just to show the ports are different If I do this Wait for one of those And then exit this No, there's still this packet really should be getting through Although it does it does sort of go through here, I guess um But I don't know if that's the same Let's print out what it is the Um th dot sequence number No, that's sec x tcph dot acknowledgement number Yeah, so we're expecting to see Three packets one two three Uh with seek one one Zero one one and act one two What does it actually get? It gets That's not a sequence number of zero I think this is like adjusting sequence numbers, which is not okay Uh This acts two so that acts are sin No acts one acts are sin x Two Should act our fin So this seems like Down here UNA should be set to two at that point So why is it not? We're establishing god stuff that x1 So the question is this packet This packet right here acts two. We're never keeping track of the fact that we act that packet Even though We should be in the established state I know why it's because we It's because we immediately try to terminate the connection Right down here. We're immediately changing away from the established phase and we're not doing this processing Even if you are in the finalized staged So this should be state fin weight one or state fin weight two And then we sort of only want this if let state a stab is self Without state because this is sort of hacky this part down here. I try this on for size Great. So now we realize that they've act our fin And so now when this terminates They've act our fin. Okay, we didn't crash So that's good. What happened here Um, we sent the fin act They act that Then they sent us a fin act Which we eventually act Nice So now that connection has gone away and we've gone full circle. We've sort of fully established the connection and torn it down Right, like there's no there's a tzb retransmission in here, which I don't know why Things like for whatever reason we didn't act the first one Um Now, okay, so I think we're gonna stop there for today Um, let me get rid of these like e prints and stuff I still a question of why we never got there, but okay Um I think we're gonna stop there because now we have Like a thing that can talk to a tcp client. It doesn't actually exchange any data yet Which I assume then is going to be what we'll cover in the in the next stream um because then we'll need to do with deal with like Retransmit queues and uh and timeouts for sending acts We'll need to deal with congestion control and window sizing But at least now we have sort of the basic setup working where we can we can at least talk the protocol and handle the Handle the appropriate messages and send the appropriate messages and sort of see that everything goes through um I will I guess I'll push this there's no reason really not to Um, let's do The learning Implementing tcp and rust Great like so And then we'll do I guess we will do Um, so remote add origin this Nice, okay, so in theory all the code should be up there if you want to take a look um Okay, so what we're going to do is uh end the stream here Because it's sort of a good breaking point where we have we have sort of one cycle of a tcp connection working And then we can cover sort of data management and congestion control And all of that stuff in the next stream um I think the next stream will be in about Maybe in about three weeks. It's a little hard to say um But the plan is to keep going on this um as you as you can see from implementing as well There's like a lot of stuff to cover here And a tcp stack is like a non trivial effort that we're doing so my guess is this will end up being three streams before we get to something Uh, I already have the key ssh added, but I have it auto expire. I don't like having key material in my memory um Yeah, there's a lot of cover. So my guess is that we'll go through probably three streams on this um Unless like unless either we get really far the next stream or people complain. They don't want to see any more about it But in either case, uh, my guess would be about three streams And as always if you want to vote on upcoming stream ideas, uh, there's a site where you can vote Um, this is how we ended up doing tcp in the first place Currently the sort of next comer is uh to do another open source contribution stream, which was really fun um And but that will then be not for quite some time because we we still want to make some more Headway on implementing tcp before we sort of leave that behind Um, so in that case, I guess thanks for watching everyone and I will see you next time Bye everyone