Initial commit
commit
9372e41393
@ -0,0 +1,3 @@
|
||||
build
|
||||
.lock-wscript
|
||||
.waf-*
|
@ -0,0 +1,14 @@
|
||||
#ifndef _LIGHTTPD_BASE_H_
|
||||
#define _LIGHTTPD_BASE_H_
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
#define CONST_STR_LEN(x) x, x ? sizeof(x) - 1 : 0
|
||||
|
||||
struct server;
|
||||
typedef struct server server;
|
||||
|
||||
struct connection;
|
||||
typedef struct connection connection;
|
||||
|
||||
#endif
|
@ -0,0 +1,436 @@
|
||||
|
||||
#include "base.h"
|
||||
#include "chunks.h"
|
||||
#include "log.h"
|
||||
|
||||
/******************
|
||||
* chunkfile *
|
||||
******************/
|
||||
|
||||
static chunkfile *chunkfile_new(GString *name, int fd, gboolean is_temp) {
|
||||
chunkfile *cf = g_slice_new(chunkfile);
|
||||
cf->refcount = 1;
|
||||
cf->name = name;
|
||||
cf->fd = fd;
|
||||
cf->is_temp = is_temp;
|
||||
return cf;
|
||||
}
|
||||
|
||||
static void chunkfile_acquire(chunkfile *cf) {
|
||||
// assert(cf->refcount > 0)
|
||||
cf->refcount++;
|
||||
}
|
||||
|
||||
static void chunkfile_release(chunkfile *cf) {
|
||||
// assert(cf->refcount > 0)
|
||||
if (!(--cf->refcount)) {
|
||||
if (-1 != cf->fd) close(cf->fd);
|
||||
cf->fd = -1;
|
||||
if (cf->is_temp) unlink(cf->name->str);
|
||||
cf->is_temp = FALSE;
|
||||
g_string_free(cf->name, TRUE);
|
||||
cf->name = NULL;
|
||||
g_slice_free(chunkfile, cf);
|
||||
}
|
||||
}
|
||||
|
||||
/* open the file cf->name if it is not already opened for reading
|
||||
* may return HANDLER_GO_ON, HANDLER_ERROR, HANDLER_WAIT_FOR_FD
|
||||
*/
|
||||
handler_t chunkfile_open(server *srv, connection *con, chunkfile *cf) {
|
||||
if (!cf) return HANDLER_ERROR;
|
||||
if (-1 != cf->fd) return HANDLER_GO_ON;
|
||||
if (!cf->name) {
|
||||
CON_ERROR(srv, con, "%s", "Missing filename for FILE_CHUNK");
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
if (-1 == (cf->fd = open(cf->name->str, O_RDONLY))) {
|
||||
if (EMFILE == errno) return HANDLER_WAIT_FOR_FD;
|
||||
CON_ERROR(srv, con, "Couldn't open file '%s': %s (%i)", cf->name->str, strerror(errno), errno);
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
#ifdef FD_CLOEXEC
|
||||
fcntl(cf->fd, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
return HANDLER_GO_ON;
|
||||
}
|
||||
|
||||
/******************
|
||||
* chunk iterator *
|
||||
******************/
|
||||
|
||||
/* must be powers of 2 */
|
||||
#define MAX_MMAP_CHUNK (2*1024*1024)
|
||||
#define MMAP_CHUNK_ALIGN (4*1024)
|
||||
|
||||
/* get the data from a chunk; easy in case of a MEM_CHUNK,
|
||||
* but needs to do io in case of FILE_CHUNK; it tries mmap and
|
||||
* falls back to read(...)
|
||||
* the data is _not_ marked as "done"
|
||||
* may return HANDLER_GO_ON, HANDLER_ERROR, HANDLER_WAIT_FOR_FD
|
||||
*/
|
||||
handler_t chunkiter_read(server *srv, connection *con, chunkiter iter, off_t start, off_t length, char **data_start, off_t *data_len) {
|
||||
chunk *c = chunkiter_chunk(iter);
|
||||
off_t we_want, we_have, our_start, our_offset;
|
||||
handler_t res = HANDLER_GO_ON;
|
||||
int mmap_errno = 0;
|
||||
|
||||
if (!c) return HANDLER_ERROR;
|
||||
if (!data_start || !data_len) return HANDLER_ERROR;
|
||||
|
||||
if (HANDLER_GO_ON != (res = chunkfile_open(srv, con, c->file.file))) return res;
|
||||
|
||||
we_have = chunk_length(c) - start;
|
||||
if (length > we_have) length = we_have;
|
||||
if (length <= 0) return HANDLER_ERROR;
|
||||
|
||||
switch (c->type) {
|
||||
case UNUSED_CHUNK: return HANDLER_ERROR;
|
||||
case MEM_CHUNK:
|
||||
*data_start = c->mem->str + c->offset + start;
|
||||
*data_len = length;
|
||||
break;
|
||||
case FILE_CHUNK:
|
||||
if ( !(c->file.mmap.data != MAP_FAILED || c->mem) /* no data present */
|
||||
|| !( /* or in the wrong range */
|
||||
(start + c->offset >= c->file.mmap.offset)
|
||||
&& (start + c->offset + length <= c->file.mmap.offset + c->file.mmap.length)) ) {
|
||||
/* then find new range */
|
||||
our_offset = start % MMAP_CHUNK_ALIGN;
|
||||
our_start = start - our_offset;
|
||||
|
||||
if (length > MAX_MMAP_CHUNK) length = MAX_MMAP_CHUNK;
|
||||
we_want = length + MAX_MMAP_CHUNK;
|
||||
if (we_want > we_have) we_want = we_have;
|
||||
we_want += our_offset;
|
||||
|
||||
if (MAP_FAILED != c->file.mmap.data) {
|
||||
munmap(c->file.mmap.data, c->file.mmap.length);
|
||||
c->file.mmap.data = MAP_FAILED;
|
||||
}
|
||||
c->file.mmap.offset = our_offset;
|
||||
c->file.mmap.length = we_want;
|
||||
if (!c->mem) { /* mmap did not fail till now */
|
||||
c->file.mmap.data = mmap(0, we_want, PROT_READ, MAP_SHARED, c->file.file->fd, our_offset);
|
||||
mmap_errno = errno;
|
||||
}
|
||||
if (MAP_FAILED == c->file.mmap.data) {
|
||||
/* fallback to read(...) */
|
||||
if (!c->mem) {
|
||||
c->mem = g_string_sized_new(we_want);
|
||||
} else {
|
||||
g_string_set_size(c->mem, we_want);
|
||||
}
|
||||
if (-1 == lseek(c->file.file->fd, our_offset, SEEK_SET)) {
|
||||
/* prefer the error of the first syscall */
|
||||
if (0 != mmap_errno) {
|
||||
CON_ERROR(srv, con, "mmap failed for '%s' (fd = %i): %s (%i)",
|
||||
c->file.file->name->str, c->file.file->fd,
|
||||
strerror(mmap_errno), mmap_errno);
|
||||
} else {
|
||||
CON_ERROR(srv, con, "lseek failed for '%s' (fd = %i): %s (%i)",
|
||||
c->file.file->name->str, c->file.file->fd,
|
||||
strerror(errno), errno);
|
||||
}
|
||||
g_string_free(c->mem, TRUE);
|
||||
c->mem = NULL;
|
||||
return HANDLER_ERROR;
|
||||
}
|
||||
read_chunk:
|
||||
if (-1 == (we_have = read(c->file.file->fd, c->mem->str, we_want))) {
|
||||
if (EINTR == errno) goto read_chunk;
|
||||
/* prefer the error of the first syscall */
|
||||
if (0 != mmap_errno) {
|
||||
CON_ERROR(srv, con, "mmap failed for '%s' (fd = %i): %s (%i)",
|
||||
c->file.file->name->str, c->file.file->fd,
|
||||
strerror(mmap_errno), mmap_errno);
|
||||
} else {
|
||||
CON_ERROR(srv, con, "read failed for '%s' (fd = %i): %s (%i)",
|
||||
c->file.file->name->str, c->file.file->fd,
|
||||
strerror(errno), errno);
|
||||
}
|
||||
g_string_free(c->mem, TRUE);
|
||||
c->mem = NULL;
|
||||
return HANDLER_ERROR;
|
||||
} else if (we_have != we_want) {
|
||||
/* may return less than requested bytes due to signals */
|
||||
/* CON_TRACE(srv, con, "read return unexpected number of bytes"); */
|
||||
we_want = we_have;
|
||||
if (length > we_have) length = we_have;
|
||||
c->file.mmap.length = we_want;
|
||||
g_string_set_size(c->mem, we_want);
|
||||
}
|
||||
} else {
|
||||
#ifdef HAVE_MADVISE
|
||||
/* don't advise files < 64Kb */
|
||||
if (c->file.mmap.length > (64*1024) &&
|
||||
0 != madvise(c->file.mmap.data, c->file.mmap.length, MADV_WILLNEED)) {
|
||||
CON_ERROR(srv, con, "madvise failed for '%s' (fd = %i): %s (%i)",
|
||||
c->file.file->name->str, c->file.file->fd,
|
||||
strerror(errno), errno);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
*data_start = (c->mem ? c->mem->str : c->file.mmap.data) + start + c->offset - c->file.mmap.offset;
|
||||
*data_len = length;
|
||||
break;
|
||||
}
|
||||
return HANDLER_GO_ON;
|
||||
}
|
||||
|
||||
/******************
|
||||
* chunk *
|
||||
******************/
|
||||
|
||||
static chunk* chunk_new() {
|
||||
chunk *c = g_slice_new0(chunk);
|
||||
c->file.mmap.data = MAP_FAILED;
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
static void chunk_reset(chunk *c) {
|
||||
if (!c) return;
|
||||
c->type = UNUSED_CHUNK;
|
||||
c->offset = 0;
|
||||
if (c->mem) g_string_free(c->mem, TRUE);
|
||||
c->mem = NULL;
|
||||
if (c->file.file) chunkfile_release(c->file.file);
|
||||
c->file.file = NULL;
|
||||
c->file.start = 0;
|
||||
c->file.length = 0;
|
||||
if (MAP_FAILED != c->file.mmap.data) munmap(c->file.mmap.data, c->file.mmap.length);
|
||||
c->file.mmap.data = MAP_FAILED;
|
||||
c->file.mmap.length = 0;
|
||||
c->file.mmap.offset = 0;
|
||||
}
|
||||
*/
|
||||
|
||||
static void chunk_free(chunk *c) {
|
||||
if (!c) return;
|
||||
c->type = UNUSED_CHUNK;
|
||||
if (c->mem) g_string_free(c->mem, TRUE);
|
||||
c->mem = NULL;
|
||||
if (c->file.file) chunkfile_release(c->file.file);
|
||||
c->file.file = NULL;
|
||||
if (c->file.mmap.data) munmap(c->file.mmap.data, c->file.mmap.length);
|
||||
c->file.mmap.data = NULL;
|
||||
g_slice_free(chunk, c);
|
||||
}
|
||||
|
||||
/******************
|
||||
* chunkqueue *
|
||||
******************/
|
||||
|
||||
chunkqueue* chunkqueue_new() {
|
||||
chunkqueue *cq = g_slice_new0(chunkqueue);
|
||||
cq->queue = g_queue_new();
|
||||
return cq;
|
||||
}
|
||||
|
||||
static void __chunk_free(gpointer c, gpointer UNUSED_PARAM(userdata)) {
|
||||
chunk_free((chunk*) c);
|
||||
}
|
||||
|
||||
void chunkqueue_reset(chunkqueue *cq) {
|
||||
if (!cq) return;
|
||||
cq->is_closed = FALSE;
|
||||
cq->bytes_in = cq->bytes_out = cq->length = 0;
|
||||
g_queue_foreach(cq->queue, __chunk_free, NULL);
|
||||
g_queue_clear(cq->queue);
|
||||
}
|
||||
|
||||
void chunkqueue_free(chunkqueue *cq) {
|
||||
if (!cq) return;
|
||||
g_queue_foreach(cq->queue, __chunk_free, NULL);
|
||||
g_queue_free(cq->queue);
|
||||
cq->queue = NULL;
|
||||
g_slice_free(chunkqueue, cq);
|
||||
}
|
||||
|
||||
/* pass ownership of str to chunkqueue, do not free/modify it afterwards
|
||||
* you may modify the data (not the length) if you are sure it isn't sent before.
|
||||
*/
|
||||
void chunkqueue_append_string(chunkqueue *cq, GString *str) {
|
||||
chunk *c = chunk_new();
|
||||
c->type = MEM_CHUNK;
|
||||
c->mem = str;
|
||||
g_queue_push_tail(cq->queue, c);
|
||||
cq->length += str->len;
|
||||
cq->bytes_in += str->len;
|
||||
}
|
||||
|
||||
/* memory gets copied */
|
||||
void chunkqueue_append_mem(chunkqueue *cq, void *mem, gssize len) {
|
||||
chunk *c = chunk_new();
|
||||
c->type = MEM_CHUNK;
|
||||
c->mem = g_string_new_len(mem, len);
|
||||
g_queue_push_tail(cq->queue, c);
|
||||
cq->length += c->mem->len;
|
||||
cq->bytes_in += c->mem->len;
|
||||
}
|
||||
|
||||
static void __chunkqueue_append_file(chunkqueue *cq, GString *filename, off_t start, off_t length, int fd, gboolean is_temp) {
|
||||
chunk *c = chunk_new();
|
||||
c->file.file = chunkfile_new(filename, fd, is_temp);
|
||||
c->file.start = start;
|
||||
c->file.length = length;
|
||||
|
||||
g_queue_push_tail(cq->queue, c);
|
||||
cq->length += length;
|
||||
cq->bytes_in += length;
|
||||
}
|
||||
/* pass ownership of filename, do not free it */
|
||||
void chunkqueue_append_file(chunkqueue *cq, GString *filename, off_t start, off_t length) {
|
||||
__chunkqueue_append_file(cq, filename, start, length, -1, FALSE);
|
||||
}
|
||||
|
||||
/* if you already opened the file, you can pass the fd here - do not close it */
|
||||
void chunkqueue_append_file_fd(chunkqueue *cq, GString *filename, off_t start, off_t length, int fd) {
|
||||
__chunkqueue_append_file(cq, filename, start, length, fd, FALSE);
|
||||
}
|
||||
|
||||
/* temp files get deleted after usage */
|
||||
/* pass ownership of filename, do not free it */
|
||||
void chunkqueue_append_tempfile(chunkqueue *cq, GString *filename, off_t start, off_t length) {
|
||||
__chunkqueue_append_file(cq, filename, start, length, -1, TRUE);
|
||||
}
|
||||
|
||||
/* if you already opened the file, you can pass the fd here - do not close it */
|
||||
void chunkqueue_append_tempfile_fd(chunkqueue *cq, GString *filename, off_t start, off_t length, int fd) {
|
||||
__chunkqueue_append_file(cq, filename, start, length, fd, TRUE);
|
||||
}
|
||||
|
||||
/* steal up to length bytes from in and put them into out, return number of bytes stolen */
|
||||
goffset chunkqueue_steal_len(chunkqueue *out, chunkqueue *in, goffset length) {
|
||||
chunk *c, *cnew;
|
||||
GList* l;
|
||||
goffset bytes = 0;
|
||||
goffset we_have;
|
||||
|
||||
while ( (NULL != (c = chunkqueue_first_chunk(in))) && length > 0 ) {
|
||||
we_have = chunk_length(c);
|
||||
if (!we_have) { /* remove empty chunks */
|
||||
chunk_free(c);
|
||||
g_queue_pop_head(in->queue);
|
||||
continue;
|
||||
}
|
||||
if (we_have <= length) { /* move complete chunk */
|
||||
l = g_queue_pop_head_link(in->queue);
|
||||
g_queue_push_tail_link(out->queue, l);
|
||||
bytes += we_have;
|
||||
length -= we_have;
|
||||
} else { /* copy first part of a chunk */
|
||||
cnew = chunk_new();
|
||||
switch (c->type) {
|
||||
case UNUSED_CHUNK: /* impossible, has length 0 */
|
||||
/* remove "empty" chunks */
|
||||
chunk_free(c);
|
||||
chunk_free(cnew);
|
||||
g_queue_pop_head(in->queue);
|
||||
continue;
|
||||
case MEM_CHUNK:
|
||||
cnew->type = MEM_CHUNK;
|
||||
cnew->mem = g_string_new_len(c->mem->str + c->offset, length);
|
||||
break;
|
||||
case FILE_CHUNK:
|
||||
cnew->type = FILE_CHUNK;
|
||||
chunkfile_acquire(c->file.file);
|
||||
cnew->file.file = c->file.file;
|
||||
cnew->file.start = c->file.start + c->offset;
|
||||
cnew->file.length = length;
|
||||
break;
|
||||
}
|
||||
c->offset += length;
|
||||
bytes += length;
|
||||
length = 0;
|
||||
g_queue_push_tail(out->queue, cnew);
|
||||
}
|
||||
}
|
||||
|
||||
in->bytes_out += bytes;
|
||||
in->length -= bytes;
|
||||
out->bytes_in += bytes;
|
||||
out->length += bytes;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/* steal all chunks from in and put them into out, return number of bytes stolen */
|
||||
goffset chunkqueue_steal_all(chunkqueue *out, chunkqueue *in) {
|
||||
/* if in->queue is empty, do nothing */
|
||||
if (!in->length) return 0;
|
||||
/* if out->queue is empty, just swap in->queue/out->queue */
|
||||
if (g_queue_is_empty(out->queue)) {
|
||||
GQueue *tmp = in->queue; in->queue = out->queue; out->queue = tmp;
|
||||
} else {
|
||||
/* link the two "lists", neither of them is empty */
|
||||
out->queue->tail->next = in->queue->head;
|
||||
in->queue->head->prev = out->queue->tail;
|
||||
/* update the queue tail and length */
|
||||
out->queue->tail = in->queue->tail;
|
||||
out->queue->length += in->queue->length;
|
||||
/* reset in->queue) */
|
||||
g_queue_init(in->queue);
|
||||
}
|
||||
/* count bytes in chunkqueues */
|
||||
goffset len = in->length;
|
||||
in->bytes_out += len;
|
||||
in->length = 0;
|
||||
out->bytes_in += len;
|
||||
out->length += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
/* steal the first chunk from in and append it to out, return number of bytes stolen */
|
||||
goffset chunkqueue_steal_chunk(chunkqueue *out, chunkqueue *in) {
|
||||
goffset length;
|
||||
GList *l = g_queue_pop_head_link(in->queue);
|
||||
if (!l) return 0;
|
||||
g_queue_push_tail_link(out->queue, l);
|
||||
|
||||
length = chunk_length((chunk*) l->data);
|
||||
in->bytes_out += length;
|
||||
in->length -= length;
|
||||
out->bytes_in += length;
|
||||
out->length += length;
|
||||
return length;
|
||||
}
|
||||
|
||||
/* skip up to length bytes in a chunkqueue, return number of bytes skipped */
|
||||
goffset chunkqueue_skip(chunkqueue *cq, goffset length) {
|
||||
chunk *c;
|
||||
goffset bytes = 0;
|
||||
goffset we_have;
|
||||
|
||||
while ( (NULL != (c = chunkqueue_first_chunk(cq))) && length > 0 ) {
|
||||
we_have = chunk_length(c);
|
||||
if (we_have <= length) {
|
||||
/* skip (delete) complete chunk */
|
||||
chunk_free(c);
|
||||
g_queue_pop_head(cq->queue);
|
||||
bytes += we_have;
|
||||
length -= we_have;
|
||||
} else { /* skip first part of a chunk */
|
||||
c->offset += length;
|
||||
bytes += length;
|
||||
length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
cq->bytes_out += bytes;
|
||||
cq->length -= bytes;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
goffset chunkqueue_skip_all(chunkqueue *cq) {
|
||||
goffset bytes = cq->length;
|
||||
|
||||
g_queue_foreach(cq->queue, __chunk_free, NULL);
|
||||
g_queue_clear(cq->queue);
|
||||
|
||||
cq->bytes_out += bytes;
|
||||
cq->length = 0;
|
||||
|
||||
return bytes;
|
||||
}
|
@ -0,0 +1,191 @@
|
||||
#ifndef _LIGHTTPD_CHUNK_H_
|
||||
#define _LIGHTTPD_CHUNK_H_
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
struct chunkfile;
|
||||
typedef struct chunkfile chunkfile;
|
||||
|
||||
struct chunk;
|
||||
typedef struct chunk chunk;
|
||||
|
||||
struct chunkqueue;
|
||||
typedef struct chunkqueue chunkqueue;
|
||||
|
||||
struct chunkiter;
|
||||
typedef struct chunkiter chunkiter;
|
||||
|
||||
#include "base.h"
|
||||
|
||||
/* Open a file only once, so it shouldn't get lost;
|
||||
* as a file may get split into many chunks, we
|
||||
* use this struct to keep track of the usage
|
||||
*/
|
||||
struct chunkfile {
|
||||
gint refcount;
|
||||
|
||||
GString *name; /* name of the file */
|
||||
int fd;
|
||||
gboolean is_temp; /* file is temporary and will be deleted on cleanup */
|
||||
};
|
||||
|
||||
struct chunk {
|
||||
enum { UNUSED_CHUNK, MEM_CHUNK, FILE_CHUNK } type;
|
||||
|
||||
goffset offset;
|
||||
/* if type == FILE_CHUNK and mem != NULL,
|
||||
* mem contains the data [file.mmap.offset .. file.mmap.offset + file.mmap.length)
|
||||
* from the file, and file.mmap.start is NULL as mmap failed and read(...) was used.
|
||||
*/
|
||||
GString *mem;
|
||||
|
||||
struct {
|
||||
chunkfile *file;
|
||||
off_t start; /* starting offset in the file */
|
||||
off_t length; /* octets to send from the starting offset */
|
||||
|
||||
struct {
|
||||
char *data; /* the pointer of the mmap'ed area */
|
||||
size_t length; /* size of the mmap'ed area */
|
||||
off_t offset; /* start is <n> octets away from the start of the file */
|
||||
} mmap;
|
||||
} file;
|
||||
};
|
||||
|
||||
struct chunkqueue {
|
||||
/* public */
|
||||
gboolean is_closed;
|
||||
/* read only */
|
||||
goffset bytes_in, bytes_out, length;
|
||||
/* private */
|
||||
GQueue *queue;
|
||||
};
|
||||
|
||||
struct chunkiter {
|
||||
/* private */
|
||||
GList *element;
|
||||
};
|
||||
|
||||
/******************
|
||||
* chunkfile *
|
||||
******************/
|
||||
|
||||
/* open the file cf->name if it is not already opened for reading
|
||||
* may return HANDLER_GO_ON, HANDLER_ERROR, HANDLER_WAIT_FOR_FD
|
||||
*/
|
||||
handler_t chunkfile_open(server *srv, connection *con, chunkfile *cf);
|
||||
|
||||
/******************
|
||||
* chunk iterator *
|
||||
******************/
|
||||
|
||||
INLINE chunk* chunkiter_chunk(chunkiter iter);
|
||||
INLINE gboolean chunkiter_next(chunkiter *iter);
|
||||
INLINE goffset chunkiter_length(chunkiter iter);
|
||||
|
||||
/* get the data from a chunk; easy in case of a MEM_CHUNK,
|
||||
* but needs to do io in case of FILE_CHUNK; it tries mmap and
|
||||
* falls back to read(...)
|
||||
* the data is _not_ marked as "done"
|
||||
* may return HANDLER_GO_ON, HANDLER_ERROR, HANDLER_WAIT_FOR_FD
|
||||
*/
|
||||
handler_t chunkiter_read(server *srv, connection *con, chunkiter iter, off_t start, off_t length, char **data_start, off_t *data_len);
|
||||
|
||||
/******************
|
||||
* chunk *
|
||||
******************/
|
||||
|
||||
INLINE goffset chunk_length(chunk *c);
|
||||
|
||||
/******************
|
||||
* chunkqueue *
|
||||
******************/
|
||||
|
||||
chunkqueue* chunkqueue_new();
|
||||
void chunkqueue_reset(chunkqueue *cq);
|
||||
void chunkqueue_free(chunkqueue *cq);
|
||||
|
||||
/* pass ownership of str to chunkqueue, do not free/modify it afterwards
|
||||
* you may modify the data (not the length) if you are sure it isn't sent before.
|
||||
*/
|
||||
void chunkqueue_append_string(chunkqueue *cq, GString *str);
|
||||
|
||||
/* memory gets copied */
|
||||
void chunkqueue_append_mem(chunkqueue *cq, void *mem, gssize len);
|
||||
|
||||
/* pass ownership of filename, do not free it */
|
||||
void chunkqueue_append_file(chunkqueue *cq, GString *filename, off_t start, off_t length);
|
||||
/* if you already opened the file, you can pass the fd here - do not close it */
|
||||
void chunkqueue_append_file_fd(chunkqueue *cq, GString *filename, off_t start, off_t length, int fd);
|
||||
|
||||
/* temp files get deleted after usage */
|
||||
/* pass ownership of filename, do not free it */
|
||||
void chunkqueue_append_tempfile(chunkqueue *cq, GString *filename, off_t start, off_t length);
|
||||
/* if you already opened the file, you can pass the fd here - do not close it */
|
||||
void chunkqueue_append_tempfile_fd(chunkqueue *cq, GString *filename, off_t start, off_t length, int fd);
|
||||
|
||||
|
||||
/* steal up to length bytes from in and put them into out, return number of bytes stolen */
|
||||
goffset chunkqueue_steal_len(chunkqueue *out, chunkqueue *in, goffset length);
|
||||
|
||||
/* steal all chunks from in and put them into out, return number of bytes stolen */
|
||||
goffset chunkqueue_steal_all(chunkqueue *out, chunkqueue *in);
|
||||
|
||||
/* steal the first chunk from in and append it to out, return number of bytes stolen */
|
||||
goffset chunkqueue_steal_chunk(chunkqueue *out, chunkqueue *in);
|
||||
|
||||
/* skip up to length bytes in a chunkqueue, return number of bytes skipped */
|
||||
goffset chunkqueue_skip(chunkqueue *cq, goffset length);
|
||||
|
||||
/* skip all chunks in a queue (similar to reset, but keeps stats) */
|
||||
goffset chunkqueue_skip_all(chunkqueue *cq);
|
||||
|
||||
/* if the chunk an iterator refers gets stolen/skipped/...,
|
||||
* the iterator isn't valid anymore
|
||||
*/
|
||||
INLINE chunkiter chunkqueue_iter(chunkqueue *cq);
|
||||
|
||||
INLINE chunk* chunkqueue_first_chunk(chunkqueue *cq);
|
||||
|
||||
/********************
|
||||
* Inline functions *
|
||||
********************/
|
||||
|
||||
INLINE chunk* chunkiter_chunk(chunkiter iter) {
|
||||
if (!iter.element) return NULL;
|
||||
return (chunk*) iter.element->data;
|
||||
}
|
||||
|
||||
INLINE gboolean chunkiter_next(chunkiter *iter) {
|
||||
if (!iter || !iter->element) return FALSE;
|
||||
return NULL != (iter->element = g_list_next(iter->element));
|
||||
}
|
||||
|
||||
INLINE goffset chunkiter_length(chunkiter iter) {
|
||||
return chunk_length(chunkiter_chunk(iter));
|
||||
}
|
||||
|
||||
INLINE goffset chunk_length(chunk *c) {
|
||||
if (!c) return 0;
|
||||
switch (c->type) {
|
||||
case UNUSED_CHUNK:
|
||||
return 0;
|
||||
case MEM_CHUNK:
|
||||
return c->mem->len - c->offset;
|
||||
case FILE_CHUNK:
|
||||
return c->file.length - c->offset;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
INLINE chunkiter chunkqueue_iter(chunkqueue *cq) {
|
||||
chunkiter i;
|
||||
i.element = g_queue_peek_head_link(cq->queue);
|
||||
return i;
|
||||
}
|
||||
|
||||
INLINE chunk* chunkqueue_first_chunk(chunkqueue *cq) {
|
||||
return (chunk*) g_queue_peek_head(cq->queue);
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,31 @@
|
||||
|
||||
#include "log.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
#if REMOVE_PATH_FROM_FILE
|
||||
const char *remove_path(const char *path) {
|
||||
char *p = strrchr(path, DIR_SEPERATOR);
|
||||
if (NULL != p && *(p) != '\0') {
|
||||
return (p + 1);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
#endif
|
||||
|
||||
int log_write(server* UNUSED_PARAM(srv), connection* UNUSED_PARAM(con), const char *fmt, ...) {
|
||||
va_list ap;
|
||||
GString *logline;
|
||||
|
||||
logline = g_string_sized_new(0);
|
||||
va_start(ap, fmt);
|
||||
g_string_vprintf(logline, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
|
||||
g_string_append_len(logline, CONST_STR_LEN("\r\n"));
|
||||
write(STDERR_FILENO, logline->str, logline->len);
|
||||
g_string_free(logline, TRUE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,48 @@
|
||||
#ifndef _LIGHTTPD_LOG_H_
|
||||
#define _LIGHTTPD_LOG_H_
|
||||
|
||||
/* #include "valgrind/valgrind.h" */
|
||||
#include "base.h"
|
||||
|
||||
#define REMOVE_PATH_FROM_FILE 1
|
||||
#if REMOVE_PATH_FROM_FILE
|
||||
LI_API const char *remove_path(const char *path);
|
||||
#define REMOVE_PATH(file) remove_path(file)
|
||||
#else
|
||||
#define REMOVE_PATH(file) file
|
||||
#endif
|
||||
|
||||
|
||||
#define ERROR(fmt, ...) \
|
||||
log_write(NULL, NULL, "%s.%d: (error) "fmt, REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__)
|
||||
|
||||
#define TRACE(fmt, ...) \
|
||||
log_write(NULL, NULL, "%s.%d: (trace) "fmt, REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__)
|
||||
|
||||
#define SEGFAULT(fmt, ...) \
|
||||
do { \
|
||||
log_write(NULL, NULL, "%s.%d: (crashing) "fmt, REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__); \
|
||||
/* VALGRIND_PRINTF_BACKTRACE(fmt, __VA_ARGS__); */\
|
||||
abort();\
|
||||
} while(0)
|
||||
|
||||
#define CON_ERROR(srv, con, fmt, ...) \
|
||||
log_write(srv, con, "%s.%d: (error) "fmt, REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__)
|
||||
|
||||
#define CON_TRACE(srv, con, fmt, ...) \
|
||||
log_write(srv, con, "%s.%d: (trace) "fmt, REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__)
|
||||
|
||||
#define CON_SEGFAULT(srv, con, fmt, ...) \
|
||||
do { \
|
||||
log_write(srv, con, "%s.%d: (crashing) "fmt, REMOVE_PATH(__FILE__), __LINE__, __VA_ARGS__); \
|
||||
/* VALGRIND_PRINTF_BACKTRACE(fmt, __VA_ARGS__); */ \
|
||||
abort();\
|
||||
} while(0)
|
||||
|
||||
|
||||
/* TODO: perhaps make portable (detect if cc supports) */
|
||||
#define __ATTRIBUTE_PRINTF_FORMAT(fmt, arg) __attribute__ ((__format__ (__printf__, fmt, arg)))
|
||||
|
||||
LI_API int log_write(server *srv, connection *con, const char *fmt, ...) __ATTRIBUTE_PRINTF_FORMAT(3, 4);
|
||||
|
||||
#endif
|
@ -0,0 +1,31 @@
|
||||
#ifndef _LIGHTTPD_OPTIONS_H_
|
||||
#define _LIGHTTPD_OPTIONS_H_
|
||||
|
||||
typedef enum { OPTION_NONE, OPTION_BOOLEAN, OPTION_INT, OPTION_STRING, OPTION_LIST, OPTION_HASH } option_type;
|
||||
|
||||
struct option;
|
||||
typedef struct option option;
|
||||
|
||||
struct option_mark;
|
||||
typedef struct option_mark option_mark;
|
||||
|
||||
|
||||
struct option {
|
||||
option_type type;
|
||||
union {
|
||||
gboolean opt_bool;
|
||||
gint opt_int;
|
||||
GString *opt_string;
|
||||
/* array of option */
|
||||
GArray *opt_list;
|
||||
/* hash GString => option */
|
||||
GHash *opt_hash;
|
||||
} value;
|
||||
};
|
||||
|
||||
struct option_mark {
|
||||
size_t ndx;
|
||||
gpointer value;
|
||||
};
|
||||
|
||||
#endif
|
@ -0,0 +1,48 @@
|
||||
#ifndef _PLUGIN_H_
|
||||
#define _PLUGIN_H_
|
||||
|
||||
#include "base.h"
|
||||
#include "option.h"
|
||||
|
||||
struct plugin;
|
||||
typedef struct plugin plugin;
|
||||
|
||||
struct module_option;
|
||||
typedef struct module_option module_option;
|
||||
|
||||
#define INIT_FUNC(x) \
|
||||
LI_EXPORT void * x(server *srv, plugin *)
|
||||
|
||||
#define PLUGIN_DATA \
|
||||
size_t id; \
|
||||
ssize_t option_base_ndx
|
||||
|
||||
struct plugin {
|
||||
size_t version;
|
||||
|
||||
GString *name; /* name of the plugin */
|
||||
|
||||
void *(* init) (server *srv, plugin *p);
|
||||
/* the plugin must free the _content_ of the option */
|
||||
option_mark *(* parse_option) (server *src, void *p_d, size_t option_ndx, option *option);
|
||||
|
||||
gpointer data;
|
||||
|
||||
/* dlopen handle */
|
||||
void *lib;
|
||||
|
||||
module_option *options;
|
||||
};
|
||||
|
||||
struct module_option {
|
||||
const char *key;
|
||||
option_type type;
|
||||
};
|
||||
|
||||
struct server_option {
|
||||
plugin *p;
|
||||
size_t index, module_index;
|
||||
option_type type;
|
||||
};
|
||||
|
||||
#endif
|
@ -0,0 +1,7 @@
|
||||
|
||||
#include "log.h"
|
||||
|
||||
int main() {
|
||||
TRACE("%s", "Test!");
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,189 @@
|
||||
#ifndef _LIGHTTPD_SETTINGS_H_
|
||||
#define _LIGHTTPD_SETTINGS_H_
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDDEF_H
|
||||
# include <stddef.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
# include <inttypes.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* if glib supports threads we will use it for async file-io
|
||||
*/
|
||||
#ifdef G_THREADS_ENABLED
|
||||
# ifndef USE_GTHREAD
|
||||
# define USE_GTHREAD
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* on linux 2.4.x you get either sendfile or LFS */
|
||||
#if defined HAVE_SYS_SENDFILE_H && defined HAVE_SENDFILE && (!defined _LARGEFILE_SOURCE || defined HAVE_SENDFILE64) && defined HAVE_WRITEV && defined(__linux__) && !defined HAVE_SENDFILE_BROKEN
|
||||
# define USE_LINUX_SENDFILE
|
||||
# include <sys/sendfile.h>
|
||||
# include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
/* all the Async IO backends need GTHREAD support */
|
||||
#if defined(USE_GTHREAD)
|
||||
# if defined(USE_LINUX_SENDFILE)
|
||||
# if 0 && defined(HAVE_LIBAIO_H)
|
||||
/** disabled for now as not all FSs are async-io capable */
|
||||
# define USE_LINUX_AIO_SENDFILE
|
||||
# endif
|
||||
# define USE_GTHREAD_SENDFILE
|
||||
# endif
|
||||
# if defined(HAVE_AIO_H) && (!defined(__FreeBSD__))
|
||||
/* FreeBSD has no SIGEV_THREAD for us */
|
||||
# define USE_POSIX_AIO
|
||||
# include <sys/types.h> /* macosx wants it */
|
||||
# include <aio.h>
|
||||
# endif
|
||||
# ifdef HAVE_MMAP
|
||||
# define USE_GTHREAD_AIO
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined HAVE_SYS_UIO_H && defined HAVE_SENDFILE && defined HAVE_WRITEV && (defined(__FreeBSD__) || defined(__DragonFly__))
|
||||
# define USE_FREEBSD_SENDFILE
|
||||
# include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
#if defined HAVE_SYS_SENDFILE_H && defined HAVE_SENDFILEV && defined HAVE_WRITEV && defined(__sun)
|
||||
# define USE_SOLARIS_SENDFILEV
|
||||
# include <sys/sendfile.h>
|
||||
# include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
#if defined HAVE_SYS_UIO_H && defined HAVE_WRITEV
|
||||
# define USE_WRITEV
|
||||
# include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
#if defined HAVE_SYS_MMAN_H && defined HAVE_MMAP
|
||||
# define USE_MMAP
|
||||
# include <sys/mman.h>
|
||||
/* NetBSD 1.3.x needs it */
|
||||
# ifndef MAP_FAILED
|
||||
# define MAP_FAILED -1
|
||||
# endif
|
||||
|
||||
#if defined(MAP_ANON)
|
||||
#define HAVE_MEM_MMAP_ANON
|
||||
#else
|
||||
/* let's try /dev/zero */
|
||||
#define HAVE_MEM_MMAP_ZERO
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined HAVE_SYS_UIO_H && defined HAVE_WRITEV && defined HAVE_SEND_FILE && defined(__aix)
|
||||
# define USE_AIX_SENDFILE
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* unix can use read/write or recv/send on sockets
|
||||
* win32 only recv/send
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# define NOGDI
|
||||
# define USE_WIN32_SEND
|
||||
/* wait for async-io support
|
||||
# define USE_WIN32_TRANSMITFILE
|
||||
*/
|
||||
#else
|
||||
# define USE_WRITE
|
||||
#endif
|
||||
|
||||
|
||||
typedef enum { HANDLER_UNSET,
|
||||
HANDLER_GO_ON,
|
||||
HANDLER_FINISHED,
|
||||
HANDLER_COMEBACK,
|
||||
HANDLER_WAIT_FOR_EVENT,
|
||||
HANDLER_ERROR,
|
||||
HANDLER_WAIT_FOR_FD
|
||||
} handler_t;
|
||||
|
||||
/* Shared library support */
|
||||
#ifdef _WIN32
|
||||
#define LI_IMPORT __declspec(dllimport)
|
||||
#define LI_EXPORT __declspec(dllexport)
|
||||
#define LI_DLLLOCAL
|
||||
#define LI_DLLPUBLIC
|
||||
#else
|
||||
#define LI_IMPORT
|
||||
#ifdef GCC_HASCLASSVISIBILITY
|
||||
#define LI_EXPORT __attribute__ ((visibility("default")))
|
||||
#define LI_DLLLOCAL __attribute__ ((visibility("hidden")))
|
||||
#define LI_DLLPUBLIC __attribute__ ((visibility("default")))
|
||||
#else
|
||||
#define LI_EXPORT
|
||||
#define LI_DLLLOCAL
|
||||
#define LI_DLLPUBLIC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef LI_DECLARE_EXPORTS
|
||||
#define LI_API LI_EXPORT
|
||||
#else
|
||||
#define LI_API LI_IMPORT
|
||||
#endif
|
||||
|
||||
/* Throwable classes must always be visible on GCC in all binaries */
|
||||
#ifdef _WIN32
|
||||
#define LI_EXCEPTIONAPI(api) api
|
||||
#elif defined(GCC_HASCLASSVISIBILITY)
|
||||
#define LI_EXCEPTIONAPI(api) LI_EXPORT
|
||||
#else
|
||||
#define LI_EXCEPTIONAPI(api)
|
||||
#endif
|
||||
|
||||
#ifdef UNUSED_PARAM
|
||||
#elif defined(__GNUC__)
|
||||
# define UNUSED_PARAM(x) UNUSED_ ## x __attribute__((unused))
|
||||
#elif defined(__LCLINT__)
|
||||
# define UNUSED_PARAM(x) /*@unused@*/ x
|
||||
#else
|
||||
# define UNUSED_PARAM(x) x
|
||||
#endif
|
||||
|
||||
#if __GNUC__
|
||||
#define INLINE static inline
|
||||
// # define INLINE extern inline
|
||||
#else
|
||||
# define INLINE static
|
||||
#endif
|
||||
|
||||
#include "sys-files.h"
|
||||
#include "sys-mmap.h"
|
||||
#include "sys-process.h"
|
||||
#include "sys-socket.h"
|
||||
#include "sys-strings.h"
|
||||
|
||||
#endif
|
@ -0,0 +1,64 @@
|
||||
#include "sys-files.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
DIR *opendir(const char *dn) {
|
||||
DIR *d = g_slice_new0(DIR);
|
||||
|
||||
if (INVALID_HANDLE_VALUE == (d->h = FindFirstFile(dn, &(d->finddata)))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
struct dirent *readdir(DIR *d) {
|
||||
if (!d->dent.d_name) {
|
||||
/* opendir has set a finddata already, push it out */
|
||||
|
||||
d->dent.d_name = d->finddata.cFileName;
|
||||
return &(d->dent);
|
||||
}
|
||||
if (FindNextFile(d->h, &(d->finddata))) {
|
||||
d->dent.d_name = d->finddata.cFileName;
|
||||
return &(d->dent);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void closedir(DIR *d) {
|
||||
FindClose(d);
|
||||
|
||||
g_slice_free(DIR, d);
|
||||
}
|
||||
|
||||
GString *pathname_unix2local(GString *fn) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < fn->len; i++) {
|
||||
if (fn->str[i] == '/') {
|
||||
fn->str[i] = '\\';
|
||||
}
|
||||
}
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
GString *filename_unix2local(GString *fn) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < fn->len; i++) {
|
||||
if (fn->str[i] == '/') {
|
||||
fn->str[i] = '\\';
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
buffer_prepare_append(fn, 4);
|
||||
memmove(fn->ptr + 4, fn->ptr, fn->used);
|
||||
memcpy(fn->ptr, "\\\\?\\", 4);
|
||||
fn->used += 4;
|
||||
#endif
|
||||
return fn;
|
||||
}
|
||||
#endif
|
||||
|
@ -0,0 +1,84 @@
|
||||
#ifndef _SYS_FILES_H_
|
||||
#define _SYS_FILES_H_
|
||||
|
||||
#define DIR_SEPERATOR_UNIX '/'
|
||||
#define DIR_SEPERATOR_UNIX_STR "/"
|
||||
#define DIR_SEPERATOR_WIN '\\'
|
||||
#define DIR_SEPERATOR_WIN_STR "\\"
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <io.h> /* open */
|
||||
#include <direct.h> /* chdir */
|
||||
|
||||
#define DIR_SEPERATOR DIR_SEPERATOR_WIN
|
||||
#define DIR_SEPERATOR_STR DIR_SEPERATOR_WIN_STR
|
||||
|
||||
#define __S_ISTYPE(mode, mask) (((mode) & _S_IFMT) == (mask))
|
||||
|
||||
#undef S_ISDIR
|
||||
#undef S_ISCHR
|
||||
#undef S_ISBLK
|
||||
#undef S_ISREG
|
||||
#define S_ISDIR(mode) __S_ISTYPE((mode), _S_IFDIR)
|
||||
#define S_ISCHR(mode) __S_ISTYPE((mode), _S_IFCHR)
|
||||
#define S_ISBLK(mode) __S_ISTYPE((mode), _S_IFBLK)
|
||||
#define S_ISREG(mode) __S_ISTYPE((mode), _S_IFREG)
|
||||
/* we don't support symlinks */
|
||||
#define S_ISLNK(mode) 0
|
||||
|
||||
#define lstat stat
|
||||
#define mkstemp(x) open(mktemp(x), O_RDWR)
|
||||
#define mkdir(x, y) mkdir(x)
|
||||
|
||||
/* retrieve the most recent network, or general libc error */
|
||||
#define light_sock_errno() (WSAGetLastError())
|
||||
|
||||
struct dirent {
|
||||
const char *d_name;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
HANDLE h;
|
||||
WIN32_FIND_DATA finddata;
|
||||
struct dirent dent;
|
||||
} DIR;
|
||||
|
||||
LI_EXPORT DIR * opendir(const char *dn);
|
||||
LI_EXPORT struct dirent * readdir(DIR *d);
|
||||
LI_EXPORT void closedir(DIR *d);
|
||||
|
||||
LI_EXPORT GString * filename_unix2local(GString *b);
|
||||
LI_EXPORT GString * pathname_unix2local(GString *b);
|
||||
|
||||
#else /* _WIN32 */
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#define DIR_SEPERATOR DIR_SEPERATOR_UNIX
|
||||
#define DIR_SEPERATOR_STR DIR_SEPERATOR_UNIX_STR
|
||||
|
||||
#define light_sock_errno() (errno)
|
||||
|
||||
#define filename_unix2local(x) /* (x) */
|
||||
#define pathname_unix2local(x) /* (x) */
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#define PATHNAME_APPEND_SLASH(x) \
|
||||
if (x->len > 1 && x->ptr[x->len - 1] != DIR_SEPERATOR) { \
|
||||
g_string_append_c(DIR_SEPEARATOR); \
|
||||
}
|
||||
|
||||
#ifndef O_LARGEFILE
|
||||
# define O_LARGEFILE 0
|
||||
#endif
|
||||
|
||||
#ifndef O_NOATIME
|
||||
# define O_NOATIME 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -0,0 +1,26 @@
|
||||
#ifndef WIN32_MMAP_H
|
||||
#define WIN32_MMAP_H
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#define MAP_FAILED -1
|
||||
#define PROT_SHARED 0
|
||||
#define MAP_SHARED 0
|
||||
#define PROT_READ 0
|
||||
|
||||
#define mmap(a, b, c, d, e, f) (-1)
|
||||
#define munmap(a, b) (-1)
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#else
|
||||
#include <sys/mman.h>
|
||||
|
||||
#ifndef MAP_FAILED
|
||||
#define MAP_FAILED -1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
@ -0,0 +1,17 @@
|
||||
#ifndef _SYS_PROCESS_H_
|
||||
#define _SYS_PROCESS_H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <process.h>
|
||||
#define pid_t int
|
||||
/* win32 has no fork() */
|
||||
#define kill(x, y) do { } while (0)
|
||||
#define getpid() 0
|
||||
|
||||
#else
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -0,0 +1,76 @@
|
||||
#include "base.h"
|
||||
#include "sys-socket.h"
|
||||
|
||||
#ifndef HAVE_INET_ATON
|
||||
/* win32 has inet_addr instead if inet_aton */
|
||||
# ifdef HAVE_INET_ADDR
|
||||
int inet_aton(const char *cp, struct in_addr *inp) {
|
||||
struct in_addr a;
|
||||
|
||||
a.s_addr = inet_addr(cp);
|
||||
|
||||
if (INADDR_NONE == a.s_addr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
inp->s_addr = a.s_addr;
|
||||
|
||||
return 1;
|
||||
}
|
||||
# else
|
||||
# error no inet_aton emulation found
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <winsock2.h>
|
||||
|
||||
/* windows doesn't have inet_ntop */
|
||||
|
||||
/*
|
||||
I have to look into this more. WSAAddressToString takes a sockaddr structure, which includes
|
||||
the port number, so I must first test this stuff more carefully. For now, no IPV6 on windows.
|
||||
You will notice that HAVE_IPV6 is never true for win32.
|
||||
*/
|
||||
|
||||
const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
|
||||
{
|
||||
/* WSAAddressToString takes a full sockaddr, while inet_ntop only takes the address */
|
||||
struct sockaddr_in sock4;
|
||||
struct sockaddr_in6 sock6;
|
||||
DWORD addrLen = cnt;
|
||||
int err = 0;
|
||||
|
||||
/* src is either an in_addr or an in6_addr. */
|
||||
const struct in_addr *src4 = (const struct in_addr*) src;
|
||||
const struct in6_addr *src6 = (const struct in6_addr*) src;
|
||||
|
||||
int ipv6 = af == AF_INET6;
|
||||
|
||||
// DebugBreak();
|
||||
|
||||
if ( ipv6 )
|
||||
{
|
||||
sock6.sin6_family = AF_INET6;
|
||||
sock6.sin6_port = 0;
|
||||
sock6.sin6_addr = *src6;
|
||||
}
|
||||
else
|
||||
{
|
||||
sock4.sin_family = AF_INET;
|
||||
sock4.sin_port = 0;
|
||||
sock4.sin_addr = *src4;
|
||||
}
|
||||
|
||||
err = WSAAddressToStringA(
|
||||
ipv6 ? (LPSOCKADDR) &sock6 : (LPSOCKADDR) &sock4,
|
||||
ipv6 ? sizeof(sock6) : sizeof(sock4),
|
||||
NULL,
|
||||
dst, &addrLen );
|
||||
return err == 0 ? dst : NULL;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
@ -0,0 +1,80 @@
|
||||
#ifndef SYS_SOCKET_H
|
||||
#define SYS_SOCKET_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef FD_SETSIZE
|
||||
/* By default this is 64 */
|
||||
#define FD_SETSIZE 4096
|
||||
#endif
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
//#include <wspiapi.h>
|
||||
//#define HAVE_IPV6 -- not until we've resolved the inet_ntop issue.
|
||||
|
||||
#define ECONNRESET WSAECONNRESET
|
||||
#define EINPROGRESS WSAEINPROGRESS
|
||||
#define EALREADY WSAEALREADY
|
||||
#define ENOTCONN WSAENOTCONN
|
||||
#define EWOULDBLOCK WSAEWOULDBLOCK
|
||||
#define ECONNABORTED WSAECONNABORTED
|
||||
#define ECONNREFUSED WSAECONNREFUSED
|
||||
#define EHOSTUNREACH WSAEHOSTUNREACH
|
||||
#define ioctl ioctlsocket
|
||||
#define hstrerror(x) ""
|
||||
#define STDIN_FILENO 0
|
||||
#define STDOUT_FILENO 1
|
||||
#define STDERR_FILENO 2
|
||||
#ifndef __MINGW32__
|
||||
#define ssize_t int
|
||||
#endif
|
||||
|
||||
#define sockread( fd, buf, bytes ) recv( fd, buf, bytes, 0 )
|
||||
|
||||
LI_EXPORT const char * inet_ntop(int af, const void *src, char *dst, socklen_t cnt);
|
||||
int inet_aton(const char *cp, struct in_addr *inp);
|
||||
#define HAVE_INET_ADDR
|
||||
#undef HAVE_INET_ATON
|
||||
|
||||
#else
|
||||
#include <sys/types.h> /* required by netinet/tcp.h on FreeBSD */
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <sys/un.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#ifndef SUN_LEN
|
||||
#define SUN_LEN(su) \
|
||||
(sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
|
||||
#endif
|
||||
|
||||
#define sockread( fd, buf, bytes ) read( fd, buf, bytes )
|
||||
#define closesocket(x) close(x)
|
||||
|
||||
#include <netdb.h>
|
||||
#endif /* !_WIN32 */
|
||||
|
||||
#ifdef HAVE_INET_NTOP
|
||||
/* only define it if it isn't defined yet */
|
||||
#ifndef HAVE_IPV6
|
||||
#define HAVE_IPV6
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef union {
|
||||
#ifdef HAVE_IPV6
|
||||
struct sockaddr_in6 ipv6;
|
||||
#endif
|
||||
struct sockaddr_in ipv4;
|
||||
#ifdef HAVE_SYS_UN_H
|
||||
struct sockaddr_un un;
|
||||
#endif
|
||||
struct sockaddr plain;
|
||||
} sock_addr;
|
||||
|
||||
#endif
|
@ -0,0 +1,46 @@
|
||||
#ifndef _SYS_STRINGS_H_
|
||||
#define _SYS_STRINGS_H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#define strcasecmp stricmp
|
||||
#define strncasecmp strnicmp
|
||||
#include <stdlib.h>
|
||||
#define str_to_off_t(p, e, b) _strtoi64(p, e, b)
|
||||
#define STR_OFF_T_MAX LLONG_MAX
|
||||
#define STR_OFF_T_MIN LLONG_MIN
|
||||
#define strtoull _strtoui64
|
||||
#ifdef __MINGW32__
|
||||
/* missing prototype */
|
||||
unsigned __int64 _strtoui64(
|
||||
const char *nptr,
|
||||
char **endptr,
|
||||
int base
|
||||
);
|
||||
__int64 _strtoi64(
|
||||
const char *nptr,
|
||||
char **endptr,
|
||||
int base
|
||||
);
|
||||
#endif
|
||||
#else /** we are a unix */
|
||||
|
||||
/**
|
||||
* we use strtoll() for parsing the ranges into a off_t
|
||||
*
|
||||
* if off_t is 32bit, we can use strtol() instead
|
||||
*/
|
||||
#if SIZEOF_OFF_T == SIZEOF_LONG
|
||||
#define str_to_off_t(p, e, b) strtol(p, e, b)
|
||||
#define STR_OFF_T_MAX LONG_MAX
|
||||
#define STR_OFF_T_MIN LONG_MIN
|
||||
#elif defined(HAVE_STRTOLL)
|
||||
#define str_to_off_t(p, e, b) strtoll(p, e, b)
|
||||
#define STR_OFF_T_MAX LLONG_MAX
|
||||
#define STR_OFF_T_MIN LLONG_MIN
|
||||
#else
|
||||
#error off_t is more than 4 bytes but we can not parse it with strtol() (run autogen.sh again if you build from svn)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -0,0 +1,120 @@
|
||||
#! /usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
#import Action, Object, Params, os, sys
|
||||
import Params
|
||||
|
||||
common_uselib = 'glib '
|
||||
|
||||
common_source='''
|
||||
chunks.c
|
||||
log.c
|
||||
sys-files.c
|
||||
'''
|
||||
# sys-socket.c
|
||||
|
||||
main_source = '''
|
||||
server.c
|
||||
'''
|
||||
|
||||
#def node_in_same_dir(node, name):
|
||||
#p = node.m_parent
|
||||
#n = p.m_files_lookup.get(name, None)
|
||||
#if not n: n = p.m_build_lookup.get(name, None)
|
||||
#if n: return n
|
||||
|
||||
#newnode = Node(name, p)
|
||||
#p.m_build_lookup[newnode.m_name]=newnode
|
||||
|
||||
#return newnode
|
||||
|
||||
#def lemon_file(self, node):
|
||||
#lemon_task = self.create_task('lemon', nice=40)
|
||||
#lemon_task.set_inputs([node, node_in_same_dir(node, 'lempar.c')])
|
||||
|
||||
#newnodes = [node.change_ext('.c'), node.change_ext('.h')]
|
||||
#lemon_task.set_outputs(newnodes)
|
||||
|
||||
#task = self.create_task(self.m_type_initials)
|
||||
#task.set_inputs(lemon_task.m_outputs[0])
|
||||
#task.set_outputs(node.change_ext('.o'))
|
||||
|
||||
def lighty_mod(bld, target, src, uselib = '', option = ''):
|
||||
if option and not getattr(Params.g_options, option): return
|
||||
mod = bld.new_task_gen('cc', 'plugin')
|
||||
mod.target = target
|
||||
mod.source = src
|
||||
mod.uselib += 'lightymod ' + common_uselib + uselib
|
||||
|
||||
def build(bld):
|
||||
env = bld.env
|
||||
|
||||
# 1. Build lemon (parser generator)
|
||||
#lemon = bld.new_task_gen('cc', 'program')
|
||||
#lemon.install_var = 0
|
||||
#lemon.source = 'lemon.c'
|
||||
#lemon.target = 'lemon'
|
||||
|
||||
#bld.add_group('lemon')
|
||||
#lem_task = lemon.m_tasks[1]
|
||||
#lem_node = lem_task.m_outputs[0]
|
||||
#lemon_exec = lem_node.abspath(lem_task.m_env)
|
||||
#Action.simple_action('lemon', 'cd ${TGT[0].bld_dir(env)}; ' + lemon_exec + ' ${SRC[0].abspath()} ${SRC[1].abspath()}', color='BLUE')
|
||||
|
||||
# hook .y to lemon
|
||||
#Object.hook('cc', 'LEMON_EXT', lemon_file)
|
||||
|
||||
main = bld.new_task_gen('cc', 'program')
|
||||
main.name = 'lighttpd'
|
||||
main.source = common_source + main_source
|
||||
main.target='lighttpd' + env['APPEND']
|
||||
main.uselib += 'lighty dl openssl pcre ' + common_uselib
|
||||
|
||||
#lighty_mod(bld, 'mod_access', 'mod_access.c')
|
||||
#lighty_mod(bld, 'mod_alias', 'mod_alias.c')
|
||||
#lighty_mod(bld, 'mod_dirlisting', 'mod_dirlisting.c', uselib = 'pcre')
|
||||
#lighty_mod(bld, 'mod_staticfile', 'mod_staticfile.c')
|
||||
#lighty_mod(bld, 'mod_indexfile', 'mod_indexfile.c')
|
||||
#lighty_mod(bld, 'mod_setenv', 'mod_setenv.c')
|
||||
#lighty_mod(bld, 'mod_rrdtool', 'mod_rrdtool.c')
|
||||
#lighty_mod(bld, 'mod_usertrack', 'mod_usertrack.c')
|
||||
#lighty_mod(bld, 'mod_proxy_core', '''
|
||||
#mod_proxy_core.c mod_proxy_core_pool.c mod_proxy_core_backend.c
|
||||
#mod_proxy_core_address.c mod_proxy_core_backlog.c mod_proxy_core_protocol.c
|
||||
#mod_proxy_core_rewrites.c mod_proxy_core_spawn.c
|
||||
#''', uselib = 'pcre')
|
||||
#lighty_mod(bld, 'mod_proxy_backend_http', 'mod_proxy_backend_http.c')
|
||||
#lighty_mod(bld, 'mod_proxy_backend_fastcgi', 'mod_proxy_backend_fastcgi.c')
|
||||
#lighty_mod(bld, 'mod_proxy_backend_scgi', 'mod_proxy_backend_scgi.c')
|
||||
#lighty_mod(bld, 'mod_proxy_backend_ajp13', 'mod_proxy_backend_ajp13.c')
|
||||
#lighty_mod(bld, 'mod_userdir', 'mod_userdir.c')
|
||||
#lighty_mod(bld, 'mod_secdownload', 'mod_secure_download.c')
|
||||
#lighty_mod(bld, 'mod_accesslog', 'mod_accesslog.c')
|
||||
#lighty_mod(bld, 'mod_simple_vhost', 'mod_simple_vhost.c')
|
||||
#lighty_mod(bld, 'mod_evhost', 'mod_evhost.c')
|
||||
#lighty_mod(bld, 'mod_expire', 'mod_expire.c')
|
||||
#lighty_mod(bld, 'mod_status', 'mod_status.c')
|
||||
#lighty_mod(bld, 'mod_compress', 'mod_compress.c', uselib = 'bzip zlib')
|
||||
#lighty_mod(bld, 'mod_redirect', 'mod_redirect.c', uselib = 'pcre')
|
||||
#lighty_mod(bld, 'mod_rewrite', 'mod_rewrite.c', uselib = 'pcre')
|
||||
#lighty_mod(bld, 'mod_auth', 'mod_auth.c http_auth_digest.c http_auth.c', uselib = 'crypt ldap') ## lber?
|
||||
#lighty_mod(bld, 'mod_sql_vhost_core', 'mod_sql_vhost_core.c')
|
||||
#lighty_mod(bld, 'mod_postgresql_vhost', 'mod_postgresql_vhost.c', uselib = 'postgresql', option = 'postgresql')
|
||||
#lighty_mod(bld, 'mod_mysql_vhost', 'mod_mysql_vhost.c', uselib = 'mysql', option = 'mysql')
|
||||
#lighty_mod(bld, 'mod_trigger_b4_dl', 'mod_trigger_b4_dl.c', uselib = 'pcre')
|
||||
#lighty_mod(bld, 'mod_uploadprogress', 'mod_uploadprogress.c')
|
||||
#lighty_mod(bld, 'mod_evasive', 'mod_evasive.c')
|
||||
#lighty_mod(bld, 'mod_ssi', 'mod_ssi_exprparser.y mod_ssi_expr.c mod_ssi.c', uselib = 'pcre')
|
||||
#lighty_mod(bld, 'mod_flv_streaming', 'mod_flv_streaming.c')
|
||||
#lighty_mod(bld, 'mod_chunked', 'mod_chunked.c')
|
||||
#lighty_mod(bld, 'mod_magnet', 'mod_magnet.c mod_magnet_cache.c', uselib = 'lua')
|
||||
#lighty_mod(bld, 'mod_deflate', 'mod_deflate.c', uselib = 'bzip zlib')
|
||||
#lighty_mod(bld, 'mod_webdav', 'mod_webdav.c', uselib = 'sqlite3 xml uuid')
|
||||
|
||||
def configure(conf):
|
||||
env = conf.env
|
||||
#env['LEMON_EXT'] = [ '.y' ]
|
||||
env['LIBDIR'] = Params.g_options.libdir
|
||||
env['APPEND'] = Params.g_options.append
|
||||
env['plugin_INST_VAR'] = 'LIBDIR'
|
||||
env['plugin_INST_DIR'] = ''
|
@ -0,0 +1,490 @@
|
||||
#! /usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
import Params, types, sys, Runner
|
||||
|
||||
# the following two variables are used by the target "waf dist"
|
||||
VERSION='2.0-pre'
|
||||
APPNAME='lighttpd'
|
||||
|
||||
# these variables are mandatory ('/' are converted automatically)
|
||||
srcdir = '.'
|
||||
blddir = 'build'
|
||||
|
||||
def set_options(opt):
|
||||
# the gcc module provides a --debug-level option
|
||||
opt.tool_options('compiler_cc')
|
||||
#opt.add_option('--with-xattr', action='store_true', help='xattr-support for the stat-cache [default: off]', dest='xattr', default = False)
|
||||
#opt.add_option('--with-mysql', action='store_true', help='with mysql-support for the mod_sql_vhost [default: off]', dest = 'mysql', default = False)
|
||||
#opt.add_option('--with-postgresql', action='store_true', help='with postgress-support for the mod_sql_vhost [default: off]', dest = 'postgresql', default = False)
|
||||
opt.add_option('--with-openssl', action='store_true', help='with openssl-support [default: off]', dest = 'openssl', default = False)
|
||||
#opt.add_option('--with-pcre', action='store_true', help='with regex support [default: on]', dest = 'pcre', default = True)
|
||||
#opt.add_option('--with-webdav-props', action='store_true', help='with property-support for mod_webdav [default: off]', dest = 'webdavprops', default = False)
|
||||
#opt.add_option('--with-sqlite3', action='store_true', help='with property-support [sqlite3] for mod_webdav [default: off]', dest = 'sqlite3', default = False)
|
||||
#opt.add_option('--with-bzip', action='store_true', help='with bzip2-support for mod_compress [default: off]', dest = 'bzip', default = False)
|
||||
#opt.add_option('--with-zlib', action='store_true', help='with deflate-support for mod_compress [default: on]', dest = 'zlib', default = True)
|
||||
#opt.add_option('--with-ldap', action='store_true', help='with LDAP-support for the mod_auth [default: off]', dest = 'ldap', default = False)
|
||||
#opt.add_option('--with-libaio', action='store_true', help='with libaio for linux [default: off]', dest = 'libaio', default = False)
|
||||
#opt.add_option('--with-libfcgi', action='store_true', help='with libfcgi for fcgi-stat-accel [default: off]', dest = 'libfcgi', default = False)
|
||||
opt.add_option('--with-lua', action='store_true', help='with lua 5.1 for mod_magnet [default: off]', dest = 'lua', default = False)
|
||||
# opt.add_option('--with-glib', action='store_true', help='with glib support for internal caches [default: on]', dest = 'glib', default = True)
|
||||
opt.add_option('--with-all', action='store_true', help='Enable all features', dest = 'all', default = False)
|
||||
opt.add_option('--build-static', action='store_true', help='build a static lighttpd with all modules added', dest = 'buildstatic', default = False)
|
||||
opt.add_option('--append', action='store', help= |