commit
9372e41393
20 changed files with 2146 additions and 0 deletions
@ -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')] |