Mercurial > dillo_port1.3
changeset 1388:eb35203124e4
Implemented the file dpi based on select() (removed its pthreads dependency)
It should be faster and use less resources.
author | Jorge Arellano Cid <jcid@dillo.org> |
---|---|
date | Sun, 01 Nov 2009 16:31:59 -0300 |
parents | 16cf380cd04c |
children | c1c822f70582 |
files | config.h.in dpi/Makefile.am dpi/bookmarks.c dpi/cookies.c dpi/file.c dpid/main.c dpip/dpip.c dpip/dpip.h |
diffstat | 8 files changed, 510 insertions(+), 396 deletions(-) [+] |
line wrap: on
line diff
--- a/config.h.in Sun Nov 01 16:31:59 2009 -0300 +++ b/config.h.in Sun Nov 01 16:31:59 2009 -0300 @@ -81,6 +81,9 @@ /* Define to the home page for this package. */ #undef PACKAGE_URL +/* Define to the home page for this package. */ +#undef PACKAGE_URL + /* Define to the version of this package. */ #undef PACKAGE_VERSION
--- a/dpi/Makefile.am Sun Nov 01 16:31:59 2009 -0300 +++ b/dpi/Makefile.am Sun Nov 01 16:31:59 2009 -0300 @@ -20,11 +20,10 @@ ftp_filter_dpi_LDADD = ../dpip/libDpip.a ../dlib/libDlib.a https_filter_dpi_LDADD = @LIBSSL_LIBS@ ../dpip/libDpip.a ../dlib/libDlib.a hello_filter_dpi_LDADD = ../dpip/libDpip.a ../dlib/libDlib.a -file_dpi_LDADD = @LIBPTHREAD_LIBS@ ../dpip/libDpip.a ../dlib/libDlib.a +file_dpi_LDADD = ../dpip/libDpip.a ../dlib/libDlib.a cookies_dpi_LDADD = ../dpip/libDpip.a ../dlib/libDlib.a datauri_filter_dpi_LDADD = ../dpip/libDpip.a ../dlib/libDlib.a -file_dpi_LDFLAGS = @LIBPTHREAD_LDFLAGS@ downloads_dpi_CXXFLAGS = @LIBFLTK_CXXFLAGS@ bookmarks_dpi_SOURCES = bookmarks.c dpiutil.c dpiutil.h
--- a/dpi/bookmarks.c Sun Nov 01 16:31:59 2009 -0300 +++ b/dpi/bookmarks.c Sun Nov 01 16:31:59 2009 -0300 @@ -1727,12 +1727,9 @@ while (1) { code = 1; - if ((tok = a_Dpip_dsh_read_token(sh)) != NULL) { + if ((tok = a_Dpip_dsh_read_token(sh, 1)) != NULL) { /* Let's see what we fished... */ code = Bmsrv_parse_token(sh, tok); - } else if (sh->status == DPIP_EAGAIN) { - /* may reach here when the tag size is larger than kernel buffer */ - continue; } dFree(tok);
--- a/dpi/cookies.c Sun Nov 01 16:31:59 2009 -0300 +++ b/dpi/cookies.c Sun Nov 01 16:31:59 2009 -0300 @@ -1482,14 +1482,11 @@ while (1) { code = 1; - if ((buf = a_Dpip_dsh_read_token(sh)) != NULL) { + if ((buf = a_Dpip_dsh_read_token(sh, 1)) != NULL) { /* Let's see what we fished... */ _MSG(" buf = {%s}\n", buf); code = srv_parse_tok(sh, client, buf); dFree(buf); - } else if (sh->status == DPIP_EAGAIN) { - /* may reach here when the tag size is larger than kernel buffer */ - continue; } _MSG(" code = %d %s\n", code, code == 1 ? "EXIT" : "BREAK");
--- a/dpi/file.c Sun Nov 01 16:31:59 2009 -0300 +++ b/dpi/file.c Sun Nov 01 16:31:59 2009 -0300 @@ -15,14 +15,13 @@ * With new HTML layout. */ -#include <pthread.h> - #include <ctype.h> /* for tolower */ #include <errno.h> /* for errno */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <sys/select.h> #include <sys/socket.h> #include <sys/stat.h> #include <sys/types.h> @@ -32,6 +31,7 @@ #include <fcntl.h> #include <time.h> #include <signal.h> +#include <netinet/in.h> #include "../dpip/dpip.h" #include "dpiutil.h" @@ -42,11 +42,32 @@ */ #define _MSG(...) #define MSG(...) printf("[file dpi]: " __VA_ARGS__) +#define _MSG_RAW(...) +#define MSG_RAW(...) printf(__VA_ARGS__) #define MAXNAMESIZE 30 #define HIDE_DOTFILES TRUE +/* + * Communication flags + */ +#define FILE_AUTH_OK 1 /* Authentication done */ +#define FILE_READ 2 /* Waiting data */ +#define FILE_WRITE 4 /* Sending data */ +#define FILE_DONE 8 /* Operation done */ +#define FILE_ERR 16 /* Operation error */ + + +typedef enum { + st_start, + st_dpip, + st_http, + st_content, + st_done, + st_err +} FileState; + typedef struct { char *full_path; const char *filename; @@ -62,34 +83,32 @@ typedef struct { Dsh *sh; - int status; + char *orig_url; + char *filename; + int file_fd; + off_t file_sz; + DilloDir *d_dir; + FileState state; + int err_code; + int flags; int old_style; - pthread_t thrID; - int done; } ClientInfo; /* * Forward references */ static const char *File_content_type(const char *filename); -static int File_get_file(ClientInfo *Client, - const char *filename, - struct stat *sb, - const char *orig_url); -static int File_get_dir(ClientInfo *Client, - const char *DirName, - const char *orig_url); /* * Global variables */ -static volatile int DPIBYE = 0; -static volatile int ThreadRunning = 0; +static int DPIBYE = 0; static int OLD_STYLE = 0; /* A list for the clients we are serving */ static Dlist *Clients; -/* a mutex for operations on clients */ -static pthread_mutex_t ClMut; +/* Set of filedescriptors we're working on */ +fd_set read_set, write_set; + /* * Close a file descriptor, but handling EINTR @@ -250,6 +269,8 @@ int i; FileInfo *finfo; + dReturn_if (Ddir == NULL); + for (i = 0; i < dList_length(Ddir->flist); ++i) { finfo = dList_nth_data(Ddir->flist, i); dFree(finfo->full_path); @@ -264,7 +285,7 @@ /* * Output the string for parent directory */ -static void File_print_parent_dir(ClientInfo *Client, const char *dirname) +static void File_print_parent_dir(ClientInfo *client, const char *dirname) { if (strcmp(dirname, "/") != 0) { /* Not the root dir */ char *p, *parent, *HUparent, *Uparent; @@ -278,7 +299,7 @@ Uparent = Escape_uri_str(parent, NULL); HUparent = Escape_html_str(Uparent); - a_Dpip_dsh_printf(Client->sh, 0, + a_Dpip_dsh_printf(client->sh, 0, "<a href='file:%s'>Parent directory</a>", HUparent); dFree(HUparent); dFree(Uparent); @@ -289,20 +310,20 @@ /* * Given a timestamp, output an HTML-formatted date string. */ -static void File_print_mtime(ClientInfo *Client, time_t mtime) +static void File_print_mtime(ClientInfo *client, time_t mtime) { char *ds = ctime(&mtime); /* Month, day and {hour or year} */ - if (Client->old_style) { - a_Dpip_dsh_printf(Client->sh, 0, " %.3s %.2s", ds + 4, ds + 8); + if (client->old_style) { + a_Dpip_dsh_printf(client->sh, 0, " %.3s %.2s", ds + 4, ds + 8); if (time(NULL) - mtime > 15811200) { - a_Dpip_dsh_printf(Client->sh, 0, " %.4s", ds + 20); + a_Dpip_dsh_printf(client->sh, 0, " %.4s", ds + 20); } else { - a_Dpip_dsh_printf(Client->sh, 0, " %.5s", ds + 11); + a_Dpip_dsh_printf(client->sh, 0, " %.5s", ds + 11); } } else { - a_Dpip_dsh_printf(Client->sh, 0, + a_Dpip_dsh_printf(client->sh, 0, "<td>%.3s %.2s %.5s", ds + 4, ds + 8, /* (more than 6 months old) ? year : hour; */ (time(NULL) - mtime > 15811200) ? ds + 20 : ds + 11); @@ -312,7 +333,7 @@ /* * Return a HTML-line from file info. */ -static void File_info2html(ClientInfo *Client, FileInfo *finfo, int n) +static void File_info2html(ClientInfo *client, FileInfo *finfo, int n) { int size; char *sizeunits; @@ -355,10 +376,10 @@ HUref = Escape_html_str(Uref); Hname = Escape_html_str(name); - if (Client->old_style) { + if (client->old_style) { char *dots = ".. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .."; int ndots = MAXNAMESIZE - strlen(name); - a_Dpip_dsh_printf(Client->sh, 0, + a_Dpip_dsh_printf(client->sh, 0, "%s<a href='%s'>%s</a>" " %s" " %-11s%4d %-5s", @@ -367,15 +388,15 @@ filecont, size, sizeunits); } else { - a_Dpip_dsh_printf(Client->sh, 0, + a_Dpip_dsh_printf(client->sh, 0, "<tr align=center %s><td>%s<td align=left><a href='%s'>%s</a>" "<td>%s<td>%d %s", (n & 1) ? "bgcolor=#dcdcdc" : "", S_ISDIR (finfo->mode) ? ">" : " ", HUref, Hname, filecont, size, sizeunits); } - File_print_mtime(Client, finfo->mtime); - a_Dpip_dsh_write_str(Client->sh, 0, "\n"); + File_print_mtime(client, finfo->mtime); + a_Dpip_dsh_write_str(client->sh, 0, "\n"); dFree(Hname); dFree(HUref); @@ -383,81 +404,92 @@ } /* - * Read a local directory and translate it to html. + * Send the HTML directory page in HTTP. */ -static void File_transfer_dir(ClientInfo *Client, - DilloDir *Ddir, const char *orig_url) +static void File_send_dir(ClientInfo *client) { int n; char *d_cmd, *Hdirname, *Udirname, *HUdirname; - - /* Send DPI header */ - d_cmd = a_Dpip_build_cmd("cmd=%s url=%s", "start_send_page", orig_url); - a_Dpip_dsh_write_str(Client->sh, 1, d_cmd); - dFree(d_cmd); - - /* Send page title */ - Udirname = Escape_uri_str(Ddir->dirname, NULL); - HUdirname = Escape_html_str(Udirname); - Hdirname = Escape_html_str(Ddir->dirname); - - a_Dpip_dsh_printf(Client->sh, 0, - "HTTP/1.1 200 OK\r\n" - "Content-Type: text/html\r\n" - "\r\n" - "<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN'>\n" - "<HTML>\n<HEAD>\n <BASE href='file:%s'>\n" - " <TITLE>file:%s</TITLE>\n</HEAD>\n" - "<BODY><H1>Directory listing of %s</H1>\n", - HUdirname, Hdirname, Hdirname); - dFree(Hdirname); - dFree(HUdirname); - dFree(Udirname); - - if (Client->old_style) { - a_Dpip_dsh_write_str(Client->sh, 0, "<pre>\n"); - } - - /* Output the parent directory */ - File_print_parent_dir(Client, Ddir->dirname); + DilloDir *Ddir = client->d_dir; - /* HTML style toggle */ - a_Dpip_dsh_write_str(Client->sh, 0, - " <a href='dpi:/file/toggle'>%</a>\n"); + if (client->state == st_start) { + /* Send DPI command */ + d_cmd = a_Dpip_build_cmd("cmd=%s url=%s", "start_send_page", + client->orig_url); + a_Dpip_dsh_write_str(client->sh, 1, d_cmd); + dFree(d_cmd); + client->state = st_dpip; - if (dList_length(Ddir->flist)) { - if (Client->old_style) { - a_Dpip_dsh_write_str(Client->sh, 0, "\n\n"); + } else if (client->state == st_dpip) { + /* send HTTP header and HTML top part */ + + /* Send page title */ + Udirname = Escape_uri_str(Ddir->dirname, NULL); + HUdirname = Escape_html_str(Udirname); + Hdirname = Escape_html_str(Ddir->dirname); + + a_Dpip_dsh_printf(client->sh, 0, + "HTTP/1.1 200 OK\r\n" + "Content-Type: text/html\r\n" + "\r\n" + "<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN'>\n" + "<HTML>\n<HEAD>\n <BASE href='file:%s'>\n" + " <TITLE>file:%s</TITLE>\n</HEAD>\n" + "<BODY><H1>Directory listing of %s</H1>\n", + HUdirname, Hdirname, Hdirname); + dFree(Hdirname); + dFree(HUdirname); + dFree(Udirname); + + if (client->old_style) { + a_Dpip_dsh_write_str(client->sh, 0, "<pre>\n"); + } + + /* Output the parent directory */ + File_print_parent_dir(client, Ddir->dirname); + + /* HTML style toggle */ + a_Dpip_dsh_write_str(client->sh, 0, + " <a href='dpi:/file/toggle'>%</a>\n"); + + if (dList_length(Ddir->flist)) { + if (client->old_style) { + a_Dpip_dsh_write_str(client->sh, 0, "\n\n"); + } else { + a_Dpip_dsh_write_str(client->sh, 0, + "<br><br>\n" + "<table border=0 cellpadding=1 cellspacing=0" + " bgcolor=#E0E0E0 width=100%>\n" + "<tr align=center>\n" + "<td>\n" + "<td width=60%><b>Filename</b>" + "<td><b>Type</b>" + "<td><b>Size</b>" + "<td><b>Modified at</b>\n"); + } } else { - a_Dpip_dsh_write_str(Client->sh, 0, - "<br><br>\n" - "<table border=0 cellpadding=1 cellspacing=0" - " bgcolor=#E0E0E0 width=100%>\n" - "<tr align=center>\n" - "<td>\n" - "<td width=60%><b>Filename</b>" - "<td><b>Type</b>" - "<td><b>Size</b>" - "<td><b>Modified at</b>\n"); + a_Dpip_dsh_write_str(client->sh, 0, "<br><br>Directory is empty..."); } - } else { - a_Dpip_dsh_write_str(Client->sh, 0, "<br><br>Directory is empty..."); + client->state = st_http; + + } else if (client->state == st_http) { + /* send directories as HTML contents */ + for (n = 0; n < dList_length(Ddir->flist); ++n) { + File_info2html(client, dList_nth_data(Ddir->flist,n), n+1); + } + + if (dList_length(Ddir->flist)) { + if (client->old_style) { + a_Dpip_dsh_write_str(client->sh, 0, "</pre>\n"); + } else { + a_Dpip_dsh_write_str(client->sh, 0, "</table>\n"); + } + } + + a_Dpip_dsh_write_str(client->sh, 1, "</BODY></HTML>\n"); + client->state = st_content; + client->flags |= FILE_DONE; } - - /* Output entries */ - for (n = 0; n < dList_length(Ddir->flist); ++n) { - File_info2html(Client, dList_nth_data(Ddir->flist,n), n+1); - } - - if (dList_length(Ddir->flist)) { - if (Client->old_style) { - a_Dpip_dsh_write_str(Client->sh, 0, "</pre>\n"); - } else { - a_Dpip_dsh_write_str(Client->sh, 0, "</table>\n"); - } - } - - a_Dpip_dsh_write_str(Client->sh, 0, "</BODY></HTML>\n"); } /* @@ -522,70 +554,60 @@ /* * Send an error page */ -static void File_send_error_page(ClientInfo *Client, int res, - const char *orig_url) +static void File_prepare_send_error_page(ClientInfo *client, int res, + const char *orig_url) +{ + client->state = st_err; + client->err_code = res; + client->orig_url = dStrdup(orig_url); + client->flags &= ~FILE_READ; + client->flags |= FILE_WRITE; +} + +/* + * Send an error page + */ +static void File_send_error_page(ClientInfo *client) { const char *status; - const char *body; char *d_cmd; + Dstr *body = dStr_sized_new(128); - switch (res) { - case EACCES: + if (client->err_code == EACCES) { status = "403 Forbidden"; - break; - case ENOENT: + } else if (client->err_code == ENOENT) { status = "404 Not Found"; - break; - default: + } else { /* good enough */ status = "500 Internal Server Error"; } - - body = status; /* it's simple */ + dStr_append(body, status); + dStr_append(body, "\n"); + dStr_append(body, dStrerror(client->err_code)); /* Send DPI command */ - d_cmd = a_Dpip_build_cmd("cmd=%s url=%s", "start_send_page", orig_url); - a_Dpip_dsh_write_str(Client->sh, 1, d_cmd); + d_cmd = a_Dpip_build_cmd("cmd=%s url=%s", "start_send_page", + client->orig_url); + a_Dpip_dsh_write_str(client->sh, 0, d_cmd); dFree(d_cmd); - a_Dpip_dsh_printf(Client->sh, 0, + a_Dpip_dsh_printf(client->sh, 0, "HTTP/1.1 %s\r\n" "Content-Type: text/plain\r\n" - "Content-Length: %ld\r\n" + "Content-Length: %d\r\n" "\r\n" "%s", - status, strlen(body), body); + status, body->len, body->str); + dStr_free(body, TRUE); + + client->flags |= FILE_DONE; } /* - * Try to stat the file and determine if it's readable. + * Scan the directory, sort and prepare to send it enclosed in HTTP. */ -static void File_get(ClientInfo *Client, const char *filename, - const char *orig_url) -{ - int res; - struct stat sb; - - if (stat(filename, &sb) != 0) { - /* stat failed, prepare a file-not-found error. */ - res = ENOENT; - } else if (S_ISDIR(sb.st_mode)) { - /* set up for reading directory */ - res = File_get_dir(Client, filename, orig_url); - } else { - /* set up for reading a file */ - res = File_get_file(Client, filename, &sb, orig_url); - } - if (res != 0) { - File_send_error_page(Client, res, orig_url); - } -} - -/* - * - */ -static int File_get_dir(ClientInfo *Client, - const char *DirName, const char *orig_url) +static int File_prepare_send_dir(ClientInfo *client, + const char *DirName, const char *orig_url) { Dstr *ds_dirname; DilloDir *Ddir; @@ -599,89 +621,152 @@ Ddir = File_dillodir_new(ds_dirname->str); dStr_free(ds_dirname, TRUE); if (Ddir) { - File_transfer_dir(Client, Ddir, orig_url); - File_dillodir_free(Ddir); + /* looks ok, set things accordingly */ + client->orig_url = dStrdup(orig_url); + client->d_dir = Ddir; + client->state = st_start; + client->flags &= ~FILE_READ; + client->flags |= FILE_WRITE; return 0; } else return EACCES; } /* - * Send HTTP headers and then send the file itself. + * Prepare to send HTTP headers and then the file itself. */ -static int File_get_file(ClientInfo *Client, - const char *filename, - struct stat *sb, - const char *orig_url) +static int File_prepare_send_file(ClientInfo *client, + const char *filename, + const char *orig_url) +{ + int fd, res = -1; + struct stat sb; + + if (stat(filename, &sb) != 0) { + /* prepare a file-not-found error */ + res = ENOENT; + } else if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) < 0) { + /* prepare an error message */ + res = errno; + } else { + /* looks ok, set things accordingly */ + client->file_fd = fd; + client->file_sz = sb.st_size; + client->d_dir = NULL; + client->state = st_start; + client->filename = dStrdup(filename); + client->orig_url = dStrdup(orig_url); + client->flags &= ~FILE_READ; + client->flags |= FILE_WRITE; + res = 0; + } + return res; +} + +/* + * Try to stat the file and determine if it's readable. + */ +static void File_get(ClientInfo *client, const char *filename, + const char *orig_url) +{ + int res; + struct stat sb; + + if (stat(filename, &sb) != 0) { + /* stat failed, prepare a file-not-found error. */ + res = ENOENT; + } else if (S_ISDIR(sb.st_mode)) { + /* set up for reading directory */ + res = File_prepare_send_dir(client, filename, orig_url); + } else { + /* set up for reading a file */ + res = File_prepare_send_file(client, filename, orig_url); + } + if (res != 0) { + File_prepare_send_error_page(client, res, orig_url); + } +} + +/* + * Send HTTP headers and then the file itself. + */ +static int File_send_file(ClientInfo *client) { #define LBUF 16*1024 const char *ct; const char *unknown_type = "application/octet-stream"; char buf[LBUF], *d_cmd, *name; - int fd, st, namelen; + int st, namelen; bool_t gzipped = FALSE; - if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) < 0) - return errno; - - /* Send DPI command */ - d_cmd = a_Dpip_build_cmd("cmd=%s url=%s", "start_send_page", orig_url); - a_Dpip_dsh_write_str(Client->sh, 1, d_cmd); - dFree(d_cmd); + if (client->state == st_start) { + /* Send DPI command */ + d_cmd = a_Dpip_build_cmd("cmd=%s url=%s", "start_send_page", + client->orig_url); + a_Dpip_dsh_write_str(client->sh, 1, d_cmd); + dFree(d_cmd); + client->state = st_dpip; - /* Check for gzipped file */ - namelen = strlen(filename); - if (namelen > 3 && !dStrcasecmp(filename + namelen - 3, ".gz")) { - gzipped = TRUE; - namelen -= 3; - } + } else if (client->state == st_dpip) { + /* send HTTP header */ - /* Content-Type info is based on filename extension (with ".gz" removed). - * If there's no known extension, perform data sniffing. - * If this doesn't lead to a conclusion, use "application/octet-stream". - */ - name = dStrndup(filename, namelen); - if (!(ct = File_content_type(name))) - ct = unknown_type; - dFree(name); + /* Check for gzipped file */ + namelen = strlen(client->filename); + if (namelen > 3 && !dStrcasecmp(client->filename + namelen - 3, ".gz")) { + gzipped = TRUE; + namelen -= 3; + } + /* Content-Type info is based on filename extension (with ".gz" removed). + * If there's no known extension, perform data sniffing. + * If this doesn't lead to a conclusion, use "application/octet-stream". + */ + name = dStrndup(client->filename, namelen); + if (!(ct = File_content_type(name))) + ct = unknown_type; + dFree(name); + + /* Send HTTP headers */ + a_Dpip_dsh_write_str(client->sh, 0, "HTTP/1.1 200 OK\r\n"); + if (gzipped) { + a_Dpip_dsh_write_str(client->sh, 0, "Content-Encoding: gzip\r\n"); + } + if (!gzipped || strcmp(ct, unknown_type)) { + a_Dpip_dsh_printf(client->sh, 0, "Content-Type: %s\r\n", ct); + } else { + /* If we don't know type for gzipped data, let dillo figure it out. */ + } + a_Dpip_dsh_printf(client->sh, 1, + "Content-Length: %ld\r\n" + "\r\n", + client->file_sz); + client->state = st_http; - /* Send HTTP headers */ - a_Dpip_dsh_write_str(Client->sh, 0, "HTTP/1.1 200 OK\r\n"); - if (gzipped) { - a_Dpip_dsh_write_str(Client->sh, 0, "Content-Encoding: gzip\r\n"); + } else if (client->state == st_http) { + /* Send body -- raw file contents */ + do { + if ((st = read(client->file_fd, buf, LBUF)) > 0) { + if (a_Dpip_dsh_write(client->sh, 0, buf, (size_t)st) != 0) + break; + } else if (st < 0) { + perror("[read]"); + if (errno == EINTR || errno == EAGAIN) + continue; + } + } while (st > 0); + + /* TODO: It may be better to send an error report to dillo instead of + * calling exit() */ + if (st == -1) { + MSG("ERROR while reading from file \"%s\", error was \"%s\"\n", + client->filename, dStrerror(errno)); + exit(1); + } else if (st == 0) { + client->state = st_content; + File_close(client->file_fd); + client->flags |= FILE_DONE; + } } - if (!gzipped || strcmp(ct, unknown_type)) { - a_Dpip_dsh_printf(Client->sh, 0, "Content-Type: %s\r\n", ct); - } else { - /* If we don't know type for gzipped data, let dillo figure it out. */ - } - a_Dpip_dsh_printf(Client->sh, 0, - "Content-Length: %ld\r\n" - "\r\n", - sb->st_size); - - /* Send body -- raw file contents */ - do { - if ((st = read(fd, buf, LBUF)) > 0) { - if (a_Dpip_dsh_write(Client->sh, 0, buf, (size_t)st) != 0) - break; - } else if (st < 0) { - perror("[read]"); - if (errno == EINTR || errno == EAGAIN) - continue; - } - } while (st > 0); - - /* TODO: It may be better to send an error report to dillo instead of - * calling exit() */ - if (st == -1) { - MSG("ERROR while reading from file \"%s\", error was \"%s\"\n", - filename, dStrerror(errno)); - exit(1); - } - - File_close(fd); return 0; } @@ -714,6 +799,8 @@ { char *str = (char *) orig, *basename = NULL, *ret = NULL, *p; + dReturn_val_if (orig == NULL, ret); + /* Make sure the string starts with "file:/" */ if (strncmp(str, "file:/", 5) != 0) return ret; @@ -757,13 +844,13 @@ /* * Set the style flag and ask for a reload, so it shows immediately. */ -static void File_toggle_html_style(ClientInfo *Client) +static void File_toggle_html_style(ClientInfo *client) { char *d_cmd; OLD_STYLE = !OLD_STYLE; d_cmd = a_Dpip_build_cmd("cmd=%s", "reload_request"); - a_Dpip_dsh_write_str(Client->sh, 1, d_cmd); + a_Dpip_dsh_write_str(client->sh, 1, d_cmd); dFree(d_cmd); } @@ -783,182 +870,180 @@ */ static ClientInfo *File_add_client(int sock_fd) { - ClientInfo *NewClient; + ClientInfo *new_client; - NewClient = dNew(ClientInfo, 1); - NewClient->sh = a_Dpip_dsh_new(sock_fd, sock_fd, 8*1024); - NewClient->status = 0; - NewClient->done = 0; - NewClient->old_style = OLD_STYLE; - pthread_mutex_lock(&ClMut); - dList_append(Clients, NewClient); - pthread_mutex_unlock(&ClMut); - return NewClient; -} - -/* - * Get client record by number - */ -static void *File_get_client_n(uint_t n) -{ - void *client; - - pthread_mutex_lock(&ClMut); - client = dList_nth_data(Clients, n); - pthread_mutex_unlock(&ClMut); - - return client; + new_client = dNew(ClientInfo, 1); + new_client->sh = a_Dpip_dsh_new(sock_fd, sock_fd, 8*1024); + new_client->orig_url = NULL; + new_client->filename = NULL; + new_client->file_fd = -1; + new_client->file_sz = 0; + new_client->d_dir = NULL; + new_client->state = 0; + new_client->err_code = 0; + new_client->flags = FILE_READ; + new_client->old_style = OLD_STYLE; + dList_append(Clients, new_client); + return new_client; } /* * Remove a client from the list. */ -static void File_remove_client_n(uint_t n) +static void File_remove_client(ClientInfo *client) { - ClientInfo *Client; - - pthread_mutex_lock(&ClMut); - Client = dList_nth_data(Clients, n); - dList_remove(Clients, (void *)Client); - pthread_mutex_unlock(&ClMut); + dList_remove(Clients, (void *)client); _MSG("Closing Socket Handler\n"); - a_Dpip_dsh_close(Client->sh); - a_Dpip_dsh_free(Client->sh); - dFree(Client); -} + a_Dpip_dsh_close(client->sh); + a_Dpip_dsh_free(client->sh); + dFree(client->orig_url); + dFree(client->filename); + File_dillodir_free(client->d_dir); -/* - * Return the number of clients. - */ -static int File_num_clients(void) -{ - uint_t n; - - pthread_mutex_lock(&ClMut); - n = dList_length(Clients); - pthread_mutex_unlock(&ClMut); - - return n; + dFree(client); } /* * Serve this client. - * (this function runs on its own thread) */ -static void File_serve_client(void *data) +static void File_serve_client(void *data, int f_write) { char *dpip_tag = NULL, *cmd = NULL, *url = NULL, *path; - ClientInfo *Client = data; + ClientInfo *client = data; int st; - /* Authenticate our client... */ - do { - dpip_tag = a_Dpip_dsh_read_token(Client->sh); - } while (!dpip_tag && Client->sh->status == DPIP_EAGAIN); - _MSG("auth={%s}\n", dpip_tag); - st = a_Dpip_check_auth(dpip_tag); - dFree(dpip_tag); - _MSG("a_Dpip_check_auth returned %d\n", st); - dReturn_if (st == -1); - - /* Read the dpi command */ - do { - dpip_tag = a_Dpip_dsh_read_token(Client->sh); - } while (!dpip_tag && Client->sh->status == DPIP_EAGAIN); - _MSG("dpip_tag={%s}\n", dpip_tag); - - if (dpip_tag) { - cmd = a_Dpip_get_attr(dpip_tag, "cmd"); - if (cmd) { - if (strcmp(cmd, "DpiBye") == 0) { - DPIBYE = 1; - MSG("file.dpi:: (pid %d): Got DpiBye.\n", (int)getpid()); + while (1) { + MSG("File_serve_client %p, flags=%d\n", client, client->flags); + if (client->flags & (FILE_DONE | FILE_ERR)) + break; + if (client->flags & FILE_READ) { + dpip_tag = a_Dpip_dsh_read_token(client->sh, 0); + MSG("dpip_tag={%s}\n", dpip_tag); + if (!dpip_tag) + break; + } + + if (client->flags & FILE_READ) { + if (!(client->flags & FILE_AUTH_OK)) { + /* Authenticate our client... */ + st = a_Dpip_check_auth(dpip_tag); + MSG("a_Dpip_check_auth returned %d\n", st); + client->flags |= (st == 1) ? FILE_AUTH_OK : FILE_ERR; } else { + /* Get file request */ + cmd = a_Dpip_get_attr(dpip_tag, "cmd"); url = a_Dpip_get_attr(dpip_tag, "url"); - if (!url) - MSG("file.dpi:: Failed to parse 'url'\n"); + path = File_normalize_path(url); + if (cmd) { + if (strcmp(cmd, "DpiBye") == 0) { + DPIBYE = 1; + MSG("(pid %d): Got DpiBye.\n", (int)getpid()); + client->flags |= FILE_DONE; + } else if (url && strcmp(url, "dpi:/file/toggle") == 0) { + File_toggle_html_style(client); + } else if (path) { + File_get(client, path, url); + } else { + client->flags |= FILE_ERR; + MSG("ERROR: URL was %s\n", url); + } + } + dFree(path); + dFree(url); + dFree(cmd); + break; } - } - dFree(cmd); - } - dFree(dpip_tag); - - if (!DPIBYE && url) { - _MSG("url = '%s'\n", url); + dFree(dpip_tag); - path = File_normalize_path(url); - if (path) { - _MSG("path = '%s'\n", path); - File_get(Client, path, url); - } else if (strcmp(url, "dpi:/file/toggle") == 0) { - File_toggle_html_style(Client); - } else { - MSG("ERROR: URL path was %s\n", url); + } else if (f_write) { + /* send our answer */ + if (client->state == st_err) + File_send_error_page(client); + else if (client->d_dir) + File_send_dir(client); + else + File_send_file(client); + break; } - dFree(path); - } - dFree(url); + } /*while*/ - /* flag the the transfer finished */ - Client->done = 1; + client->flags |= (client->sh->status & DPIP_ERROR) ? FILE_ERR : 0; + client->flags |= (client->sh->status & DPIP_EOF) ? FILE_DONE : 0; } /* * Serve the client queue. - * (this function runs on its own thread) */ -static void *File_serve_clients(void *client) +static void File_serve_clients() { - /* switch to detached state */ - pthread_detach(pthread_self()); + int i, f_read, f_write; + ClientInfo *client; - while (File_num_clients()) { - client = File_get_client_n((uint_t)0); - File_serve_client(client); - File_remove_client_n((uint_t)0); + for (i = 0; (client = dList_nth_data(Clients, i)); ++i) { + f_read = FD_ISSET(client->sh->fd_in, &read_set); + f_write = FD_ISSET(client->sh->fd_out, &write_set); + if (!f_read && !f_write) + continue; + File_serve_client(client, f_write); + if (client->flags & (FILE_DONE | FILE_ERR)) { + File_remove_client(client); + --i; + } } - ThreadRunning = 0; - - return NULL; } /* --------------------------------------------------------------------------*/ /* - * Check a fd for activity, with a max timeout. + * Check the fd sets for activity, with a max timeout. * return value: 0 if timeout, 1 if input available, -1 if error. */ -static int File_check_fd(int filedes, uint_t seconds) +static int File_check_fds(uint_t seconds) { - int st; - fd_set set; - struct timeval timeout; + int i, st; + ClientInfo *client; + struct timeval timeout; - /* Initialize the file descriptor set. */ - FD_ZERO (&set); - FD_SET (filedes, &set); + /* initialize observed file descriptors */ + FD_ZERO (&read_set); + FD_ZERO (&write_set); + FD_SET (STDIN_FILENO, &read_set); + for (i = 0; (client = dList_nth_data(Clients, i)); ++i) { + if (client->flags & FILE_READ) + FD_SET (client->sh->fd_in, &read_set); + if (client->flags & FILE_WRITE) + FD_SET (client->sh->fd_out, &write_set); + } + MSG("Watching %d fds:", dList_length(Clients) + 1); - /* Initialize the timeout data structure. */ - timeout.tv_sec = seconds; - timeout.tv_usec = 0; + /* Initialize the timeout data structure. */ + timeout.tv_sec = seconds; + timeout.tv_usec = 0; - do { - st = select(FD_SETSIZE, &set, NULL, NULL, &timeout); - } while (st == -1 && errno == EINTR); + do { + st = select(FD_SETSIZE, &read_set, &write_set, NULL, &timeout); + } while (st == -1 && errno == EINTR); - return st; + MSG_RAW(" (%d%s%s)", STDIN_FILENO, + FD_ISSET(STDIN_FILENO, &read_set) ? "R" : "", + FD_ISSET(STDIN_FILENO, &write_set) ? "W" : ""); + for (i = 0; (client = dList_nth_data(Clients, i)); ++i) { + MSG_RAW(" (%d%s%s)", client->sh->fd_in, + FD_ISSET(client->sh->fd_in, &read_set) ? "R" : "", + FD_ISSET(client->sh->fd_out, &write_set) ? "W" : ""); + } + MSG_RAW("\n"); + + return st; } int main(void) { - ClientInfo *NewClient; - struct sockaddr_un spun; - int temp_sock_descriptor; + struct sockaddr_in sin; socklen_t address_size; - int c_st, st = 1; - uint_t i; + int tmp_fd, c_st, st = 1; /* Arrange the cleanup function for abnormal terminations */ if (signal (SIGINT, termination_handler) == SIG_IGN) @@ -968,57 +1053,46 @@ if (signal (SIGTERM, termination_handler) == SIG_IGN) signal (SIGTERM, SIG_IGN); - MSG("(v.1) accepting connections...\n"); + MSG("(v.2) accepting connections...\n"); - /* initialize mutex */ - pthread_mutex_init(&ClMut, NULL); + /* initialize observed file descriptors */ + FD_ZERO (&read_set); + FD_ZERO (&write_set); + FD_SET (STDIN_FILENO, &read_set); /* initialize Clients list */ Clients = dList_new(512); /* some OSes may need this... */ - address_size = sizeof(struct sockaddr_un); + address_size = sizeof(struct sockaddr_in); /* start the service loop */ while (!DPIBYE) { - /* wait for a connection */ + /* wait for activity */ do { - c_st = File_check_fd(STDIN_FILENO, 1); + c_st = File_check_fds(10); } while (c_st == 0 && !DPIBYE); if (c_st < 0) { - perror("[select]"); + MSG(" select() %s\n", dStrerror(errno)); break; } if (DPIBYE) break; - temp_sock_descriptor = - accept(STDIN_FILENO, (struct sockaddr *)&spun, &address_size); - - if (temp_sock_descriptor == -1) { - perror("[accept]"); - break; + if (FD_ISSET(STDIN_FILENO, &read_set)) { + /* accept the incoming connection */ + tmp_fd = accept(STDIN_FILENO, (struct sockaddr *)&sin, &address_size); + if (tmp_fd == -1) { + MSG(" accept() %s\n", dStrerror(errno)); + break; + } else { + /* Create and initialize a new client */ + File_add_client(tmp_fd); + } + continue; } - /* Create and initialize a new client */ - NewClient = File_add_client(temp_sock_descriptor); - - if (!ThreadRunning) { - ThreadRunning = 1; - /* Serve the client from a thread (avoids deadlocks) */ - if (pthread_create(&NewClient->thrID, NULL, - File_serve_clients, NewClient) != 0) { - perror("[pthread_create]"); - ThreadRunning = 0; - break; - } - } - } - - /* TODO: handle a running thread better. */ - for (i = 0; i < 5 && ThreadRunning; ++i) { - MSG("sleep i=%u", i); - sleep(i); + File_serve_clients(); } if (DPIBYE)
--- a/dpid/main.c Sun Nov 01 16:31:59 2009 -0300 +++ b/dpid/main.c Sun Nov 01 16:31:59 2009 -0300 @@ -117,9 +117,7 @@ char *dpip_tag; (void) sigprocmask(SIG_BLOCK, &mask_sigchld, NULL); - do { - dpip_tag = a_Dpip_dsh_read_token(sh); - } while (!dpip_tag && sh->status == DPIP_EAGAIN); + dpip_tag = a_Dpip_dsh_read_token(sh, 1); (void) sigprocmask(SIG_UNBLOCK, &mask_sigchld, NULL); return dpip_tag;
--- a/dpip/dpip.c Sun Nov 01 16:31:59 2009 -0300 +++ b/dpip/dpip.c Sun Nov 01 16:31:59 2009 -0300 @@ -22,6 +22,9 @@ #include "dpip.h" #include "d_size.h" +//#define RBUF_SZ 16384 +#define RBUF_SZ 1 + #define DPIP_TAG_END " '>" #define DPIP_MODE_SWITCH_TAG "cmd='start_send_page' " #define MSG_ERR(...) fprintf(stderr, "[dpip]: " __VA_ARGS__) @@ -292,27 +295,24 @@ } /* - * Read new data from the socket into our buffer. - * Used by both blocking and non-blocking IO. + * Read raw data from the socket into our buffer without blocking. */ -static void Dpip_dsh_read(Dsh *dsh) +static void Dpip_dsh_read_nb(Dsh *dsh) { -//#define LBUF_SZ 16384 -#define LBUF_SZ 1 - ssize_t st; int old_flags, blocking; - char buf[LBUF_SZ]; + char buf[RBUF_SZ]; blocking = !(dsh->mode & DPIP_NONBLOCK); if (blocking) { + /* set NONBLOCKING temporarily... */ old_flags = fcntl(dsh->fd_in, F_GETFL); + fcntl(dsh->fd_in, F_SETFL, O_NONBLOCK | old_flags); } while (1) { - /* can't use fread() */ do - st = read(dsh->fd_in, buf, LBUF_SZ); + st = read(dsh->fd_in, buf, RBUF_SZ); while (st < 0 && errno == EINTR); if (st < 0) { @@ -330,10 +330,6 @@ } else { /* append to buf */ dStr_append_l(dsh->rd_dbuf, buf, st); - if (blocking) { - /* set NONBLOCKING temporarily... */ - fcntl(dsh->fd_in, F_SETFL, O_NONBLOCK | old_flags); - } } } @@ -344,23 +340,73 @@ } /* + * Read raw data from the socket into our buffer in BLOCKING mode. + */ +static void Dpip_dsh_read(Dsh *dsh) +{ + + ssize_t st; + int old_flags, non_blocking; + char buf[RBUF_SZ]; + + non_blocking = (dsh->mode & DPIP_NONBLOCK); + if (non_blocking) { + /* set blocking mode temporarily */ + old_flags = fcntl(dsh->fd_in, F_GETFL); + fcntl(dsh->fd_in, F_SETFL, old_flags); + } + + while (1) { + do + st = read(dsh->fd_in, buf, RBUF_SZ); + while (st < 0 && errno == EINTR); + + if (st < 0) { + MSG_ERR("[Dpip_dsh_read] %s\n", dStrerror(errno)); + dsh->status = DPIP_ERROR; + break; + } else if (st == 0) { + dsh->status = DPIP_EOF; + break; + } else { + /* append to buf */ + dStr_append_l(dsh->rd_dbuf, buf, st); + break; + } + } + + if (non_blocking) { + /* restore non blocking mode */ + fcntl(dsh->fd_in, F_SETFL, old_flags); + } + + /* assert there's no more data in the wire... */ + Dpip_dsh_read_nb(dsh); +} + +/* * Return a newlly allocated string with the next dpip token in the socket. * Return value: token string on success, NULL otherwise */ -char *a_Dpip_dsh_read_token(Dsh *dsh) +char *a_Dpip_dsh_read_token(Dsh *dsh, int blocking) { char *p, *ret = NULL; + /* Read all available data without blocking */ + Dpip_dsh_read_nb(dsh); + /* switch mode upon request */ if (dsh->mode & DPIP_LAST_TAG) dsh->mode = DPIP_RAW; - /* Only read from socket when there's no data in buffer or - * the tag is incomplete */ - if (dsh->rd_dbuf->len == 0 || - (dsh->mode & DPIP_TAG && - !(p = strstr(dsh->rd_dbuf->str, DPIP_TAG_END)))) { - Dpip_dsh_read(dsh); + if (blocking && dsh->mode & DPIP_TAG) { + /* Only wait for data when the tag is incomplete */ + if (!strstr(dsh->rd_dbuf->str, DPIP_TAG_END)) { + do { + Dpip_dsh_read(dsh); + p = strstr(dsh->rd_dbuf->str, DPIP_TAG_END); + } while (!p && dsh->status == EAGAIN); + } } if (dsh->mode & DPIP_TAG) {
--- a/dpip/dpip.h Sun Nov 01 16:31:59 2009 -0300 +++ b/dpip/dpip.h Sun Nov 01 16:31:59 2009 -0300 @@ -68,7 +68,7 @@ Dsh *a_Dpip_dsh_new(int fd_in, int fd_out, int flush_sz); int a_Dpip_dsh_write(Dsh *dsh, int flush, const char *Data, int DataSize); int a_Dpip_dsh_write_str(Dsh *dsh, int flush, const char *str); -char *a_Dpip_dsh_read_token(Dsh *dsh); +char *a_Dpip_dsh_read_token(Dsh *dsh, int blocking); void a_Dpip_dsh_close(Dsh *dsh); void a_Dpip_dsh_free(Dsh *dsh);