commit
c81c68f300
9 changed files with 585 additions and 0 deletions
-
4.gitignore
-
20CMakeLists.txt
-
14cmake/LighttpdMacros.cmake
-
65src/CMakeLists.txt
-
0src/config.h.cmake
-
174src/connection.c
-
187src/fcgi-debug.c
-
70src/fcgi-debug.h
-
51src/tools.c
@ -0,0 +1,4 @@ |
|||
*build |
|||
Doxyfile |
|||
*kdev* |
|||
*~ |
@ -0,0 +1,20 @@ |
|||
PROJECT(fcgi-debug C) |
|||
|
|||
CMAKE_MINIMUM_REQUIRED(VERSION 2.4.0 FATAL_ERROR) |
|||
|
|||
SET(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) |
|||
|
|||
SET(CPACK_PACKAGE_VERSION_MAJOR 2) |
|||
SET(CPACK_PACKAGE_VERSION_MINOR 0) |
|||
SET(CPACK_PACKAGE_VERSION_PATCH 0) |
|||
|
|||
#SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/COPYING") |
|||
#SET(CPACK_RESOURCE_FILE_README "${CMAKE_SOURCE_DIR}/README") |
|||
SET(CPACK_PACKAGE_VENDOR "lighttpd@stbuehler.de") |
|||
|
|||
SET(CPACK_SOURCE_GENERATOR "TGZ") |
|||
SET(CPACK_SOURCE_IGNORE_FILES "/\\\\.;~$;/_;build/;CMakeFiles/;CMakeCache;gz$;Makefile\\\\.;trace;Testing/;foo;autom4te;cmake_install;CPack;\\\\.pem;ltmain.sh;configure;libtool;/config\\\\.;missing;autogen.sh;install-sh;Dart;aclocal;log$;Makefile$") |
|||
|
|||
SET(CPACK_SOURCE_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") |
|||
|
|||
ADD_SUBDIRECTORY(src build) |
@ -0,0 +1,14 @@ |
|||
|
|||
MACRO(ADD_TARGET_PROPERTIES _target _name) |
|||
SET(_properties) |
|||
FOREACH(_prop ${ARGN}) |
|||
SET(_properties "${_properties} ${_prop}") |
|||
ENDFOREACH(_prop) |
|||
GET_TARGET_PROPERTY(_old_properties ${_target} ${_name}) |
|||
MESSAGE("adding property to ${_target} ${_name}:" ${_properties}) |
|||
IF(NOT _old_properties) |
|||
# in case it's NOTFOUND |
|||
SET(_old_properties) |
|||
ENDIF(NOT _old_properties) |
|||
SET_TARGET_PROPERTIES(${_target} PROPERTIES ${_name} "${_old_properties} ${_properties}") |
|||
ENDMACRO(ADD_TARGET_PROPERTIES) |
@ -0,0 +1,65 @@ |
|||
INCLUDE(CheckIncludeFiles) |
|||
INCLUDE(CheckFunctionExists) |
|||
INCLUDE(CheckVariableExists) |
|||
INCLUDE(CheckTypeSize) |
|||
INCLUDE(CheckLibraryExists) |
|||
INCLUDE(CMakeDetermineCCompiler) |
|||
INCLUDE(FindThreads) |
|||
INCLUDE(CPack) |
|||
INCLUDE(FindPkgConfig) |
|||
|
|||
INCLUDE(LighttpdMacros) |
|||
cmake_policy(SET CMP0005 OLD) |
|||
|
|||
ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGE_FILES) |
|||
|
|||
# libev |
|||
CHECK_INCLUDE_FILES(ev.h HAVE_EV_H) |
|||
IF(HAVE_EV_H) |
|||
CHECK_LIBRARY_EXISTS(ev ev_loop "" HAVE_LIBEV) |
|||
IF(HAVE_LIBEV) |
|||
SET(EV_LDFLAGS -lev) |
|||
ELSE(HAVE_LIBEV) |
|||
MESSAGE(FATAL_ERROR "Couldn't find lib ev") |
|||
ENDIF(HAVE_LIBEV) |
|||
ELSE(HAVE_EV_H) |
|||
MESSAGE(FATAL_ERROR "Couldn't find <ev.h>") |
|||
ENDIF(HAVE_EV_H) |
|||
|
|||
# glib/gthread |
|||
pkg_check_modules(GTHREAD REQUIRED gthread-2.0) |
|||
#INCLUDE_DIRECTORIES(${GTHREAD_INCLUDE_DIRS}) |
|||
|
|||
ADD_DEFINITIONS( |
|||
-DPACKAGE_NAME="\\"${CMAKE_PROJECT_NAME}\\"" |
|||
-DPACKAGE_VERSION="\\"${CPACK_PACKAGE_VERSION}\\"" |
|||
) |
|||
|
|||
## Write out config.h |
|||
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) |
|||
|
|||
ADD_DEFINITIONS(-DHAVE_CONFIG_H) |
|||
|
|||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) |
|||
|
|||
ADD_EXECUTABLE(fcgi-debug |
|||
fcgi-debug.c |
|||
connection.c |
|||
tools.c |
|||
) |
|||
|
|||
ADD_TARGET_PROPERTIES(fcgi-debug LINK_FLAGS ${EV_LDFLAGS}) |
|||
ADD_TARGET_PROPERTIES(fcgi-debug COMPILE_FLAGS ${EV_CFLAGS}) |
|||
|
|||
IF(CMAKE_COMPILER_IS_GNUCC) |
|||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -Wall -g -Wshadow -W -pedantic") |
|||
SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O2") |
|||
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0") |
|||
SET(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_WITHDEBINFO} -O2") |
|||
ADD_DEFINITIONS(-D_GNU_SOURCE) |
|||
ENDIF(CMAKE_COMPILER_IS_GNUCC) |
|||
|
|||
ADD_TARGET_PROPERTIES(fcgi-debug LINK_FLAGS ${GTHREAD_LDFLAGS}) |
|||
ADD_TARGET_PROPERTIES(fcgi-debug COMPILE_FLAGS ${GTHREAD_CFLAGS}) |
|||
|
|||
SET_TARGET_PROPERTIES(fcgi-debug PROPERTIES CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}) |
@ -0,0 +1,174 @@ |
|||
#include "fcgi-debug.h" |
|||
|
|||
static void connection_close(connection *con) { |
|||
ev_io_stop(con->srv->loop, &con->w_server); |
|||
ev_io_stop(con->srv->loop, &con->w_client); |
|||
if (-1 != con->fd_server) { |
|||
shutdown(con->fd_server, SHUT_RDWR); |
|||
close(con->fd_server); |
|||
} |
|||
if (-1 != con->fd_client) { |
|||
shutdown(con->fd_client, SHUT_RDWR); |
|||
close(con->fd_client); |
|||
} |
|||
g_string_free(con->send_client_buf, TRUE); |
|||
g_string_free(con->send_server_buf, TRUE); |
|||
g_slice_free(connection, con); |
|||
} |
|||
|
|||
static gboolean connection_connect(connection *con) { |
|||
server *srv = con->srv; |
|||
if (con->client_connected) return TRUE; |
|||
ev_io_start(srv->loop, &srv->w_accept); |
|||
if (-1 == connect(con->fd_client, srv->client.saddr, srv->client.addr_len)) { |
|||
switch (errno) { |
|||
case EALREADY: |
|||
case EINPROGRESS: |
|||
case EINTR: |
|||
ev_io_stop(srv->loop, &srv->w_accept); /* no new connections until we have a new connection to the client */ |
|||
ev_io_set_events(srv->loop, &con->w_client, EV_WRITE | EV_READ); |
|||
break; |
|||
default: |
|||
g_warning("couldn't connect: %s", g_strerror(errno)); |
|||
connection_close(con); |
|||
} |
|||
return FALSE; |
|||
} else { |
|||
con->client_connected = TRUE; |
|||
ev_io_set_events(srv->loop, &con->w_client, EV_READ); |
|||
ev_io_set_events(srv->loop, &con->w_server, EV_READ); |
|||
return TRUE; |
|||
} |
|||
} |
|||
|
|||
static char readbuf[4096]; |
|||
|
|||
static void fd_server_cb(struct ev_loop *loop, struct ev_io *w, int revents) { |
|||
connection *con = (connection*) w->data; |
|||
server *srv = con->srv; |
|||
UNUSED(loop); |
|||
|
|||
if (revents & EV_READ) { |
|||
int l = read(w->fd, readbuf, sizeof(readbuf)); |
|||
switch (l) { |
|||
case -1: |
|||
switch (errno) { |
|||
case EAGAIN: |
|||
case EINTR: |
|||
break; |
|||
default: |
|||
g_warning("couldn't read from server: %s", g_strerror(errno)); |
|||
connection_close(con); |
|||
} |
|||
return; |
|||
case 0: |
|||
/* end of file */ |
|||
connection_close(con); |
|||
return; |
|||
default: |
|||
break; |
|||
} |
|||
g_string_append_len(con->send_client_buf, readbuf, l); |
|||
if (con->send_client_buf->len > 4*4096) ev_io_rem_events(srv->loop, w, EV_READ); |
|||
ev_io_add_events(srv->loop, &con->w_client, EV_WRITE); |
|||
} |
|||
if (revents & EV_WRITE) { |
|||
if (con->send_server_buf->len > 0) { |
|||
int l = write(w->fd, con->send_server_buf->str, con->send_server_buf->len); |
|||
switch (l) { |
|||
case -1: |
|||
switch (errno) { |
|||
case EAGAIN: |
|||
case EINTR: |
|||
break; |
|||
default: |
|||
g_warning("couldn't write to server: %s", g_strerror(errno)); |
|||
connection_close(con); |
|||
} |
|||
return; |
|||
} |
|||
g_string_erase(con->send_server_buf, 0, l); |
|||
if (con->send_server_buf->len < 4*4096) ev_io_add_events(srv->loop, &con->w_server, EV_READ); |
|||
} |
|||
if (con->send_server_buf->len == 0) ev_io_rem_events(srv->loop, w, EV_WRITE); |
|||
} |
|||
} |
|||
|
|||
static void fd_client_cb(struct ev_loop *loop, struct ev_io *w, int revents) { |
|||
connection *con = (connection*) w->data; |
|||
server *srv = con->srv; |
|||
UNUSED(loop); |
|||
if (!connection_connect(con)) return; |
|||
|
|||
if (revents & EV_READ) { |
|||
int l = read(w->fd, readbuf, sizeof(readbuf)); |
|||
switch (l) { |
|||
case -1: |
|||
switch (errno) { |
|||
case EAGAIN: |
|||
case EINTR: |
|||
break; |
|||
default: |
|||
g_warning("couldn't read from client: %s", g_strerror(errno)); |
|||
connection_close(con); |
|||
} |
|||
return; |
|||
case 0: |
|||
/* end of file */ |
|||
connection_close(con); |
|||
return; |
|||
default: |
|||
break; |
|||
} |
|||
g_string_append_len(con->send_server_buf, readbuf, l); |
|||
if (con->send_server_buf->len > 4*4096) ev_io_rem_events(srv->loop, w, EV_READ); |
|||
ev_io_add_events(srv->loop, &con->w_server, EV_WRITE); |
|||
} |
|||
if (revents & EV_WRITE) { |
|||
if (con->send_client_buf->len > 0) { |
|||
int l = write(w->fd, con->send_client_buf->str, con->send_client_buf->len); |
|||
switch (l) { |
|||
case -1: |
|||
switch (errno) { |
|||
case EAGAIN: |
|||
case EINTR: |
|||
break; |
|||
default: |
|||
g_warning("couldn't write to client: %s", g_strerror(errno)); |
|||
connection_close(con); |
|||
} |
|||
return; |
|||
} |
|||
g_string_erase(con->send_client_buf, 0, l); |
|||
if (con->send_client_buf->len < 4*4096) ev_io_add_events(srv->loop, &con->w_client, EV_READ); |
|||
} |
|||
if (con->send_client_buf->len == 0) ev_io_rem_events(srv->loop, w, EV_WRITE); |
|||
} |
|||
} |
|||
|
|||
void connection_new(server *srv, int fd_server) { |
|||
connection *con; |
|||
int fd_client; |
|||
|
|||
fd_init(fd_server); |
|||
con = g_slice_new0(connection); |
|||
con->srv = srv; |
|||
con->fd_server = fd_server; |
|||
con->fd_client = -1; |
|||
ev_io_init(&con->w_server, fd_server_cb, fd_server, 0); |
|||
con->w_server.data = con; |
|||
ev_io_init(&con->w_client, fd_client_cb, -1, 0); |
|||
con->w_client.data = con; |
|||
con->send_client_buf = g_string_sized_new(0); |
|||
con->send_server_buf = g_string_sized_new(0); |
|||
|
|||
if (-1 == (fd_client = socket(AF_UNIX, SOCK_STREAM, 0))) { |
|||
g_warning("couldn't create socket: %s", g_strerror(errno)); |
|||
connection_close(con); |
|||
} |
|||
fd_init(fd_client); |
|||
con->fd_client = fd_client; |
|||
ev_io_set(&con->w_client, fd_client, EV_WRITE | EV_READ); |
|||
con->client_connected = FALSE; |
|||
connection_connect(con); |
|||
} |
@ -0,0 +1,187 @@ |
|||
|
|||
#include "fcgi-debug.h" |
|||
|
|||
static void accept_cb(struct ev_loop *loop, struct ev_io *w, int revents) { |
|||
server *srv = (server*) w->data; |
|||
int fd; |
|||
UNUSED(loop); |
|||
UNUSED(revents); |
|||
|
|||
if (-1 == (fd = accept(w->fd, NULL, NULL))) { |
|||
g_error("Couldn't accept: %s", g_strerror(errno)); |
|||
} |
|||
|
|||
connection_new(srv, fd); |
|||
} |
|||
|
|||
#define CATCH_SIGNAL(loop, cb, n) do {\ |
|||
ev_init(&srv->sig_w_##n, cb); \ |
|||
ev_signal_set(&srv->sig_w_##n, SIG##n); \ |
|||
ev_signal_start(loop, &srv->sig_w_##n); \ |
|||
srv->sig_w_##n.data = srv; \ |
|||
ev_unref(loop); /* Signal watchers shouldn't keep loop alive */ \ |
|||
} while (0) |
|||
|
|||
#define UNCATCH_SIGNAL(loop, n) do {\ |
|||
ev_ref(loop); \ |
|||
ev_signal_stop(loop, &srv->sig_w_##n); \ |
|||
} while (0) |
|||
|
|||
void server_stop(server *srv) { |
|||
if (srv->tmpfile_name) { |
|||
unlink(srv->tmpfile_name); |
|||
g_free(srv->tmpfile_name); |
|||
srv->tmpfile_name = NULL; |
|||
} |
|||
if (srv->sockfile_name) { |
|||
unlink(srv->sockfile_name); |
|||
g_free(srv->sockfile_name); |
|||
srv->sockfile_name = NULL; |
|||
} |
|||
ev_io_stop(srv->loop, &srv->w_accept); |
|||
close(0); |
|||
if (!srv->exiting) { |
|||
if (-1 != srv->child) kill(srv->child, SIGINT); |
|||
} else { |
|||
if (-1 != srv->child) kill(srv->child, SIGTERM); |
|||
|
|||
if (!srv->stopped_signals) { |
|||
srv->stopped_signals = TRUE; |
|||
/* reset default behaviour which will kill us next time */ |
|||
UNCATCH_SIGNAL(srv->loop, INT); |
|||
UNCATCH_SIGNAL(srv->loop, TERM); |
|||
UNCATCH_SIGNAL(srv->loop, PIPE); |
|||
UNCATCH_SIGNAL(srv->loop, HUP); |
|||
} |
|||
} |
|||
} |
|||
|
|||
static void child_cb(struct ev_loop *loop, struct ev_child *w, int revents) { |
|||
server *srv = (server*) w->data; |
|||
UNUSED(revents); |
|||
|
|||
ev_child_stop(loop, w); |
|||
g_message ("process %d exited with status %d", w->rpid, w->rstatus); |
|||
srv->child = -1; |
|||
server_stop(srv); |
|||
} |
|||
|
|||
static void sigint_cb(struct ev_loop *loop, struct ev_signal *w, int revents) { |
|||
server *srv = (server*) w->data; |
|||
UNUSED(loop); |
|||
UNUSED(revents); |
|||
|
|||
if (!srv->exiting) { |
|||
g_message("Got signal, shutdown"); |
|||
} else if (w->signum != SIGINT && w->signum != SIGTERM) { |
|||
return; /* ignore */ |
|||
} else { |
|||
g_message("Got second signal, force shutdown"); |
|||
} |
|||
server_stop(srv); |
|||
if (w->signum == SIGINT || w->signum == SIGTERM) srv->exiting = TRUE; |
|||
} |
|||
|
|||
static void sigpipe_cb(struct ev_loop *loop, struct ev_signal *w, int revents) { |
|||
/* ignore */ |
|||
UNUSED(loop); UNUSED(w); UNUSED(revents); |
|||
} |
|||
|
|||
void create_tmp_addr(server *srv) { |
|||
gchar *fn = g_strdup("/tmp/fcgi-debug.XXXXXX"); |
|||
int fd; |
|||
|
|||
struct sockaddr_un *sun; |
|||
gsize slen = strlen(fn) + sizeof(".sock") - 1, len = 1 + slen + (gsize) (((struct sockaddr_un *) 0)->sun_path); |
|||
sun = (struct sockaddr_un*) g_malloc0(len); |
|||
sun->sun_family = AF_UNIX; |
|||
|
|||
if (-1 == (fd = mkstemp(fn))) { |
|||
g_error("Couldn't make a tmpfile name"); |
|||
} |
|||
close(fd); |
|||
strcpy(sun->sun_path, fn); |
|||
strcat(sun->sun_path, ".sock"); |
|||
srv->sockfile_name = g_strdup(sun->sun_path); |
|||
srv->tmpfile_name = fn; |
|||
|
|||
srv->client.saddr = (struct sockaddr*) sun; |
|||
srv->client.addr_len = len; |
|||
} |
|||
|
|||
int client_bind(server *srv) { |
|||
int s; |
|||
|
|||
if (-1 == (s = socket(AF_UNIX, SOCK_STREAM, 0))) { |
|||
g_error("Couldn't create socket: %s", g_strerror(errno)); |
|||
} |
|||
|
|||
if (-1 == bind(s, srv->client.saddr, srv->client.addr_len)) { |
|||
g_error("Couldn't bind socket: %s", g_strerror(errno)); |
|||
} |
|||
|
|||
if (-1 == listen(s, 1024)) { |
|||
g_error("Couldn't listen on socket: %s", g_strerror(errno)); |
|||
} |
|||
|
|||
return s; |
|||
} |
|||
|
|||
pid_t spawn(char **argv, int s) { |
|||
pid_t child; |
|||
|
|||
switch (child = fork()) { |
|||
case -1: |
|||
g_error("Fork failed: %s", g_strerror(errno)); |
|||
break; |
|||
case 0: /* child */ |
|||
setsid(); |
|||
move2fd(s, 0); |
|||
execv(argv[1], argv+1); |
|||
g_error("execv failed: %s", g_strerror(errno)); |
|||
break; |
|||
default: |
|||
close(s); |
|||
break; |
|||
} |
|||
|
|||
return child; |
|||
} |
|||
|
|||
int main(int argc, char **argv) { |
|||
server *srv; |
|||
int s; |
|||
pid_t ch; |
|||
UNUSED(argc); |
|||
|
|||
srv = g_slice_new0(server); |
|||
srv->exiting = FALSE; |
|||
srv->child = -1; |
|||
srv->loop = ev_default_loop (0); |
|||
|
|||
CATCH_SIGNAL(srv->loop, sigint_cb, INT); |
|||
CATCH_SIGNAL(srv->loop, sigint_cb, TERM); |
|||
CATCH_SIGNAL(srv->loop, sigint_cb, HUP); |
|||
CATCH_SIGNAL(srv->loop, sigpipe_cb, PIPE); |
|||
|
|||
create_tmp_addr(srv); |
|||
s = client_bind(srv); |
|||
|
|||
ch = spawn(argv, s); |
|||
|
|||
srv->child = ch; |
|||
ev_child_init(&srv->w_child, child_cb, ch, 0); |
|||
srv->w_child.data = srv; |
|||
ev_child_start(srv->loop, &srv->w_child); |
|||
|
|||
fd_init(0); |
|||
ev_io_init(&srv->w_accept, accept_cb, 0, EV_READ); |
|||
srv->w_accept.data = srv; |
|||
ev_io_start(srv->loop, &srv->w_accept); |
|||
|
|||
ev_loop(srv->loop, 0); |
|||
|
|||
g_message("exit fcgi-debug"); |
|||
server_stop(srv); |
|||
return 0; |
|||
} |
@ -0,0 +1,70 @@ |
|||
|
|||
#include <ev.h> |
|||
#include <glib.h> |
|||
|
|||
#include <errno.h> |
|||
#include <fcntl.h> |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include <sys/socket.h> |
|||
#include <sys/stat.h> |
|||
#include <sys/un.h> |
|||
#include <unistd.h> |
|||
|
|||
#define UNUSED(x) ( (void)(x) ) |
|||
|
|||
struct addr; |
|||
typedef struct addr addr; |
|||
|
|||
struct server; |
|||
typedef struct server server; |
|||
|
|||
struct connection; |
|||
typedef struct connection connection; |
|||
|
|||
struct addr { |
|||
struct sockaddr *saddr; |
|||
socklen_t addr_len; |
|||
}; |
|||
|
|||
struct server { |
|||
struct ev_loop *loop; |
|||
|
|||
ev_signal |
|||
sig_w_INT, |
|||
sig_w_TERM, |
|||
sig_w_PIPE, |
|||
sig_w_HUP |
|||
; |
|||
|
|||
ev_child w_child; |
|||
ev_io w_accept; |
|||
int child; |
|||
|
|||
gchar *tmpfile_name, *sockfile_name; |
|||
addr client; |
|||
|
|||
gboolean exiting, stopped_signals; |
|||
}; |
|||
|
|||
struct connection { |
|||
server *srv; |
|||
int fd_server, fd_client; |
|||
ev_io w_server, w_client; |
|||
gboolean client_connected; |
|||
|
|||
GString *send_client_buf, *send_server_buf; |
|||
}; |
|||
|
|||
|
|||
/* tools.c */ |
|||
void move2fd(int srcfd, int dstfd); |
|||
void move2devnull(int fd); |
|||
void fd_init(int fd); |
|||
|
|||
void ev_io_add_events(struct ev_loop *loop, ev_io *watcher, int events); |
|||
void ev_io_rem_events(struct ev_loop *loop, ev_io *watcher, int events); |
|||
void ev_io_set_events(struct ev_loop *loop, ev_io *watcher, int events); |
|||
|
|||
/* connection.c */ |
|||
void connection_new(server *srv, int fd_server); |
@ -0,0 +1,51 @@ |
|||
#include "fcgi-debug.h" |
|||
|
|||
/* move a fd to another and close the old one */ |
|||
void move2fd(int srcfd, int dstfd) { |
|||
if (srcfd != dstfd) { |
|||
close(dstfd); |
|||
dup2(srcfd, dstfd); |
|||
close(srcfd); |
|||
} |
|||
} |
|||
|
|||
/* replace an fd with /dev/null */ |
|||
void move2devnull(int fd) { |
|||
move2fd(open("/dev/null", O_RDWR), fd); |
|||
} |
|||
|
|||
void fd_init(int fd) { |
|||
#ifdef _WIN32 |
|||
int i = 1; |
|||
#endif |
|||
#ifdef FD_CLOEXEC |
|||
/* close fd on exec (cgi) */ |
|||
fcntl(fd, F_SETFD, FD_CLOEXEC); |
|||
#endif |
|||
#ifdef O_NONBLOCK |
|||
fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR); |
|||
#elif defined _WIN32 |
|||
ioctlsocket(fd, FIONBIO, &i); |
|||
#endif |
|||
} |
|||
|
|||
void ev_io_add_events(struct ev_loop *loop, ev_io *watcher, int events) { |
|||
if ((watcher->events & events) == events) return; |
|||
ev_io_stop(loop, watcher); |
|||
ev_io_set(watcher, watcher->fd, watcher->events | events); |
|||
ev_io_start(loop, watcher); |
|||
} |
|||
|
|||
void ev_io_rem_events(struct ev_loop *loop, ev_io *watcher, int events) { |
|||
if (0 == (watcher->events & events)) return; |
|||
ev_io_stop(loop, watcher); |
|||
ev_io_set(watcher, watcher->fd, watcher->events & ~events); |
|||
ev_io_start(loop, watcher); |
|||
} |
|||
|
|||
void ev_io_set_events(struct ev_loop *loop, ev_io *watcher, int events) { |
|||
if (events == (watcher->events & (EV_READ | EV_WRITE))) return; |
|||
ev_io_stop(loop, watcher); |
|||
ev_io_set(watcher, watcher->fd, (watcher->events & ~(EV_READ | EV_WRITE)) | events); |
|||
ev_io_start(loop, watcher); |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue