 Okay, so thank you really for coming here We'll talk about network today because it's a topic that's been a bit obsessing for me And I'll show you like what I've been doing for the past three five years So I'm sure for I do cloud stuff. We host your applications at clever cloud and Hosting all of that stuff means that I have to mess with protocols and HTTP and proxies and stuff And I had to get a bit far in rust networking So this is a topic that's been very big in the rust community for the past years. What's a sync networking? Why do we care? Can't we just Think of network in a blocking way like I Create a connection somewhere or listen to something and my code is blocking until I get the connection of the data And it's very easy very nice to think about And this is what a lot of platforms want you to do The thing is if you do that in rust blocking network, it's not good for performance That's that's been a problem. That's been annoying people for I Don't know what when the seat and K problem appeared the idea was like, okay We have blocking servers everywhere So we have for every connection We need to have a new thread or a new process to handle them and then the servers got overloaded and So performance was not great and someone said, okay, we need a way to accept 10,000 concurrent connections How do we do that? So we needed another way to think about networking and the thing is network is not blocking That's not how the operating system works Packets can come here and go there and all the time and what your process is is just a nice view That the operating system is doing to help you do networking, but basically Anything can happen at any time on the network so What happens in fact? You have the OS that receives packets like imagine you want to accept TCP connection You have a function to say I want to accept one You're not like getting waiting for a connection there. What happened is like someone did a TCP and shake with your server and the the kernel Handled the handshake and then put the connection in a queue somewhere and when you do accept you get something from that queue So already when you're accepting a connection a lot of stuff happened before you even took a look at it And then when you want to read data from the socket well you're not waiting for data to happen there basically the operating system received a packet and Passed it and put that in a buffer somewhere and when you do a read on the socket you get the data from the buffer So the data was already there for a long time ago and when you write to the socket You know it's not already going to the network it goes into a buffer and then the operating system say okay I give that to the network at some point and the packet will will go So whatever you think you do in networking the operating system is scheduling itself I'm choosing when it does whatever and you're not in control of anything The blocking the nice blocking interface is actually a lie a very nice lie that we want to believe but it's a lie it's not how it works and When people wanted to get to like the 10,000 Concurrent connection problem. They had to get to remove the subtraction and get a bit lower So that's where Eventidio came The idea was that you could register a socket to the operating system and say okay I want you to tell me when I can read or write on a socket There's a specific error code on socket like when you want to read data You can read and read and read and read at some point the operating system says it says wood block Which means okay? I have no more data to give you you have to wait for the next event when I tell you there's data and You on you handle your own scheduling and what you do with the socket yourself This is what's been done to get like fast web servers like this is what you can find in engine X and in almost any language runtime ever because it's It's a bit hard to do but you get like good performance and you handle like the scheduling yourself So how we can do the first method was that To have an asynchronous you are you in your system like you do the people calls So what I was describing you wait on events and then you will read or write for two sockets This is a bit what I will present that has been this is what I've been doing in Rust for for some time Some languages will give you a good nice interface. So you will recognize this as some go and Go as this concept of grouting and like it's it always appears appears blocking But you know that it will have really actually do a lot of stuff another hood to schedule you and Call you back when there's data call you back to where there's a connection So it makes the code easier to write, but you still Profit from the yes, I think we're working and what's good in the system like that is that the language runtime Gives you Complete abstraction you do not have to think about what's inside the system But you get still the benefits of async networking There's the another approach we've called wax Not just works a bit the same way as going on that but instead of Having blocking code where you call something and then the code will be just stopped say you last somewhere and Executes it starts executing again when there's something Now you receive a call back that will be that you call when you have something to do on this and you give a Function that will be called when there's data, etc. It's It's At the same time easy to understand and make the workflow a bit hard to follow. So they went to an async await flavor Of course, there's the way we do that in Rust with futures and combinator The interesting thing I see with futures is that it's not you call the incoming function on listener and then it will It will wait no it calls incoming and then map and then for each etc etc and builds a structure of something that will do some networking at some point and That structure has a poll method and we call that poll method and it will go through all of the state that were built before So the server stuff has been built right away, and then it will we recall the poll method on that It's a bit annoying to write You have to move stuff around you have to Actually put stuff into mutex's It was better knowing to to share states. So There's been a lot of work to get to better syntax by reusing the same future system in an async await syntax by adding by using the await keyword to do Basically what we were doing in go there So This will be good This will be nice to use once they agree on a syntax There's a lot of problems with futures To to refer I'm known for having criticized futures a lot. I love them I use them a lot But we I will not shy away from the problems they have and what pisses me off when I working with them I'm what I want to fix So the first thing is I told you it when you create the features it makes A structure that implements Paul, but any steps inside your protocol are a structure that implements Paul So when you have a stack trace you have Paul Paul and Paul Where am I doing what I? Don't know you can try to add functions inside of basically it's it's a bit annoying to today back It's a hard to test This is some code. I've been taking from trust dealers, which is a very great project by the way the very great DNS implementation and They went away where they are they create complete mock of a name server to test the client So you have to have something that? implements a server over TCP or UDP for your tests It's I had to do that for some HTTP stuff and it's it it makes the test very non-deterministic and very hard to Reproduce bugs, so it's annoying and And finally the typing issue so Assuming you have your so you if you know like the impulse future Impulse rate features says Okay, instead of returning the entire type I will say it's something that implements future and I let the compiler like replace impulse future by the real real type so if you have two functions that return impulse future of you 42 a number When you see the code You say okay, they return the same type. That's what you will think but no They can be completely different type because one of them as a map somewhere and the other does not So the the function that says both when you want to call one of the function in one case or the other in a case It will not compile because both functions have different written types This is annoying a Worst one is a very simple case I often have to do is okay if there's some condition I return a static value or something I've pre-computed at some point so Result, okay, it implements future. So it's it should work But no, it's not the same type as so gone. So I have to ever box the stuff or do over jump through hoops to fix the typing issues and This is not hard. It's not just something I have to think about every time I do branching in the future It's it's a it's annoying so what happens is like They would they want you Futures want you to think in terms of blocking IO like you do this and then that and then that and it's very imperative And it's very nice But the way they're done match a lot on I think I think networking And so you have to think about the I think that working under that like when you debug a future You have to think okay Where did I get the readable event for this socket that triggers this over one to execute that function? It's it can be a mess to the bug especially when you're doing low-level development and protocols I really like features for high-level stuff when I like create a HTTP server using HTTP library And then I do a call to database somewhere that kind of thing and that that can work very nicely But at a lower level Not so not so much So with that I Want to implement network protocols because it's a large part of my work I have some criterion It must be easy to test like having to set up Server and TCP and DNS and stuff to test anything is a no go. I want my test to be deterministic. I Want my code to be reusable so Futures are nice But you cannot use a future's best protocol outside of first I have protocol implementation I had to use like in over platforms and share between platforms How can I do that? And how can I make it so that it's not tied to a specific way to do IO because when I started to to work in the approach I will present like it was 2014 like in 2015 something like that like the features appeared and Said okay, everybody moved to that and I tried and say okay I want to support that but I would keep my way there because I want to to be flexible on that So where does it come from I? Walk on HTTP, which is nightmare protocol For reverse proxy at the clever cloud. It's nice. It's I encourage you to go look at so zoo It's HTTP reverse proxy that can reconfigure itself at runtime and its main for load balancing and performance It's a really nice project and there's lots of fun stuff to do that Uh La pa the amqp library a mqp is even more of a nightmare to implement is one of the worst protocol I've seen like everything is in there everything and This when I started to implement lava it was impossible to do that with features in 2015 now it might be possible There are other stuff like the messaging protocol in iOS and read I wanted to have Same implementation for both platforms So I did that in rust and so this mob is be called from see and from GNI and you have to be flexible on how it works and of course There's the song I you movement that appeared in Python. Well, they They had the same needs the same approach because there was already a single-weight debate in that community to People had opinions and some say okay We want to do network protocols, but we don't want them to be tired about IO because Network protocol is not about input output. I'm talking talking to a network card it's just such state machine that Ingest messages gives you messages and updates its state and you can query that Like you can simulate an entire protocol without doing network IO and you should It's not a framework You want so often you would you want to do like Like the thing you see like in a HTTP framework when when you just provide The framework requires that you provide a trait and the framework will call you and say okay This is a request. Tell me how you want to respond so that we handle the rest but like This is a low-level component the low-level component. You should not drive my application I am in control of my application and so I will tell the low-level component. Okay now do some work and Tell me where you are and now I will do something else and I will make a nice layer about that But inverting the control like that it makes everything if everything hard to program so No, I owe means you can be deterministic you can make Something that's easy to test you try one input. It should always give you the same output This is what you want in you in a unit test basically There are still some details about measuring time and Generation but this this is a this are part that are easy to book so We can make a program implementation. That's better to debug and the last thing They can be represented as code or data When you see the implementation we had in the different languages, they were just code So I call something and then I call something else and then it's In features it generates a state machine It generates structure that contain each other and call each other's pole method It's a way to represent state machines And set machine that can be represented as data can be stored so you can handle multiple clients at the same point and You can just create a structure like create a state Like at yeah, whatever state you want and okay, I want to go from there I want to send a message and see what happens Representing a state machine as just data makes makes it easy to serialize me exit easy to test so sum up I Want to represent a protocol state machine that just text message I Want a way to move this message back and forth with the network IO and with buffers and I want to separate the IO layer because The IO layer is the responsibility of my application the protocol should not decide okay How many HTTP clients can I handle concurrently? The HTTP implementation that does not decide that it just handles one client. This is the The application over that that says okay, so if I have this many Clients I have to have another trend to handle them And lastly How most protocol are specified is with state machines This is from HTTP to HTTP to is a very nicely designed protocol and the complete mess as well because there's Multiplexing you can have multiple streams in the same connection and they have flow control So you can have one stream that's stopped by either the client or the server while overs are running And you have to handle all the state like that. It's it's really nice nice to do I have to do one implementation at some point and you see that it's just you have states and you have message and The state machine specifies okay when you in that states here are the messages you accept And where you can go from there if you have one of those messages So it should be simple to implement you make an NM with all the states You have some structure to for the messages and you make an interface where okay? I give you a message where we were going from there So as an example, this is something I have in so zoo So zoo wants to be very very smart about performance and how to under HTTP So it tries to do stuff with the HTTP connection before having passed the whole connection Because we receive like some very weird traffic where like one header could be larger than a whole buffer that kind of thing So I have a series of states like I start my HP parsing. I don't have anything Okay, I'll try to pass a request line and get into the request line state He's small car for that if I'm I pass the request line I'm passing the headers and now I'm waiting for Header messages. Okay. If I got a host a host error. I get into the as host State where I have a request line and the host string I Care mainly about the host and the length information the content length error. There are there are a few more steps But I will not show them then I will not show them today And then you can get into three different states at the end So ever it was you had no content length and you have just a request without body You can have a content length with a size and Do you know you have a body of a specific size or it will just take tell you chunked And then you have to have another state machine to handle the chunks of HTTP so This should already be simple, but we already have quite some number of state How do I build something above that I want to handle a new message and Get into a new stage from that and maybe when I get into a new state I might have a message to send on over the network So not really with HTTP there, but like a MQP when you start connecting to a server You say okay I want to connect and now there's a set of request replies that start from server So you the client says hello and then the server asks a question the client for answers for like 11 steps, I guess something like that So They have to have a way to just send stuff and it's not the only request response The second machine should also have a way to indicate the earlier how to behave like okay Maybe I'm receiving a lot of data on that on this socket, but I don't want to read data from this socket So I will just tell okay. No. I want to read data. No, I don't and maybe if the earlier says Sees that there's too much are you coming and we don't want to read anything It would just drop the connection because there's something that's wrong with the protocol. We can do something like that and We might want to pass messages depending on the state we are we are in so the state machines does something that we create Do you want to read? Do you want to write something to the network? I have data. How should I pass that? Okay, that gave me a message. What do you want to do with that message? Do you have something to give me to send the network now? It's just a small thing that you ask and it answers and From the nm I have there I can implement a method That will do a lot of pattern matching because we have lots of states and say okay I got a request line if you are in the initial state you go to the house request line state Otherwise if you were in another state, it's an error You should not try to recover anything because there was an error in the protocol. You stop there. I Have the parse method that says okay if I have if I am in the initial state The parser I will try is the request line parser otherwise it was it will be the header parser She's over there. So Lots of pattern machine. It's a bit annoying to write. I have I have to stop for that afterwards. I will show you You can make methods over the state machine to query its state like hey, do you have a host? Like I want to open a connection to the back end I have to know which server which name you were trying to connect to so do you have a host? Okay, so if you were in as host or as host on land or any of the request Types you can go and say okay. I have a host now. I can open a connection to that server Do you want to read? Well? in most cases Yep except I got a full request or I got a request with a body and there's no more remaining data or I got a request with chunks and There are no more chunks to read And this means that after that I would probably have to to read from the the back end So as you can see it's a bit annoying to write all of those pattern machines and these nm's and stuff and unwrapping stuff from the nm So I built a small crate. That's called machine Like when I started rust I wanted to build that this awesome state machine Create that will allow you to write a statistic machine that will never get into an error state and Then I left that for years rotting somewhere because when you write a protocol you're not deciding Who which message will go to this to your state machine? It's a runtime property So you can get any crap sent to your state machine at any point So you have to have something that's a bit dynamic and so that's why I built a new one That will generate code that matches that kind of programming So here I specified The the same states what they will contain So there are few states few types of all like the length info the length information can be okay There's a length needs a number or it's trying This will generate code that looks like that an enum with some structure If you want you can add some derived attributes and they will appear on the enum and all on all the structures some helper methods Or I fixed something yesterday now it's snake case there So with this you can just start in the state you want So I want to be in a state where I already have a host so I create one And then from there you already have a lot of things to to use but you want to specify transitions So I have another procedural macro for that where I specify The first state the message and the outside state And I can even For some part from some transition I can have multiple outside states because sometimes there are still conditions Inside the message like if this value is that I want to be in that state if this value is that I want to be in That one and it's easier to do in a method that Generating like 10 more states for that And this generates a method that will do all of the pattern matching you want And now you what you only need to do is implement the like the own request line on the initial state structure So all of the boilerplate To write set machines is done and we only had to under like okay. I'm in that state I got this message. I'm supposed to get so what do I do and This is a very nice way to see oh All my states are okay because I know I can only get to that one if I got that message on everything else go into a Neural state that's been added automatically And to make things nicer it can generate the graph you saw just earlier This is very nice to debug because okay. I want to write my transition I want to see where do I go from there and oh wait, I'm missing a state Why or how can I get into the other state at this point? Oh, I'm trying am I trying to recover from the arrow state should I really do that can go a bit far with that You can also generate some helper methods so as you can see in The specification a few of them have the other host member And maybe I want to get to have an accessor for that so we'll do I Recreate that and it will create me to create the host method on the state machine and on each of the Required states and return me known if it's not a state that has that so with that it gets a bit easier to write a protocol It's also very easy to unit test. I Can start in the as host state And I send the lent header. Okay. I know I'm in the as host and lent state Oh, what happened? What happens when I send another host say host message after that? Well, I get an error. I think there was some case where you could get two host headers in HTTP and Some server where we're accepting that and this is a bad idea So you have to make to go into an error state with that So we already have like a lot of tooling to build protocols and but it's still very abstract Like we suddenly the state machine. How do we talk to the rest of the IO? Well, there are First we have to have a way to interact with data. We have to to find I Have a buffer. I want to make to make a strict on message from that. I have a message. I want to write that to a buffer The thing is We don't know how much data has been sent or not by the network You could have someone that's very not nice and sends you the HTTP request One character by one character by one character You could have someone that sends a cookie header. That's like one megabyte This happens a lot. So We need some tooling to to handle partial data so Passer that could work with Let's say, okay This is not invalid because I know there can be more data and I'm waiting for you to read more data And you need to have the same way on the right side and say, okay I will try to write and if there was not enough room I will write the rest later. You need to handle some state of it out. So on the passing side Hi, I built none. This is a nice parcel combinator library that's based on macros And with this you can be like very fast very simple parsers So this is the one to pass the request line so we try to pass the method the url I the version and If like if you only got like the the method and the url I and nothing else it would just say Okay, I've written the result I return is incomplete. I need more data But if there's even a small asteroid we say, okay now you have to stop This was invalid message you you have to stop with that So now he's able to walk in string to walk in with partial data and really helps with that type of programming On the right side, there's the cookie factory crate which Which lets you Build a set machine. So you see it's it's a bit like the futures. I got inspiration from the The futures combinator I build a machine that we try to write and If you stop like, okay, there was not enough data to write the old you are the whole you are I Okay, we just have to call that structure later and say, okay, man. No, you can write So this will handle partial data correctly. So from there Out how do we interact with the world? We have a very nice protocol. That's very nicely Stored inside in state machines. So now we have to talk to the rest of the world. So The the calling application will just call methods that say, okay, I Want you to pass HTTP requests? I want you to connect to MQP server. I want you to create a channel Then send some message on it. So you need to have methods the method will trigger a state change We'll trigger the message sent over the network or waiting for message from the network and Then you let the IO Implementation run until something happens This is this is what happens in any network protocol implementation Most of the time we don't see it because this is the lower level and the annoying part And this is about we want to make nice and once we get into the correct state We can query that and say okay. Are you in the state? I want and you have the data I want if not continue with the event loop continue doing IO and I will carry you back later So the first the easiest way is you can use those protocol in a synchronous way in a blocking way Just have to have a loop that says, okay read from the socket. Okay now try to pass that Send the message to the the state. I am in the right state. No, so then I have to read again It works in sequence ways If you let me and want to have a bit of pain build your own event loop So there's this very very nice library. That's called my oh for metal IO. That's at the heart of most Asinct networking implementation is gross like Tokyo and everything is based on my oh My oh is a thin wrapper above people and KQ to handle Events the way you build that is you wait for the OS to tell you, okay What are the events for each of the sockets I handle? You get an event Okay, I have this token this corresponds to this client this session I Got a readiness the readiness tells me this socket is readable. This socket is writable There was a narrow in that toast in that socket and it's been disconnected, etc You look at how it's a bit larger But like you look at what you were waiting for like the interest. So maybe I want a socket that's readable Maybe I have data to write. So I want to get that's writable. So you match both of them And you you see okay, so if The socket is readable. I want a socket that's readable. I will read from the network Okay, that means now I have more messages to send us to the state machine. I have to run my states My event loop until there's nothing nothing more to do And then from there, okay, I run all of all of the messages. Maybe I have something to write to the network Can I write to the network? If I can yes, I will So this is Full of easy mistakes, but it's still a very nice way to program network because you're in control of everything So I'm writing a lot of boilerplate around that and we'll probably should publish at some point some guidelines on how to write that But I encourage you to look at how it's done and hood. That's like that's how people have been building C servers for a while So There's no reason we can do that interest There's the callback way where we can't get an event loop like that and we have Callbacks that we put on that callbacks and closures and stuff are a bit hard to To store in rust so this might be not be the easiest way to write that but the good news is We can make features around what I just show So you can build a future like the the future trade It gives you it requires a pole Pole method pole method is just okay. Do you have something to do? Do you are you in the the right state to give you to give me the data? I want etc and the state machine will say maybe I have something to give you or may know I'm not in the right state yet So you can just wrap a state machine like that and build your own future system and this is what I did with lapin because I Made this this implementation. That's asynchronous that that's very deterministic and then there's a future a future rapper that's very nice to use because You don't see all of the lower level details So this is called I got from lapin. That's a bit hard to follow maybe but the idea is okay I want to create a queue so I will Call the state machine and say queue declare This will this will create a message that will be put in the output queue and At some point will be returned by the the event loop and then I pull one function And every time I say okay No, are you in the right state for what I want like if you are in the if you got the queue If the server answered and told you okay the queue exists now I can return otherwise continue on the Parse side That's a very nice way we've took you we've took you I you to do that It's called the transport and you build a structure that has a Decoder and the decoder will get past some data here and there and You use your non-passer on that data and it will tell you okay I consume this much data you can remove this much from the buffer and It gives the the message is that to your state machine afterwards So it's it's a bit of work, but you can make a very nice protocol implementation That's as introduced that can be used in C that in C and all the new language That's testable That can be used with me oh if you choose with everything you want That's a real pain to write honestly. I would like to want to write high-level code But for what I want this is a bit easier If you have higher higher level application write them with a sinker wait with futures If you have low-level protocols and stuff do that This is this is this will be a bit better and so This was a bit annoying until a few weeks months ago, but now we have No, we have cookie factory and we have the machine crate So we have the whole set of tools to do that and if you go look at the rust bakery Or guys they get up organization You will see like I will accumulate a lot of projects around protocols and none that will help you Write what you want because there are lots of things you can do with parcels I'm all for giving people tools to write what they want safely and fast All right So thank you. I will people You can clap if you want Any questions She said what about performance with DP DK DP DK the I hope as through for the canal was right. Hello. How you tried DP DK? Okay, so I have a try DP DK DP DK is a way to have your packets Send directly from the network card to use alone instead of letting the the OS past them So I did not but someone has built IP TCP and whatever Passes for that and I know someone is doing like very low-level IO with norm And it's not at any liberty to tell which company and which kind of product they are doing But I know it exists. Can I write level two protocols? I can write protocol at almost any level I can handle bit stream passing I can add regex in that I can tokenize a language It's not the nicest library known for the form to pass a programming language But for most all of the file storage or network formats, it's very good, especially in binary protocols Okay, so question. There's an implementation of quick That's actually to this Quaring and quish I guess which Funny thing is like the way the one that from proper which is kish. I Don't remember which one. So Cloudflare did one one implementation of the quick protocol, which is low level UDP based increased protocol that could be used for the next HTTP More or less and they did an implementation like what I presented because I thought fair They want their protocol implementation to be able to be called from C code or Lua or whatever they're doing. So Maybe I'll do a quick implementation at some point Not any time soon. I'm quite busy, but the protocol looks nice. Yeah, it's interesting What's the level of maturity of the machine crate? Not much. I released that last week. I Was still patching it yesterday but What I've presented I've been doing the state machine manually for years So I know I it's annoying. It's long, but you can do that and it works Now that I have the machine crate I can't believe I did that manually because it's much much much easier and I did more and more features like I have methods I can add a tag to say okay implement for all those states You have to implement the method and for all those others. He's he's the default value you can give there are lots of Interesting stuff I can want. I want to do that with that Anyone okay. Thank you