 Rock and roll. Cool. Okay, so I see a lot of good discussions on the Discord. Seems that people are working on things. Are you all working on things? You should say yes, you're working on things. The next question is are you working on things for this class in this assignment group? Also yes, cool. Awesome. That is excellent. So, cool. So we talked, yes? Not yesterday. We talked Monday on how to make connections. So, somebody refresh our memory. How do we accept as a server TCPIP network connections? Okay, so what are the steps and what do they mean? I mean, the steps are on this thing, but okay. What do they mean? So when I do a socket, what's that doing? Say it again? Getting the file of the script. Getting me a file of the script or of what? Not of the server I'm connected to yet. What is it? So the very first socket call. What's the points of that? Haven't a connection yet. There's no connections happening here. Yeah, we're kind of, we're telling that, yeah, it's almost like step zero. We haven't actually started a connection. We can't accept anything coming in, but we're telling the operating system that we're gonna want to make a connection. What else are we telling the operating system through this socket call? What was it? Not yet read data, because we haven't even listened. There's nothing to read. Yeah. That's an internet socket. That's an internet socket. Yeah, there's many types of sockets. So is it an IPv4 type of socket? Is it an IPv6 socket? That's these arguments here. The second argument was what type of communication is it? Is it a string-based communication or a packet-based communication? And finally, some other options here at the end. So we're just telling the operating system, hey, we need a socket. And actually, I mean, we're not gonna go into it here, but we saw that when you read and write from a socket, if a socket is non-blocking, it'll return immediately with an error code. So you can then, with this file descriptor, set options on this socket to do various things. But as we call socket, we get back a file descriptor, and now we can do call bind. What does bind do? It close, yeah. It's getting us ready to accept connections. But what specifically are we telling it here? Yeah, so it gives it kind of, you can think of it like that, that's pretty good. Yeah, it's kind of like an address. So it's saying like, okay, well, you want a socket. What IP address and what port do you want to listen on? So in this case, it's saying, well, we're telling the operating system, hey, with this socket that you just created for me, I want you to listen on port 80 and four connections from address here, 0, 0, 0, 0. And then, if that's successful, if that port is open, yeah. Have you posted these specific slides? I may not have put them in the syllabus, but they're under, if you go to the module, I think I added them, because I also had the recordings of these videos under the module as well, and I think the slides are directly there too. But yeah, if you send me a, you can DM me on Discord, I'll remember to do it after class. Yeah. Thanks. Cool. Okay, so at this point, we've created a socket, we've told the operating system, hey, for this socket, I want to listen on port 80. And if that is successful, meaning nobody else is listening on port 80 or trying to listen, it will return zero, it'll return zero. If it's not successful, it'll probably return negative one. We passed that. Then we call listen. What argument do we pass to listen for the first argument? Does three mean I want to listen for three times? What's the argument for? Okay. What socket? Yeah, so what socket we want to listen, we're still not there yet, we're almost there. We've told the operating system our intention. So I believe at this point, it will be, I wanted to listen. Say it again? I think the listening command tells the OSC wants to listen there. Yeah, I think that means to start listening. So by and we've bound to an address and listen means hey, start listening for incoming connections. And at this point, we are ready and anyone else can make a TCP connection to our machine port 80. And then if that happens, then when we call accept and we pass in that socket, this then we were asking the operating system, hey, when you have a new connection on this socket, so on this listening on this port, then tell me and what does it return to us? Yeah. Oh, no, I was just gonna ask. No, you have to tell me now. Just kidding, go ahead to answer your question. Yeah, so these refer to the same socket because we can actually have, we don't have to have just one port. We can have as many sockets as we want listening on different ports. We can listen on port 80 and actually a web server will typically listen on port 80 for HTTP traffic. And you remember what the HTTPS port was? It's the more secure version of HTTP. Yeah, what's the port? 443. So a web server when it spins up actually creates two different sockets, binds to each of those ports. And so it has to call listen and accept on both of them. So it has to keep track of those things so it can tell the operating system. Then it has to figure out, I think it actually uses a different thing than accept. There's different things, I think like pull where you can give it multiple file descriptors and it will return other file descriptors when it's ready. But anyway, we don't have to get there right now. But yeah, this allows a process to listen on as many ports as it wants. So that's the point of specifying this. And this is our way of telling the operating system, this is the exact socket I want you to listen to. It's the same thing that I created so it knows what type it is. It's the same thing that we bound to so it's bound to that port and that's the exact one I want you to listen to. You can start accepting connections on it. Then answer your question. A little bit. So three is the server we're trying to listen to? No, it's the return value of the first socket call. Oh, right. Cause we're the server. And then zero means what? Zero means no problem, everything's good. Oh. Yeah, except for accept, which returns a new file descriptor that we can then read and write from because that is our connection to the other side. And I completely forgot the original question I was asking when I accidentally called on you. Yeah, do you remember? Good question. How do we know? So I guess a better question is how did this value three get from here to this first argument to bind? Writing the assembly code for this. Yeah, so after we call syscall to call socket, the RAX register will have the value three. We don't actually know that it's three so we don't want to hard code this. We'll just store that in some other register and then we'll pass it as an argument to the following functions. Yeah, so you can think of that as like a local variable. So if you're writing this in C code, you got some int called file descriptor and you'd say fd equals socket call and then later you call bind on fd so you're passing an argument of the time. From accept like a file descriptor? Yes, exactly. The four from accept is file descriptor which means now that we've set up, we've listened, somebody wants to finally talk to us after all this long time and all this long setup. Now we need to understand what they're saying, right? So we're a server, usually that means we want to, somebody is asking us for something so we want to read the response from them and that's what we do with this file descriptor return from accept. If you want to get super technical about it, because of the way these file descriptors are created and the Unix, I think it's a Unix level, it guarantees that it will always return the lower most file descriptor that's free. So when you call socket, if you haven't done anything else beforehand, it will always be three and then when you call accept, it will always be four but you shouldn't count on that, that's not good programming, right? Hard coding things? Yes, bad hard coding things. All right, and this is at the point, yeah. You like hard coding things, it looks like. Yes, we can have not only, so even in this example there's actually two sockets open, there's the socket that we're listening on, FD3, and then there's the file descriptor which is a socket that accept returns and that is the connection that we have to that other side. So when we read and write, we are reading and writing from a remote and like to a remote connection. Go ahead. As many as we want and you could find, you could, because we're not gonna get into it here but to make a connection, you also need to create a socket and then there's another function you call to connect to a specific IP address and port. So we may have a socket that we're listening on, we may take in a request, depending on what that request is, we may actually create a new socket to make a connection to some other machine, get data and then respond back. We may be listening on multiple ports and it's only when we get connections on both of those that we start reading and writing from there, we can do all kinds of crazy complex stuff. Yes, the idea is like walking through these basics here and these are the building blocks that you can use to do these more complicated things. Yeah, more questions. Oh, do I realize that my OBS is covering the slides? No, I do not, why is it doing that? Okay, so you all are seeing this not move, right? Like I move this, the thing in here should move. Computers are great, that's what they're not. All right, how about now, recording? There we go, okay, now I can see it's working. Okay, excellent, excellent, okay. Cool, well everything that we talked about is on the slide which we saw on Monday, so refer to that, I guess, for this part. Okay, so now that we've done this, we've done all this work, we've made a connection, somebody's finally trying to talk to us. So who's sending this HTTP request? Yeah, whoever's talking to us, we don't know, but if we're writing an HTTP server, then we can assume and we can expect that somebody is sending us an HTTP request. Are you familiar with HTTP requests? Instantly, deeply, painfully, why? Yeah, the first module, you have to do all these requests. Now you're on the other side, you have to parse somebody else's request and manage it correctly. Cool, so this is what if we're writing a web server, which we are, as soon as we get an accept, we want to say, okay, let's read in that data from that other side that they're sending to us so we can properly respond to this request. Now, what does the other side expect us to send back? Can we just send back gibberish? Can we just send back Hello World? In what way, yes. How do we give them what they requested? We send it back. What protocol are we using? An HTTP and we're specifically doing an HTTP, what? Response, right? Somebody makes an HTTP request, we send back an HTTP response. You can look at the syntax of this online or in the slides, right? We talked about this when we talked about the web basics. So they're expecting an HTTP response. Now, depending on what our server does, maybe we just say everything was great and we send back a static HTTP reply. Response reply, yeah, okay. So, we have a file descriptor four. We now want to write some HTTP reply and write out on file descriptor four. So what's this string? HTTP slash 1.0, space 200, space okay. What's this part of the HTTP response? Response line and the status line, I think. But yeah, essentially you can think of it as the header, right? It's the start of the message. The first thing tells you what version of HTTP you're talking and then, so what is the slash r slash n slash r slash n mean? Somebody raised their hand. Two new lines and what does that signify in HTTP? Exactly, the start of the body, what is our body? Nothing, it's empty, right? So we're just sending it back an HTTP 200 response, right? This is the status code, we're talking about the status code as responses. 200 means, yep, this is okay. Normally the server, the client would expect whatever they requested for in the body. Here we're sending them an empty body of nothing, but they should say that yes, this is a valid HTTP. I talked to a valid HTTP server that is actually talking HTTP back to me. We can then close the socket and once we do this, the operating system terminates the connection and tells the client, thank you, that was great, I'm done talking to you. And then at this point the client interprets our response. Ah, great, what's the 19 for? So what's the third argument to write? How many, yeah, exactly, how many bytes to write? So the 19 is specifically, I think if we counted this up, it should be exactly 19 characters there. Let's see, one, two, three, four, five, six, seven, eight, nine, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19. How come I counted the slash n as one character instead of two? It's an escaped character, yes. So the character that gets sent is slash r slash n, whatever you can look that up and ask you if exactly what that value is. So we wanna be very careful when we're doing this that the number of bytes that we're sending is exactly what it should be and what we think that it is. It is the status line of the HTTP response. It is similar to a header. So this first part, it's three things. The HTTP version separated by a space followed by the response code separated by a short status code message, which I think is technically ignored. I don't think anyone looks at this part. And now we built an HTTP server. Literally, this is it. You're a valid HTTP server. Any web browser that's ever been written can talk to your server. You can use Netcat. You can use what other nice tools? Curl, what else? The Python request library. You could use your browser. You could use your phones browser. You could use links, a graphical terminal browser. You could use all kinds of crazy stuff. You could actually use the original web browser written for the Next Step operating system for 1993. You could use that browser and talk to this web server and it would work fine. It wouldn't show you anything. Why wouldn't it show you anything? There's nothing to show. We didn't send anything, right? It's an empty body. But it would successfully connect and successfully show us nothing, which is different than an error that said that something bad happened. Look at this. What is it? Six lines? It's a lot more assembly, but still, six lines of code. You're a web server now. Okay, but it's kind of a boring web server. It doesn't actually do anything. Oftentimes they may want to forget a specific file. Now, web servers, like how they're actually done, usually you wouldn't just want to allow anybody access to any file on your machine. Why is that? Yeah, security, like you don't want them to have access to all your files. We have special files on there. But, you know, right now we're just building things and we'll learn more about the security later as we learn how to build. And so, if we wanted to actually emulate a server or create a web server where somebody could get any file on our system, what would we do? So the first thing we did was write the response. Can we write our response yet? We need to read. Why do we need to read? Yeah, we need to read what they sent us so that we can find and what specific thing are we trying to find, right? So this is the HTTP request. And this, I think, is also the status of the response. What's the first part of the request call? The method of the response. Yeah, that line is called something. That part is the method, but that first line, like the first new line is something. I definitely talked about it. I know, I'm looking it up. I'm trying to look it up. I wish one of you would talk, sorry. It's the start line, there we go. So on the request, it's the start line and then headers and then the status line on the reply. So the first thing is the start line and it tells us first the method and then the second one is what? And then the third thing is, yeah, the version, the HTTP version, exactly. And then what's after that in an HTTP request? Queries go after the path. Headers, HTTP headers, headers are what? 20 queries by, or HTTP request by name, gone. That was only two weeks ago. Yeah, but what's the format as a header? What's the format of the syntax? Header name, colon, and then what? And then the argument, usually a space, I think, is probably technically in spec. I don't know if things are more lenient. Yeah, header name, colon, space, slash r slash n, another header name, colon, header, value, and then how do we know when we're done with the headers? An empty line, exactly, which was, if we look, well, anyways, because the response can have headers, but anyways, empty line and then a body, right? Cool, okay, we don't care about all of the requests, right? We're only writing a server that's only getting, looking for the second part here. So, we just mentioned, we first wanna read, what file descriptor are we gonna wanna read from? What's the first argument to read? The first argument to read is a file descriptor. We've bound to a port, a port and an IP address. We're listening, we've accepted a connection. The operative system told us, yep, there's somebody that wants to talk to you. They're on file descriptor four. What was that? Four, we wanna read from file descriptor four, why? Yeah, and what are we trying to figure out when we read from file descriptor four? Exactly, we wanna get their start, the start line, and we wanna understand exactly where that value is. Cool, so we wanna read from file descriptor four. The second argument to read in this S-trace is a little bit confusing because it's not a string that we pass in, what do we pass in as read for the second parameter? An address to put the data that came in from the other side of the connection. So why is, and the third argument is the amount of bytes to read, so where does that come from? Not seven from the request is in our code, so this is hard coded in our server code. How come it's not 10 or 20 or 1,000? Yeah, we don't know. So this is actually, you can see here a key problem about the HTTP protocol. There's no limit on how much data can be sent in an HTTP request or an HTTP response. And so this is why we have to first read this, parse it, understand if we needed to read more and then parse more and sort things in data, all this kind of stuff. For our little simple web server purposes, we can just be pretty conservative. We are not. We can be pretty generous and just say, okay, they will probably tell us within two and a half weeks, I guess technically we could look at the spec and see, okay, what is the, because we only care about the path and we can see what's the longest path that we could possibly have and we don't need to worry about that right now. So we just use a large value. We just have to make sure there's enough space there. Yeah, your which out on the server side? Ah, so we still don't know. So we do know something. So we know something about how many bytes we read because the return value of read returns how many bytes, 19. So this is exactly one, two, three, four, five, six, seven, eight, nine, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22. Okay, that's weird. Why is it 19? It should probably be 21 or 22. Did I? One, two, three, four, five, six, seven, eight, nine, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19. Yeah, that's weird. Right, returns it up to the new line. Maybe that's a weird optimization somewhere. Anyways, it doesn't matter because it gets us what we need, but it tells us that 19 bytes were read in. So that's what we have to use and we have to dynamically allocate memory. So we have to use something like malloc, which you're writing assembly code. You don't have access to malloc. So you have to figure out another way to do it. So it'd be very complicated to do it. Purely an assembly based on what you're doing now and this is why libraries exist to help you do that for other programs. But this is why you can't know in advance how big it's necessarily going to be. But we do actually, this is why anybody has fond memories of their friend, Mr. Content Lake Header. I see some shutters and then some people nodding. Yeah, so the Content Lake Header, now you can see why that's necessary because the server has to read that value and then it understands how many bytes to expect in the body. So it will keep reading that many bytes and that's why you have to send that many bytes. So some of you are getting into infinite loops because you set a long Content Lake that didn't send that much data. I think I was suggesting to some person to just keep hitting enter until they got to the end and hit 1,000 bytes and they would have got the flag. But it's better to actually fix it. Okay, cool. So we can read from this and now how do we know to open slash lag? Right, what? These bytes are written wherever this argument is in memory. So how do we know to write slash flag? To open flag, the file slash flag. Yeah, but how do we actually like, if we were gonna do that, what's the logic? So there's some address in memory. We call read, it says, great, I have 19 bytes now. So that pointer that we passed in the second argument to read, what's the value of the first byte that it points to? Was it? Capital G, yeah. So then we have to go through that until what? A space, because that's part of the protocol, right? So the first thing is the method. If we needed to, let's say like some of the future levels do, if we needed to do something, if it was a get or a post, we could look at that first character and say is it a G or a P and change our logic depending. Then we could go through until we get to a space, go one more character and then we know, okay, that is the start of the path. Then can we just pass that string, that memory location into open? So what if I did this? So what if I had a pointer here at slash flag and I called open and gave it that memory address right here? What file would it open? The operating system known against the end of the string or a C, how does a C program known against the end of the string? A zero, a null byte. So what we'll try to, if we assume there's a zero at the end here, it will try to open a file called slash FLAG space HGTP slash 1.0 slash r slash n slash r s s n. The operating system will tell us that file does not exist and we'll get an error on the open statement. So what should we do? Yeah, so we'd go through, figure out where the next space is and change the space to what? A null byte, yes, zero. Slash zero and see if you're thinking about that. We're literally just zero and null byte right there and we put a null byte right here where this space is and then we do the same thing that we were previously doing, calling open with a pointer to the startup slash. What file will the operating system try to open for us? Slash flag. And we can tell that we want to read it. So read only means we're telling the operating system we only want to open this file for reading. This is because we're not changing this so we don't care. This returned, what type of thing does an open return? What was it? A file descriptor, just another one, right? Again, do we care exactly what it is? No, but we know it's file descriptor five because the smallest number that's available is five and so that will be slash flag. Now what do we, yeah, here does this argument? So open takes a pointer, right? It takes a memory address. So you need to make sure the bytes that that is pointing to are the file that you want to have open, yeah, exactly. So that's why you have to do some minor parsing on this input in order to figure out where the start of it is and then null out the end of it. Now that we've opened it, now what do we want to do? What was it? Read from it. We want to read it. We have to read from it. Again, we need to store what we call read just like the previous read. And this is file descriptor five, right? Because this is reading from the file that we just opened. We have to give it some other probably memory location because we want to be careful that we're not using the same pointers and overriding our data here, although maybe that's fine, but I'd probably avoid that. So we want some place to put the result there and we can be conservative again and say 256. We don't know how much. We can now, oh, that's pretty clever, I see. So now we can do several different things. We can do like we did before, write out the status line that we had before. So the, what do we call that? Yeah, the status line, slash r slash n, slash r slash n, and then the contents that we just read. All right, let's close it and then we're done. Okay, let's, let me know when you're done and then we'll switch over to an example of doing this with a different format, not HTTP because that's what you're doing. This is the one challenge of these levels. If I show you how to solve, let's say level seven, like many people were asking. If I do that, then that will automatically solve you all levels one through six. So I'm not going to solve any specific level, but we can use similar concepts to the different protocol and try to see how that would be structured. Make sense? Oh, these values? Yeah, we went through finding those. So now we can actually, with this lines, actually not crazy, we've built a tiny little server that actually responds and returns those files. So let's, I'm going to use Emacs because I'm tired of using Vim. This is driving me insane. So let's go here. Okay, so this is where we were last time. We were calling socket, so this is IPv6. So again, if you're following this, this will not work for what you're doing, right? This is for specifically IPv6. So we call socket. So this is our socket called. We're telling the operating system, hey, I want to make an IPv6 socket. We then bind. We're then calling bind. And this is the one I got in right under the buzzer with this nice offset. If any of you were watching or were there. This is the data structure that we had talked about. I'm trying to look that up later, but it was in the slides, but this is the family. So 10 should be exactly what this AFINET6 is, is 10. So the first thing was the family. The second thing was which one? You remember? What was it? The port and it was a short, so it's two bytes. And it was, so let's reverse engineer this. So if we were just looking at this, what port is this? Is this port, so 91F, like a decimal? Is this port 36,895? Why not? Little Indian, so we got to flip the bytes around. So this should be 1F90 and going to 10, it's 8080. And you remember that from Monday? Amazing. Cool. Then we have dot space says fill four bytes with zero. This was some IPv6 junk. If I remember correctly, this was like the flow ID and something else here. Actually, I think I can show it here with this run. Yeah, here's the S-trace, bind, essay family, AFINat6, the port, 8080, flow info, then the IPv6 address, and then the scope ID, cool. So I should be able to, I had originally done this with all Fs. Let's say I want to listen on any port here. I'm gonna change this to all zeros. Let's see, this, I do not have this, okay, there we go. Okay. So now I can see the bind. I am binding on port 8080 with an empty. So on all zeros for my IPv6 address, and was this bind successful? Yes, how do you know? I returned a non-negative. Yeah, tricky, cause it's not positive, it's zero, but it returned a non-negative number. So we have successfully listened on this port, but then we just immediately exited and then did nothing after that. Okay. So we've bound. What are the next things we do if we wanna make a server? What's the next call? I can't hear you. Listen, thank you. So I wanna listen on that FD and this is why, remember, like I said, why you wanna write comments to yourself because I absolutely no idea what we stored FD into, but luckily this nice little comment says we stored FD into RBX. So if we want to call listen, we will need to look at our handy, is this call table? Listen, it's 50. Move into RAX 50 and I'll need to move into, oh, so that's that. The first argument is RDI. So move into RDI RBX. So that should be our file descriptor and then move into RSI. What was the second argument? It was our backlog, which here is zero. This will not work. Well, don't do that. I think I made a point of that. What's the last thing I do? CIS call, yes. Now what should I do? Should I just keep writing code? I can test it, see if this works before I do other stuff that relies on this that is broken. Build it, trace it. And I'm looking specifically for this listen. Good, this is exactly what we wanted. All right, what's the next one? Accept. And let's go back to this, Mr. Slide. Accept, null, null. Oh, that's right, that's the address. And this is not three. It's FD. And what is accept return? A new file descriptor, yeah. So let's call this client FD. How about that? We go with that. Cool. Okay. Need to figure out accept. Accept is 43. Move into RDI RBX because that's the FD. Move into RSI zero. Move, what was the last one? RDX, thank you. So it's so nice having all of your brains. Last thing, I thought I was just fading from lack of coffee or, oh, dead battery is what it says, so it has enough juice. It has enough juice to tell me that. Okay, success that people can hear now. Okay, let me figure out which way to charge. Did you see that? Looks like a battery charger. Did I break it? Nope, nope, okay. Everything's fine. Okay, what do I do now at the end of this block? Is this call our favorite friend? Okay. And then what? Test it. What am I looking for? The accept system call has non-negative return result. Beautiful. Oh no, it's not showing me a non-negative return result. Why is that? My computer hang? Yeah, remember, we read the manual for accept. What does accept do? It listens for a connection. Will there be any connection? Probably not. If there was, that'd be super weird because that means one of you, like, I didn't do it. So somebody else is magically connecting to port 80 on IPv6 in my specific instance here. So it should be impossible for you to do that. Yeah, exactly. It doesn't have an end parenthesis yet. I think because it hasn't actually ended. So there's no accept. Yeah, so it hasn't actually ended so it doesn't do the parenthesis and then the equal. So, do we just give up now and just keep writing code? What should we do? Run the challenge and see what it expects as input. But I wanna debug this, I'm not even doing the challenge. I'm doing something completely different. But okay. Let's do that. This is hanging, why? Yes, the accept never stops and what else? Well accept stops when somebody connects to that port. What port is this challenge connecting on? 80, what port are we listening on? 8080, that's why this doesn't work. We can actually see here that we never got a return result from accept because we got a sig alarm. Or did this return? I don't know. Anyways, we got an alarm. So this did not solve our problem and we're relying on all this challenge infrastructure to do this, but I'm writing this separate IPv6 thing that's listening on port 8080 to do something we haven't even decided on yet. And I wanna test it here with Strace. Yeah. And what was that nice tool that you could use just to make a TCP connection to any arbitrary IP address on port? Netcat, curl is limited, well limited to like HTTP, but we just wanna talk to it. So let's open up a new terminal. I can't increase the font size, there we go. Cool. So we can Strace the server. It's listening, Netcat. I think this won't work, but let's see. The port was, it was local host, it actually wasn't local host, it was 8080. I did connect. Oh, that's really annoying. Okay. I was hoping I need more IPv6 stuff, but I guess it worked. So it did succeed. And then we can see going back to that question, Strace wrote out that final parentheses and it gave us the return value and was the return value what we wanted? Yeah. So our accept is correct and now we know how to talk to ourselves, right? We can make a TCP connection to this IP address on port. I was hoping we'd have to look at Netcat to figure out how to do IPv6 connections, but something else must be happening. So whatever, we'll ignore that. Okay. So we did that. Now what do we do? Yeah, we're gonna run a read from this client FD that was returned from accept. I'm gonna do stuff with that. First, we have to invent a protocol because we're not gonna use HTTP because you're doing HTTP. Though we can do something similar. Let's, what do you think? I actually just want to use get, but I think that's because we've been looking at it so much. Gimme underscore file name underscore client. I like that client and then version number. Okay. So let's do, so anything, we'll just inventing our own, no, not version, this was file. Okay. We'll do slash N because we don't want, cool and, okay. So, anything that's not between brackets is literal, let's say. So this means literal capital G I M M E underscore and then this in brackets is dynamic could be a file. And then an underscore. We do slightly have a problem here. How do you ask for a gimme a file name that has an underscore in it? Yeah, we'd have to invent that, but let's ignore that for now and just say that no files with backslashes. This one's great when you're developing a protocol. You can just do whatever you want. You can say files don't have backslashes. Cool. And then client and then some version number. So this is gonna be the client and what do we want our server to respond with? About here you go, new line, content. Something like that. Like it, don't like it, you hate it. It's bad protocol, the best protocol. It's good, it's the best, good. I like it, okay. Okay, so let's do this in the way that we just talked about. The first thing we do is just build a static server. What do I mean by static server? Doesn't do anything but returns just one thing, right? It doesn't change what it responds with based on the request. So this is the string that we wanted to send, right? So do we need to read it actually at this point? No, because we're just sending, we actually don't care. That's literally part of static, right? We don't care what you say, I'm always just gonna say here you go and then give nothing in terms of content. Okay, so we will want to write out, where do we wanna write out the FD, this string? How many characters is that? I don't know, but I do know I can use Python to tell me. It's 20, oh, 20, good job. 20, client FD, why is a client FD? Yeah, if we tried to write to FD, we'd get an error because that's not a, that's not a, that socket is only used to call accept on, that was a trick. I was gonna see how long you guys let me go with that. You're supposed to stop me when I make mistakes and also one of my intentionally introduced mistakes. That's why we do this together. Or we're being rated with a party of 28, what is that you're gonna need? Oh, we need someone just like. Cool, welcome. Start writing x86, 64 assembly. We're writing that out, so we wanna call, write, sys write is one, oh, what a nice one. Okay, so move into RAX one, which is right. Yeah, we need to store the client FD. Where do you wanna store it? Our CX, why can't we use RBX? Or why shouldn't we use RBX? We used it for FD. Also, why wouldn't we wanna use like RDI or RSI? Yeah, those are part of the calling convention, right? Those are used to pass arguments to our sys call. So if we put it in there, it would get overwritten as we did future sys calls. Perfect, look at that. All right, we do that. And now into RDI, we want our CX for client FD. I think I made you too cautious for two. Oh, thank you, that was not on purpose. Okay, and in RSI, we want the size 20. Oh, nope, we want that into RDX. Now into RSI, we need our string. So how do we put our string in here? What was that? Yeah, so well, we have several options, right? We actually have this nice data section where we can store data. So we can look at our handy dandy. I wonder if I still have that up from class. Random stuff, grades. Ah, here we go, look at that. And somebody mentioned an ASCII thing. Ah, cool. Okay, so we got to read everything. That's why reading is important. You agree? Okay, good, there was a lot of actually, strenuous, hypnotic, thank you. Okay, so .ASCII expects zero or more string literals, like this delicate string, separated by commas. It assembles each string with no automatic trailing zero byte into consecutive addresses. Does this sound like what we want to use? No, potentially not, because we really want that trailing zero byte. So we'd have to make sure to put it ourselves if we use .ASCII. Otherwise, whatever's after that would be cool. Okay, so ASCII Z is something, is just like ASCII, but each string is followed by a zero byte. The Z stands for zero. Cool, that sounds like something we'd want to use, right? Sweet, all right. ASCII Z, copy that here. We need to give it a name so we actually know where this place is. So what do you think, server response? Sound like that? And then we can look back, because of course I don't even remember what I did yesterday. So we already did this, cool. So we can use this offset trick. So if we just did this, what does this instruction mean? Correct. We could look at the, because so it's telling us zero or more string literals, C-section strings, so we could click on that and say a string is written between double quotes. It may contain double quotes or null characters. The way to get special characters is to escape those characters, proceed them with a backslash character. So to me, this reads as exactly like the strings you're normally used to. As long as we do it in double quotes, we can backslash do anything we want. We can do arbitrary hex values with slash X in here. Okay. So back here, where were we? Writing. Okay. Yeah. So we want to do offset server response. How's that look? Syscall, thank you. Okay. Should we test? See if we have our nice static server. Okay. So I run it, it's stuck on the accept. Before I hit enter on this net cap, what do I expect to happen? This is successful. What do we want to see? What was that? I want to see where? Will it be printed out on this terminal? What will I see on this terminal that tells me I'm successful on the one that's running the server? What was it? Oh, I said zero, but non-negative is more correct. Of for which one? For what? Yeah, for the right. So I should see a right. I should see writing to whatever the return value of the accept is. I should see a string value as a second argument. I should see 20 as the third argument and it should have a non-zero. It actually is the amount of bytes written so it should be 20 because that's what we're telling it to write. It's actually not 20, we'll have problems but we'll ignore that for now. So then what do I expect to see on the right? I should see that string because it's writing it and net catch will show me on standard out exactly what it's written. Okay. It didn't work. Why didn't it work? Is that it again? I didn't give it what request. We're not doing any reads, we're only doing a right. It's a mistake that happens all the time. Where's my right? Let's look back at the code. So call accept, store it, syscall, write it. So I should see some kind of syscall here. So why didn't I see that? So still no write. What happened? What's step one? You write code and then what do you do? You test it. How do you test it? What was that? Before you run it. You can't just run code. Compile it. We missed the step. We didn't compile it. I just ran the server. I'm running the old version. Yeah, this happens all the time. This is what you should think about first. It's like, if you're ever in a case, you're like, I'm going insane. I'm making changes to my code and the binary isn't changing. You should think, oh wait, am I compiling my code? Because if the answer is no, then that's the problem. Yeah, this happens all the time. Just good to think of that first. Hey, look at that. Very sweet. Look at that, we're talking. Bang, sending data across the network. So we got the write. We got the for. We got the server. Here you go, slash n. We got the 20. So good. Does it always say server? We did that. Actually, you're right. That was, this is not part of our protocol because it's supposed to be here you go. Thank you. Okay. And I will compile it, test it. This is so annoying, I hate it when this happens. Ah, this is failing because the address port 80 is already in use. This can happen if your server crashes and it's, the operating system hangs on to the port for a little bit and doesn't let another process reuse it. So we have to wait for a little bit. I really hate that. Hi. Is that the challenge you started with virtual network? Yeah, the challenge just doesn't happen, but this is real life. Okay. So all we do is change the server colon to just be here we go. Here you go, because that's part of the format. Okay, so now we want to read in. So now we're going back to our read. So we want to move into RAX. Wanna call read? We are read people zero. Perfect. Read. And I am reading from a file descriptor. What file descriptor am I reading from? Client file descriptor, which is in, so I want to RCX client FD. So read from there. I need to read from somewhere. So the read argument, oh, I guess I didn't put the, well, this is what I'm trying to do. So I want to read that. So I have the file descriptor. Our SI is going to be some buff that I'm just going to put something in here. So this will be some offset because I'm going to, it's going to be a memory address. I'm going to want to do that. And we'll move RDX. So let's say 256 because we don't know exactly how long it is. Let's just say that. Okay. So I need some place to store this. Where do I want to store it? I could store it on the stack. There's a stack for me. There may or may not be enough space on the stack. So I have to worry about allocating space. I personally don't want to deal with that right now. So we've just been storing stuff in .data. So why not just store more stuff there? And the cool thing is I have, I already have this nice space thing that I can say I want 256 bytes of zeros. And let's call it buff for a buffer. Except some buffer, it's going to reserve 256 bytes. That'll be zeros. Make sense? So when I read, I think there's a buff, right? Okay, syscall at the end. Cool. So now if I test this, what should happen? Same thing. We should see the accept. So I will connect. What was the problem? I didn't compile it. Yes, see? This is why now at this point, if I've made the same mistake twice, I would figure out how can I not make this same mistake again? And to do that, I would add the compilation and running it as one whole step. That way I'd never have to forget this. So I will go down. Boom. All right, the accept pass, it got four. Why is it hanging on read? We don't have any data. So there's no data to read. We've made a connection, but we haven't sent anything yet. So we need to have some kind of thing to read. Read four, gimme underscore. So this is exactly what I sent in with an extra, the slash slash n because I just typed in slash n instead of a new line. 256, it told me it read 32 bytes. And now I can actually create just a very simple, stupid echo server by just changing this from my server response to buff. Although the length will be messed up, but let's look at that. So read in, oh, interesting. My right failed, why did my right fail? That's correct, the length is hard code to 20, but there's something else that's wrong here. Yeah, my file descriptor was messed up, which is an RCX. Maybe RCX was a poor decision. So this is when I'd look up a system V calling convention. I would look up and see that, ah, parameters to functions are pass and registers, RDI, RSI, RDX, RCX, R8, R9. Oops, seems bad. We accidentally use one and when we're changing things, that happened to be constant with our previous tests, but this just blew up in our face. A good thing to look for is functions preserve the registers, RBX, RSPRBP, R12, R13, 14, 15. So let's use R12 because that seems fine. Let's use that for client FD. Let's see, oh, hello. I'll use an Emacs function query replace RCX with R12. Is that what we said? R12, boom, boom, boom, boom. Hey, there we go. So now I just wrote a very simple thing that reads in and whatever it reads in and we'll just output that back. We messed up the exact size. Okay, but let's look at, let's get closer to where we wanted to build in here. I will go slightly faster because we only have four minutes technically. So let's change buff back to server response. Buff to server response. Okay, so now we need to open that file. So we need to first figure out file, then open file, then read file, and then here we'd wanna say output file content. So I'm just outlining and sketching what I want the program to do. It's actually a good trick. If you're programming, I learned this in a really good book called Code Complete that you can write out, you're like at a high level, what you wanna do in a function and comments, and then you go in and fill those out and then your comments actually help kind of explain what the thought process is of the function. So figuring out the file. So we have buff. Buff will point to the start of the request which was gimme underscore. So I will need a register. So let's use R, give me a new good one, R13. R13 for start of file. So like the file name that we want. So let's move into R13, the offset of buff. So this should point to the start of the string now that we just read in into R13. And we wanna increment this how many times until when? What was it? Until we see a, well, not a space, our format doesn't have spaces. An underscore, yeah, because that's what separates this from here. Exactly, okay. So we'll want to do something like move into, let's say, let's say move into Rax zero. So no, let's do, sorry. Move into AL, we'll use the lower byte of Rax to do our calculation. We're gonna dereference R13. So this means take that byte that is there, move it into AL. We wanna compare it with what? We just said underscore, AL with underscore. We'll have to look at the ASCII values. Oh, underscore is 5F, okay. And do this comparison. So get it, move it in, compare the byte, jump if equal to done. Let's say found underscore. Okay, that'll be something else to do afterwards. So if it's equal, then jump there. If it's not equal, start to find. First I need to do one thing before I do that. Increment R13, so I'm advancing the pointer by one byte. Jump, start underscore, after. Okay, so how can I test that this worked? Cause I just wrote a bunch of code. And if I have to write all these functions to open the file, read the file, blah, blah, blah. How can I test it with what I have right now? One thing I can do is debug it. I use GDB debug it. But I already have something that's outputting to me. So if I change this from offset of server response to our new friend R13, this should do what? Say it again? It's not a number, this is a pointer. So write is writing to a buffer. R13 should point to at this point, what? Yeah, we're the first underscore. I think it should be at the underscore. So we may need to deal with that later when actually doing the file. So it should get rid of all the gimme underscore. So if we do this, instruction suffers, JV. So we got back that right there. We incremented one more, we're exactly at the file. We do something similar to find the last underscore. Write that out to be a zero and boom. Now R13 points to exactly a null terminated string that is the file we want to open. Is that terminal like sitting on the right? On the left or on the right? On the right, it's not exactly you have to hit enter afterwards, I don't know why. Look at that, we just did that. Pretty cool. Good stuff, you got it. How was that?