# HG changeset patch # User Adam Chlipala # Date 1215970703 14400 # Node ID c5d7ce9ddd57ab2f36ca7851ffe87542b86826e1 # Parent ff13d390ec60f9fe5f094fde3345642060754b9b Basic web server diff -r ff13d390ec60 -r c5d7ce9ddd57 src/c/driver.c --- a/src/c/driver.c Sun Jul 13 12:56:39 2008 -0400 +++ b/src/c/driver.c Sun Jul 13 13:38:23 2008 -0400 @@ -1,8 +1,132 @@ -void lw_handle(void); +#include + +#include +#include +#include +#include + +int lw_port = 8080; +int lw_backlog = 10; +int lw_bufsize = 1024; + +void lw_handle(char*); + +static void worker(int sock) { + char buf[lw_bufsize+1], *back = buf, *s; + + while (1) { + int r = recv(sock, back, lw_bufsize - (back - buf), 0); + + if (r < 0) { + fprintf(stderr, "Recv failed\n"); + close(sock); + return; + } + + if (r == 0) { + printf("Connection closed.\n"); + close(sock); + return; + } + + printf("Received %d bytes.\n", r); + + back += r; + *back = 0; + + if (s = strstr(buf, "\r\n\r\n")) { + char *cmd, *path; + + *s = 0; + + if (!(s = strstr(buf, "\n"))) { + fprintf(stderr, "No newline in buf\n"); + close(sock); + return; + } + + *s = 0; + cmd = s = buf; + + if (!strsep(&s, " ")) { + fprintf(stderr, "No first space in HTTP command\n"); + close(sock); + return; + } + + if (strcmp(cmd, "GET")) { + fprintf(stderr, "Not ready for non-get command: %s\n", cmd); + close(sock); + return; + } + + path = s; + if (!strsep(&s, " ")) { + fprintf(stderr, "No second space in HTTP command\n"); + close(sock); + return; + } + + printf("Serving URI %s....\n", path); + puts("Content-type: text/html\n\n"); + puts(""); + lw_handle(path); + puts(""); + + printf("Done with client.\n\n"); + close(sock); + return; + } + } +} int main() { - puts(""); - lw_handle(); - puts(""); - return 0; + // The skeleton for this function comes from Beej's sockets tutorial. + int sockfd, new_fd; // listen on sock_fd, new connection on new_fd + struct sockaddr_in my_addr; + struct sockaddr_in their_addr; // connector's address information + int sin_size, yes = 1; + + sockfd = socket(PF_INET, SOCK_STREAM, 0); // do some error checking! + + if (sockfd < 0) { + fprintf(stderr, "Listener socket creation failed\n"); + return 1; + } + + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) < 0) { + fprintf(stderr, "Listener socket option setting failed\n"); + return 1; + } + + my_addr.sin_family = AF_INET; // host byte order + my_addr.sin_port = htons(lw_port); // short, network byte order + my_addr.sin_addr.s_addr = INADDR_ANY; // auto-fill with my IP + memset(my_addr.sin_zero, '\0', sizeof my_addr.sin_zero); + + if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof my_addr) < 0) { + fprintf(stderr, "Listener socket bind failed\n"); + return 1; + } + + if (listen(sockfd, lw_backlog) < 0) { + fprintf(stderr, "Socket listen failed\n"); + return 1; + } + + sin_size = sizeof their_addr; + + printf("Listening on port %d....\n", lw_port); + + while (1) { + new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size); + + if (new_fd < 0) { + fprintf(stderr, "Socket accept failed\n"); + return 1; + } + + printf("Accepted connection.\n"); + worker(new_fd); + } } diff -r ff13d390ec60 -r c5d7ce9ddd57 src/cjr_print.sml --- a/src/cjr_print.sml Sun Jul 13 12:56:39 2008 -0400 +++ b/src/cjr_print.sml Sun Jul 13 13:38:23 2008 -0400 @@ -174,11 +174,15 @@ end fun p_page env (s, n) = - box [string "/* ", - string s, - string " */ ", + box [string "if (!strcmp(request, \"", + string (String.toString s), + string "\")) {", + newline, p_enamed env n, - string "(lw_unit_v);"] + string "(lw_unit_v);", + newline, + string "}", + newline] fun p_file env (ds, ps) = let @@ -193,7 +197,7 @@ newline, p_list_sep newline (fn x => x) pds, newline, - string "void lw_handle(void) {", + string "void lw_handle(char *request) {", newline, p_list_sep newline (fn x => x) pds', newline, diff -r ff13d390ec60 -r c5d7ce9ddd57 src/cjrize.sml --- a/src/cjrize.sml Sun Jul 13 12:56:39 2008 -0400 +++ b/src/cjrize.sml Sun Jul 13 13:38:23 2008 -0400 @@ -184,7 +184,7 @@ in (SOME (d, loc), NONE, sm) end - | L.DExport n => (NONE, SOME n, sm) + | L.DExport (s, n) => (NONE, SOME ("/" ^ s, n), sm) fun cjrize ds = let