mirror of
https://github.com/SmallPond/MIT6.828_OS.git
synced 2026-05-01 22:29:43 +08:00
my solution to lab 6
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
OBJDIRS += user
|
||||
|
||||
USERLIBS += lwip
|
||||
|
||||
USERLIBS += jos
|
||||
|
||||
|
||||
89
lab/user/echosrv.c
Normal file
89
lab/user/echosrv.c
Normal file
@@ -0,0 +1,89 @@
|
||||
#include <inc/lib.h>
|
||||
#include <lwip/sockets.h>
|
||||
#include <lwip/inet.h>
|
||||
|
||||
#define PORT 7
|
||||
|
||||
#define BUFFSIZE 32
|
||||
#define MAXPENDING 5 // Max connection requests
|
||||
|
||||
static void
|
||||
die(char *m)
|
||||
{
|
||||
cprintf("%s\n", m);
|
||||
exit();
|
||||
}
|
||||
|
||||
void
|
||||
handle_client(int sock)
|
||||
{
|
||||
char buffer[BUFFSIZE];
|
||||
int received = -1;
|
||||
// Receive message
|
||||
if ((received = read(sock, buffer, BUFFSIZE)) < 0)
|
||||
die("Failed to receive initial bytes from client");
|
||||
|
||||
// Send bytes and check for more incoming data in loop
|
||||
while (received > 0) {
|
||||
// Send back received data
|
||||
if (write(sock, buffer, received) != received)
|
||||
die("Failed to send bytes to client");
|
||||
|
||||
// Check for more data
|
||||
if ((received = read(sock, buffer, BUFFSIZE)) < 0)
|
||||
die("Failed to receive additional bytes from client");
|
||||
}
|
||||
close(sock);
|
||||
}
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
int serversock, clientsock;
|
||||
struct sockaddr_in echoserver, echoclient;
|
||||
char buffer[BUFFSIZE];
|
||||
unsigned int echolen;
|
||||
int received = 0;
|
||||
|
||||
// Create the TCP socket
|
||||
if ((serversock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
|
||||
die("Failed to create socket");
|
||||
|
||||
cprintf("opened socket\n");
|
||||
|
||||
// Construct the server sockaddr_in structure
|
||||
memset(&echoserver, 0, sizeof(echoserver)); // Clear struct
|
||||
echoserver.sin_family = AF_INET; // Internet/IP
|
||||
echoserver.sin_addr.s_addr = htonl(INADDR_ANY); // IP address
|
||||
echoserver.sin_port = htons(PORT); // server port
|
||||
|
||||
cprintf("trying to bind\n");
|
||||
|
||||
// Bind the server socket
|
||||
if (bind(serversock, (struct sockaddr *) &echoserver,
|
||||
sizeof(echoserver)) < 0) {
|
||||
die("Failed to bind the server socket");
|
||||
}
|
||||
|
||||
// Listen on the server socket
|
||||
if (listen(serversock, MAXPENDING) < 0)
|
||||
die("Failed to listen on server socket");
|
||||
|
||||
cprintf("bound\n");
|
||||
|
||||
// Run until canceled
|
||||
while (1) {
|
||||
unsigned int clientlen = sizeof(echoclient);
|
||||
// Wait for client connection
|
||||
if ((clientsock =
|
||||
accept(serversock, (struct sockaddr *) &echoclient,
|
||||
&clientlen)) < 0) {
|
||||
die("Failed to accept client connection");
|
||||
}
|
||||
cprintf("Client connected: %s\n", inet_ntoa(echoclient.sin_addr));
|
||||
handle_client(clientsock);
|
||||
}
|
||||
|
||||
close(serversock);
|
||||
|
||||
}
|
||||
68
lab/user/echotest.c
Normal file
68
lab/user/echotest.c
Normal file
@@ -0,0 +1,68 @@
|
||||
#include <inc/lib.h>
|
||||
#include <lwip/sockets.h>
|
||||
#include <lwip/inet.h>
|
||||
|
||||
#define BUFFSIZE 32
|
||||
#define IPADDR "10.0.2.15"
|
||||
#define PORT 10000
|
||||
|
||||
const char *msg = "Hello world!\n";
|
||||
|
||||
static void
|
||||
die(char *m)
|
||||
{
|
||||
cprintf("%s\n", m);
|
||||
exit();
|
||||
}
|
||||
|
||||
void umain(int argc, char **argv)
|
||||
{
|
||||
int sock;
|
||||
struct sockaddr_in echoserver;
|
||||
char buffer[BUFFSIZE];
|
||||
unsigned int echolen;
|
||||
int received = 0;
|
||||
|
||||
cprintf("Connecting to:\n");
|
||||
cprintf("\tip address %s = %x\n", IPADDR, inet_addr(IPADDR));
|
||||
|
||||
// Create the TCP socket
|
||||
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
|
||||
die("Failed to create socket");
|
||||
|
||||
cprintf("opened socket\n");
|
||||
|
||||
// Construct the server sockaddr_in structure
|
||||
memset(&echoserver, 0, sizeof(echoserver)); // Clear struct
|
||||
echoserver.sin_family = AF_INET; // Internet/IP
|
||||
echoserver.sin_addr.s_addr = inet_addr(IPADDR); // IP address
|
||||
echoserver.sin_port = htons(PORT); // server port
|
||||
|
||||
cprintf("trying to connect to server\n");
|
||||
|
||||
// Establish connection
|
||||
if (connect(sock, (struct sockaddr *) &echoserver, sizeof(echoserver)) < 0)
|
||||
die("Failed to connect with server");
|
||||
|
||||
cprintf("connected to server\n");
|
||||
|
||||
// Send the word to the server
|
||||
echolen = strlen(msg);
|
||||
if (write(sock, msg, echolen) != echolen)
|
||||
die("Mismatch in number of sent bytes");
|
||||
|
||||
// Receive the word back from the server
|
||||
cprintf("Received: \n");
|
||||
while (received < echolen) {
|
||||
int bytes = 0;
|
||||
if ((bytes = read(sock, buffer, BUFFSIZE-1)) < 1) {
|
||||
die("Failed to receive bytes from server");
|
||||
}
|
||||
received += bytes;
|
||||
buffer[bytes] = '\0'; // Assure null terminated string
|
||||
cprintf(buffer);
|
||||
}
|
||||
cprintf("\n");
|
||||
|
||||
close(sock);
|
||||
}
|
||||
@@ -18,5 +18,7 @@ umain(int argc, char **argv)
|
||||
// fault, because user-level code shouldn't be able to use the io space.
|
||||
outb(0x1F6, 0xE0 | (1<<4));
|
||||
|
||||
|
||||
cprintf("%s: made it here --- bug\n");
|
||||
|
||||
}
|
||||
|
||||
354
lab/user/httpd.c
Normal file
354
lab/user/httpd.c
Normal file
@@ -0,0 +1,354 @@
|
||||
#include <inc/lib.h>
|
||||
#include <lwip/sockets.h>
|
||||
#include <lwip/inet.h>
|
||||
|
||||
#define PORT 80
|
||||
#define VERSION "0.1"
|
||||
#define HTTP_VERSION "1.0"
|
||||
|
||||
#define E_BAD_REQ 1000
|
||||
|
||||
#define BUFFSIZE 512
|
||||
#define MAXPENDING 5 // Max connection requests
|
||||
|
||||
struct http_request {
|
||||
int sock;
|
||||
char *url;
|
||||
char *version;
|
||||
};
|
||||
|
||||
struct responce_header {
|
||||
int code;
|
||||
char *header;
|
||||
};
|
||||
|
||||
struct responce_header headers[] = {
|
||||
{ 200, "HTTP/" HTTP_VERSION " 200 OK\r\n"
|
||||
"Server: jhttpd/" VERSION "\r\n"},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
struct error_messages {
|
||||
int code;
|
||||
char *msg;
|
||||
};
|
||||
|
||||
struct error_messages errors[] = {
|
||||
{400, "Bad Request"},
|
||||
{404, "Not Found"},
|
||||
};
|
||||
|
||||
static void
|
||||
die(char *m)
|
||||
{
|
||||
cprintf("%s\n", m);
|
||||
exit();
|
||||
}
|
||||
|
||||
static void
|
||||
req_free(struct http_request *req)
|
||||
{
|
||||
free(req->url);
|
||||
free(req->version);
|
||||
}
|
||||
|
||||
static int
|
||||
send_header(struct http_request *req, int code)
|
||||
{
|
||||
struct responce_header *h = headers;
|
||||
// 搜索相应的 header
|
||||
while (h->code != 0 && h->header!= 0) {
|
||||
if (h->code == code)
|
||||
break;
|
||||
h++;
|
||||
}
|
||||
|
||||
if (h->code == 0)
|
||||
return -1;
|
||||
|
||||
int len = strlen(h->header);
|
||||
if (write(req->sock, h->header, len) != len) {
|
||||
die("Failed to send bytes to client");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
send_data(struct http_request *req, int fd)
|
||||
{
|
||||
// LAB 6: Your code here.
|
||||
// panic("send_data not implemented");
|
||||
// 从fd 中读size大小数据,并发送
|
||||
int r;
|
||||
size_t len;
|
||||
char buf[BUFFSIZE];
|
||||
if ( (r = read(fd, buf, BUFFSIZE)) < 0 )
|
||||
return -1;
|
||||
|
||||
len = r;
|
||||
if ( write(req->sock, buf, len) != len) {
|
||||
die("Failed to send bytes to client");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
send_size(struct http_request *req, off_t size)
|
||||
{
|
||||
char buf[64];
|
||||
int r;
|
||||
|
||||
r = snprintf(buf, 64, "Content-Length: %ld\r\n", (long)size);
|
||||
if (r > 63)
|
||||
panic("buffer too small!");
|
||||
|
||||
if (write(req->sock, buf, r) != r)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char*
|
||||
mime_type(const char *file)
|
||||
{
|
||||
//TODO: for now only a single mime type
|
||||
return "text/html";
|
||||
}
|
||||
|
||||
static int
|
||||
send_content_type(struct http_request *req)
|
||||
{
|
||||
char buf[128];
|
||||
int r;
|
||||
const char *type;
|
||||
|
||||
type = mime_type(req->url);
|
||||
if (!type)
|
||||
return -1;
|
||||
|
||||
r = snprintf(buf, 128, "Content-Type: %s\r\n", type);
|
||||
if (r > 127)
|
||||
panic("buffer too small!");
|
||||
|
||||
if (write(req->sock, buf, r) != r)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
send_header_fin(struct http_request *req)
|
||||
{
|
||||
const char *fin = "\r\n";
|
||||
int fin_len = strlen(fin);
|
||||
|
||||
if (write(req->sock, fin, fin_len) != fin_len)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// given a request, this function creates a struct http_request
|
||||
static int
|
||||
http_request_parse(struct http_request *req, char *request)
|
||||
{
|
||||
const char *url;
|
||||
const char *version;
|
||||
int url_len, version_len;
|
||||
|
||||
if (!req)
|
||||
return -1;
|
||||
|
||||
if (strncmp(request, "GET ", 4) != 0)
|
||||
return -E_BAD_REQ;
|
||||
|
||||
// skip GET
|
||||
request += 4;
|
||||
|
||||
// get the url
|
||||
url = request;
|
||||
while (*request && *request != ' ')
|
||||
request++;
|
||||
url_len = request - url;
|
||||
|
||||
req->url = malloc(url_len + 1);
|
||||
memmove(req->url, url, url_len);
|
||||
req->url[url_len] = '\0';
|
||||
|
||||
// skip space
|
||||
request++;
|
||||
|
||||
version = request;
|
||||
while (*request && *request != '\n')
|
||||
request++;
|
||||
version_len = request - version;
|
||||
|
||||
req->version = malloc(version_len + 1);
|
||||
memmove(req->version, version, version_len);
|
||||
req->version[version_len] = '\0';
|
||||
|
||||
// no entity parsing
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
send_error(struct http_request *req, int code)
|
||||
{
|
||||
char buf[512];
|
||||
int r;
|
||||
|
||||
struct error_messages *e = errors;
|
||||
while (e->code != 0 && e->msg != 0) {
|
||||
if (e->code == code)
|
||||
break;
|
||||
e++;
|
||||
}
|
||||
|
||||
if (e->code == 0)
|
||||
return -1;
|
||||
|
||||
r = snprintf(buf, 512, "HTTP/" HTTP_VERSION" %d %s\r\n"
|
||||
"Server: jhttpd/" VERSION "\r\n"
|
||||
"Connection: close"
|
||||
"Content-type: text/html\r\n"
|
||||
"\r\n"
|
||||
"<html><body><p>%d - %s</p></body></html>\r\n",
|
||||
e->code, e->msg, e->code, e->msg);
|
||||
|
||||
if (write(req->sock, buf, r) != r)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
send_file(struct http_request *req)
|
||||
{
|
||||
int r;
|
||||
off_t file_size = -1;
|
||||
int fd;
|
||||
struct Stat st;
|
||||
// open the requested url for reading
|
||||
// if the file does not exist, send a 404 error using send_error
|
||||
// if the file is a directory, send a 404 error using send_error
|
||||
// set file_size to the size of the file
|
||||
|
||||
// LAB 6: Your code here.
|
||||
// panic("send_file not implemented");
|
||||
if ( (r = open(req->url, O_RDONLY) )< 0 ) {
|
||||
return send_error(req, 404);
|
||||
|
||||
}
|
||||
fd = r;
|
||||
// 怎么判断一个fd 是目录, 没有 num2fd
|
||||
if ( (r = fstat(fd, &st)) < 0)
|
||||
return send_error(req, 404);
|
||||
|
||||
if (st.st_isdir)
|
||||
return send_error(req, 404);
|
||||
|
||||
file_size = st.st_size;
|
||||
|
||||
if ((r = send_header(req, 200)) < 0)
|
||||
goto end;
|
||||
|
||||
if ((r = send_size(req, file_size)) < 0)
|
||||
goto end;
|
||||
|
||||
if ((r = send_content_type(req)) < 0)
|
||||
goto end;
|
||||
|
||||
if ((r = send_header_fin(req)) < 0)
|
||||
goto end;
|
||||
|
||||
r = send_data(req, fd);
|
||||
|
||||
end:
|
||||
close(fd);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_client(int sock)
|
||||
{
|
||||
struct http_request con_d;
|
||||
int r;
|
||||
char buffer[BUFFSIZE];
|
||||
int received = -1;
|
||||
struct http_request *req = &con_d;
|
||||
|
||||
while (1)
|
||||
{
|
||||
// Receive message
|
||||
if ((received = read(sock, buffer, BUFFSIZE)) < 0)
|
||||
panic("failed to read");
|
||||
|
||||
memset(req, 0, sizeof(*req));
|
||||
|
||||
req->sock = sock;
|
||||
|
||||
r = http_request_parse(req, buffer);
|
||||
if (r == -E_BAD_REQ)
|
||||
send_error(req, 400);
|
||||
else if (r < 0)
|
||||
panic("parse failed");
|
||||
else
|
||||
send_file(req);
|
||||
|
||||
req_free(req);
|
||||
|
||||
// no keep alive
|
||||
break;
|
||||
}
|
||||
|
||||
close(sock);
|
||||
}
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
int serversock, clientsock;
|
||||
struct sockaddr_in server, client;
|
||||
|
||||
binaryname = "jhttpd";
|
||||
|
||||
// Create the TCP socket
|
||||
if ((serversock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
|
||||
die("Failed to create socket");
|
||||
|
||||
// Construct the server sockaddr_in structure
|
||||
memset(&server, 0, sizeof(server)); // Clear struct
|
||||
server.sin_family = AF_INET; // Internet/IP
|
||||
server.sin_addr.s_addr = htonl(INADDR_ANY); // IP address
|
||||
server.sin_port = htons(PORT); // server port
|
||||
|
||||
// Bind the server socket
|
||||
if (bind(serversock, (struct sockaddr *) &server,
|
||||
sizeof(server)) < 0)
|
||||
{
|
||||
die("Failed to bind the server socket");
|
||||
}
|
||||
|
||||
// Listen on the server socket
|
||||
if (listen(serversock, MAXPENDING) < 0)
|
||||
die("Failed to listen on server socket");
|
||||
|
||||
cprintf("Waiting for http connections...\n");
|
||||
|
||||
while (1) {
|
||||
unsigned int clientlen = sizeof(client);
|
||||
// Wait for client connection
|
||||
if ((clientsock = accept(serversock,
|
||||
(struct sockaddr *) &client,
|
||||
&clientlen)) < 0)
|
||||
{
|
||||
die("Failed to accept client connection");
|
||||
}
|
||||
handle_client(clientsock);
|
||||
}
|
||||
|
||||
close(serversock);
|
||||
}
|
||||
@@ -53,6 +53,9 @@ again:
|
||||
// then check whether 'fd' is 0.
|
||||
// If not, dup 'fd' onto file descriptor 0,
|
||||
// then close the original 'fd'.
|
||||
// LAB 5: Your code here.
|
||||
// panic("< redirection not implemented");
|
||||
|
||||
if ( (fd = open(t, O_RDONLY) )< 0 ) {
|
||||
fprintf(2,"file %s is no exist\n", t);
|
||||
exit();
|
||||
@@ -62,8 +65,7 @@ again:
|
||||
close(fd);
|
||||
}
|
||||
|
||||
// LAB 5: Your code here.
|
||||
// panic("< redirection not implemented");
|
||||
|
||||
break;
|
||||
|
||||
case '>': // Output redirection
|
||||
|
||||
35
lab/user/testtime.c
Normal file
35
lab/user/testtime.c
Normal file
@@ -0,0 +1,35 @@
|
||||
#include <inc/lib.h>
|
||||
#include <inc/x86.h>
|
||||
|
||||
void
|
||||
sleep(int sec)
|
||||
{
|
||||
unsigned now = sys_time_msec();
|
||||
unsigned end = now + sec * 1000;
|
||||
|
||||
if ((int)now < 0 && (int)now > -MAXERROR)
|
||||
panic("sys_time_msec: %e", (int)now);
|
||||
if (end < now)
|
||||
panic("sleep: wrap");
|
||||
|
||||
while (sys_time_msec() < end)
|
||||
sys_yield();
|
||||
}
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
// Wait for the console to calm down
|
||||
for (i = 0; i < 50; i++)
|
||||
sys_yield();
|
||||
|
||||
cprintf("starting count down: ");
|
||||
for (i = 5; i >= 0; i--) {
|
||||
cprintf("%d ", i);
|
||||
sleep(1);
|
||||
}
|
||||
cprintf("\n");
|
||||
breakpoint();
|
||||
}
|
||||
Reference in New Issue
Block a user