You are viewing a plain text version of this content. The canonical link for it is here.
Posted to axis-cvs@ws.apache.org by di...@apache.org on 2008/07/22 06:35:46 UTC
svn commit: r678637 [40/46] - in
/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd: ./
autom4te.cache/ cygwin/ doc/ openwrt/ src/ tests/ tests/docroot/
tests/docroot/123/ tests/docroot/www/ tests/docroot/www/dummydir/
tests/docroot/www/expire/ ...
Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network.c
URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network.c?rev=678637&view=auto
==============================================================================
--- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network.c (added)
+++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network.c Mon Jul 21 21:35:35 2008
@@ -0,0 +1,672 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "network.h"
+#include "fdevent.h"
+#include "log.h"
+#include "connections.h"
+#include "plugin.h"
+#include "joblist.h"
+
+#include "network_backends.h"
+#include "sys-mmap.h"
+#include "sys-socket.h"
+
+#ifdef USE_OPENSSL
+# include <openssl/ssl.h>
+# include <openssl/err.h>
+# include <openssl/rand.h>
+#endif
+
+handler_t network_server_handle_fdevent(void *s, void *context, int revents) {
+ server *srv = (server *)s;
+ server_socket *srv_socket = (server_socket *)context;
+ connection *con;
+ int loops = 0;
+
+ UNUSED(context);
+
+ if (revents != FDEVENT_IN) {
+ log_error_write(srv, __FILE__, __LINE__, "sdd",
+ "strange event for server socket",
+ srv_socket->fd,
+ revents);
+ return HANDLER_ERROR;
+ }
+
+ /* accept()s at most 100 connections directly
+ *
+ * we jump out after 100 to give the waiting connections a chance */
+ for (loops = 0; loops < 100 && NULL != (con = connection_accept(srv, srv_socket)); loops++) {
+ handler_t r;
+
+ connection_state_machine(srv, con);
+
+ switch(r = plugins_call_handle_joblist(srv, con)) {
+ case HANDLER_FINISHED:
+ case HANDLER_GO_ON:
+ break;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "d", r);
+ break;
+ }
+ }
+ return HANDLER_GO_ON;
+}
+
+int network_server_init(server *srv, buffer *host_token, specific_config *s) {
+ int val;
+ socklen_t addr_len;
+ server_socket *srv_socket;
+ char *sp;
+ unsigned int port = 0;
+ const char *host;
+ buffer *b;
+ int is_unix_domain_socket = 0;
+ int fd;
+
+#ifdef SO_ACCEPTFILTER
+ struct accept_filter_arg afa;
+#endif
+
+#ifdef __WIN32
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ int err;
+
+ wVersionRequested = MAKEWORD( 2, 2 );
+
+ err = WSAStartup( wVersionRequested, &wsaData );
+ if ( err != 0 ) {
+ /* Tell the user that we could not find a usable */
+ /* WinSock DLL. */
+ return -1;
+ }
+#endif
+
+ srv_socket = calloc(1, sizeof(*srv_socket));
+ srv_socket->fd = -1;
+
+ srv_socket->srv_token = buffer_init();
+ buffer_copy_string_buffer(srv_socket->srv_token, host_token);
+
+ b = buffer_init();
+ buffer_copy_string_buffer(b, host_token);
+
+ /* ipv4:port
+ * [ipv6]:port
+ */
+ if (NULL == (sp = strrchr(b->ptr, ':'))) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "value of $SERVER[\"socket\"] has to be \"ip:port\".", b);
+
+ return -1;
+ }
+
+ host = b->ptr;
+
+ /* check for [ and ] */
+ if (b->ptr[0] == '[' && *(sp-1) == ']') {
+ *(sp-1) = '\0';
+ host++;
+
+ s->use_ipv6 = 1;
+ }
+
+ *(sp++) = '\0';
+
+ port = strtol(sp, NULL, 10);
+
+ if (host[0] == '/') {
+ /* host is a unix-domain-socket */
+ is_unix_domain_socket = 1;
+ } else if (port == 0 || port > 65535) {
+ log_error_write(srv, __FILE__, __LINE__, "sd", "port out of range:", port);
+
+ return -1;
+ }
+
+ if (*host == '\0') host = NULL;
+
+ if (is_unix_domain_socket) {
+#ifdef HAVE_SYS_UN_H
+
+ srv_socket->addr.plain.sa_family = AF_UNIX;
+
+ if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, 0))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
+ return -1;
+ }
+#else
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "ERROR: Unix Domain sockets are not supported.");
+ return -1;
+#endif
+ }
+
+#ifdef HAVE_IPV6
+ if (s->use_ipv6) {
+ srv_socket->addr.plain.sa_family = AF_INET6;
+
+ if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
+ return -1;
+ }
+ srv_socket->use_ipv6 = 1;
+ }
+#endif
+
+ if (srv_socket->fd == -1) {
+ srv_socket->addr.plain.sa_family = AF_INET;
+ if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
+ return -1;
+ }
+ }
+
+ /* */
+ srv->cur_fds = srv_socket->fd;
+
+ val = 1;
+ if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "socketsockopt failed:", strerror(errno));
+ return -1;
+ }
+
+ switch(srv_socket->addr.plain.sa_family) {
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ memset(&srv_socket->addr, 0, sizeof(struct sockaddr_in6));
+ srv_socket->addr.ipv6.sin6_family = AF_INET6;
+ if (host == NULL) {
+ srv_socket->addr.ipv6.sin6_addr = in6addr_any;
+ } else {
+ struct addrinfo hints, *res;
+ int r;
+
+ memset(&hints, 0, sizeof(hints));
+
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ if (0 != (r = getaddrinfo(host, NULL, &hints, &res))) {
+ log_error_write(srv, __FILE__, __LINE__,
+ "sssss", "getaddrinfo failed: ",
+ gai_strerror(r), "'", host, "'");
+
+ return -1;
+ }
+
+ memcpy(&(srv_socket->addr), res->ai_addr, res->ai_addrlen);
+
+ freeaddrinfo(res);
+ }
+ srv_socket->addr.ipv6.sin6_port = htons(port);
+ addr_len = sizeof(struct sockaddr_in6);
+ break;
+#endif
+ case AF_INET:
+ memset(&srv_socket->addr, 0, sizeof(struct sockaddr_in));
+ srv_socket->addr.ipv4.sin_family = AF_INET;
+ if (host == NULL) {
+ srv_socket->addr.ipv4.sin_addr.s_addr = htonl(INADDR_ANY);
+ } else {
+ struct hostent *he;
+ if (NULL == (he = gethostbyname(host))) {
+ log_error_write(srv, __FILE__, __LINE__,
+ "sds", "gethostbyname failed: ",
+ h_errno, host);
+ return -1;
+ }
+
+ if (he->h_addrtype != AF_INET) {
+ log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
+ return -1;
+ }
+
+ if (he->h_length != sizeof(struct in_addr)) {
+ log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
+ return -1;
+ }
+
+ memcpy(&(srv_socket->addr.ipv4.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
+ }
+ srv_socket->addr.ipv4.sin_port = htons(port);
+
+ addr_len = sizeof(struct sockaddr_in);
+
+ break;
+ case AF_UNIX:
+ srv_socket->addr.un.sun_family = AF_UNIX;
+ strcpy(srv_socket->addr.un.sun_path, host);
+
+#ifdef SUN_LEN
+ addr_len = SUN_LEN(&srv_socket->addr.un);
+#else
+ /* stevens says: */
+ addr_len = strlen(host) + 1 + sizeof(srv_socket->addr.un.sun_family);
+#endif
+
+ /* check if the socket exists and try to connect to it. */
+ if (-1 != (fd = connect(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len))) {
+ close(fd);
+
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "server socket is still in use:",
+ host);
+
+
+ return -1;
+ }
+
+ /* connect failed */
+ switch(errno) {
+ case ECONNREFUSED:
+ unlink(host);
+ break;
+ case ENOENT:
+ break;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "testing socket failed:",
+ host, strerror(errno));
+
+ return -1;
+ }
+
+ break;
+ default:
+ addr_len = 0;
+
+ return -1;
+ }
+
+ if (0 != bind(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
+ switch(srv_socket->addr.plain.sa_family) {
+ case AF_UNIX:
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "can't bind to socket:",
+ host, strerror(errno));
+ break;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "ssds",
+ "can't bind to port:",
+ host, port, strerror(errno));
+ break;
+ }
+ return -1;
+ }
+
+ if (-1 == listen(srv_socket->fd, 128 * 8)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "listen failed: ", strerror(errno));
+ return -1;
+ }
+
+ if (s->is_ssl) {
+#ifdef USE_OPENSSL
+ if (srv->ssl_is_init == 0) {
+ SSL_load_error_strings();
+ SSL_library_init();
+ srv->ssl_is_init = 1;
+
+ if (0 == RAND_status()) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ "not enough entropy in the pool");
+ return -1;
+ }
+ }
+
+ if (NULL == (s->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+
+ if (!s->ssl_use_sslv2) {
+ /* disable SSLv2 */
+ if (SSL_OP_NO_SSLv2 != SSL_CTX_set_options(s->ssl_ctx, SSL_OP_NO_SSLv2)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+ }
+
+ if (!buffer_is_empty(s->ssl_cipher_list)) {
+ /* Disable support for low encryption ciphers */
+ if (SSL_CTX_set_cipher_list(s->ssl_ctx, s->ssl_cipher_list->ptr) != 1) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+ }
+
+ if (buffer_is_empty(s->ssl_pemfile)) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "ssl.pemfile has to be set");
+ return -1;
+ }
+
+ if (!buffer_is_empty(s->ssl_ca_file)) {
+ if (1 != SSL_CTX_load_verify_locations(s->ssl_ctx, s->ssl_ca_file->ptr, NULL)) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_file);
+ return -1;
+ }
+ }
+
+ if (SSL_CTX_use_certificate_file(s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
+ return -1;
+ }
+
+ if (SSL_CTX_use_PrivateKey_file (s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
+ ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
+ return -1;
+ }
+
+ if (SSL_CTX_check_private_key(s->ssl_ctx) != 1) {
+ log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:",
+ "Private key does not match the certificate public key, reason:",
+ ERR_error_string(ERR_get_error(), NULL),
+ s->ssl_pemfile);
+ return -1;
+ }
+ SSL_CTX_set_default_read_ahead(s->ssl_ctx, 1);
+ SSL_CTX_set_mode(s->ssl_ctx, SSL_CTX_get_mode(s->ssl_ctx) | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+
+ srv_socket->ssl_ctx = s->ssl_ctx;
+#else
+
+ buffer_free(srv_socket->srv_token);
+ free(srv_socket);
+
+ buffer_free(b);
+
+ log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
+ "ssl requested but openssl support is not compiled in");
+
+ return -1;
+#endif
+ } else {
+#ifdef SO_ACCEPTFILTER
+ /*
+ * FreeBSD accf_http filter
+ *
+ */
+ memset(&afa, 0, sizeof(afa));
+ strcpy(afa.af_name, "httpready");
+ if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) {
+ if (errno != ENOENT) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "can't set accept-filter 'httpready': ", strerror(errno));
+ }
+ }
+#endif
+ }
+
+ srv_socket->is_ssl = s->is_ssl;
+ srv_socket->fde_ndx = -1;
+
+ if (srv->srv_sockets.size == 0) {
+ srv->srv_sockets.size = 4;
+ srv->srv_sockets.used = 0;
+ srv->srv_sockets.ptr = malloc(srv->srv_sockets.size * sizeof(server_socket));
+ } else if (srv->srv_sockets.used == srv->srv_sockets.size) {
+ srv->srv_sockets.size += 4;
+ srv->srv_sockets.ptr = realloc(srv->srv_sockets.ptr, srv->srv_sockets.size * sizeof(server_socket));
+ }
+
+ srv->srv_sockets.ptr[srv->srv_sockets.used++] = srv_socket;
+
+ buffer_free(b);
+
+ return 0;
+}
+
+int network_close(server *srv) {
+ size_t i;
+ for (i = 0; i < srv->srv_sockets.used; i++) {
+ server_socket *srv_socket = srv->srv_sockets.ptr[i];
+
+ if (srv_socket->fd != -1) {
+ /* check if server fd are already registered */
+ if (srv_socket->fde_ndx != -1) {
+ fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd);
+ fdevent_unregister(srv->ev, srv_socket->fd);
+ }
+
+ close(srv_socket->fd);
+ }
+
+ buffer_free(srv_socket->srv_token);
+
+ free(srv_socket);
+ }
+
+ free(srv->srv_sockets.ptr);
+
+ return 0;
+}
+
+typedef enum {
+ NETWORK_BACKEND_UNSET,
+ NETWORK_BACKEND_WRITE,
+ NETWORK_BACKEND_WRITEV,
+ NETWORK_BACKEND_LINUX_SENDFILE,
+ NETWORK_BACKEND_FREEBSD_SENDFILE,
+ NETWORK_BACKEND_SOLARIS_SENDFILEV
+} network_backend_t;
+
+int network_init(server *srv) {
+ buffer *b;
+ size_t i;
+ network_backend_t backend;
+
+ struct nb_map {
+ network_backend_t nb;
+ const char *name;
+ } network_backends[] = {
+ /* lowest id wins */
+#if defined USE_LINUX_SENDFILE
+ { NETWORK_BACKEND_LINUX_SENDFILE, "linux-sendfile" },
+#endif
+#if defined USE_FREEBSD_SENDFILE
+ { NETWORK_BACKEND_FREEBSD_SENDFILE, "freebsd-sendfile" },
+#endif
+#if defined USE_SOLARIS_SENDFILEV
+ { NETWORK_BACKEND_SOLARIS_SENDFILEV, "solaris-sendfilev" },
+#endif
+#if defined USE_WRITEV
+ { NETWORK_BACKEND_WRITEV, "writev" },
+#endif
+ { NETWORK_BACKEND_WRITE, "write" },
+ { NETWORK_BACKEND_UNSET, NULL }
+ };
+
+ b = buffer_init();
+
+ buffer_copy_string_buffer(b, srv->srvconf.bindhost);
+ buffer_append_string(b, ":");
+ buffer_append_long(b, srv->srvconf.port);
+
+ if (0 != network_server_init(srv, b, srv->config_storage[0])) {
+ return -1;
+ }
+ buffer_free(b);
+
+#ifdef USE_OPENSSL
+ srv->network_ssl_backend_write = network_write_chunkqueue_openssl;
+#endif
+
+ /* get a usefull default */
+ backend = network_backends[0].nb;
+
+ /* match name against known types */
+ if (!buffer_is_empty(srv->srvconf.network_backend)) {
+ for (i = 0; network_backends[i].name; i++) {
+ /**/
+ if (buffer_is_equal_string(srv->srvconf.network_backend, network_backends[i].name, strlen(network_backends[i].name))) {
+ backend = network_backends[i].nb;
+ break;
+ }
+ }
+ if (NULL == network_backends[i].name) {
+ /* we don't know it */
+
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "server.network-backend has a unknown value:",
+ srv->srvconf.network_backend);
+
+ return -1;
+ }
+ }
+
+ switch(backend) {
+ case NETWORK_BACKEND_WRITE:
+ srv->network_backend_write = network_write_chunkqueue_write;
+ break;
+#ifdef USE_WRITEV
+ case NETWORK_BACKEND_WRITEV:
+ srv->network_backend_write = network_write_chunkqueue_writev;
+ break;
+#endif
+#ifdef USE_LINUX_SENDFILE
+ case NETWORK_BACKEND_LINUX_SENDFILE:
+ srv->network_backend_write = network_write_chunkqueue_linuxsendfile;
+ break;
+#endif
+#ifdef USE_FREEBSD_SENDFILE
+ case NETWORK_BACKEND_FREEBSD_SENDFILE:
+ srv->network_backend_write = network_write_chunkqueue_freebsdsendfile;
+ break;
+#endif
+#ifdef USE_SOLARIS_SENDFILEV
+ case NETWORK_BACKEND_SOLARIS_SENDFILEV:
+ srv->network_backend_write = network_write_chunkqueue_solarissendfilev;
+ break;
+#endif
+ default:
+ return -1;
+ }
+
+ /* check for $SERVER["socket"] */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ specific_config *s = srv->config_storage[i];
+ size_t j;
+
+ /* not our stage */
+ if (COMP_SERVER_SOCKET != dc->comp) continue;
+
+ if (dc->cond != CONFIG_COND_EQ) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "only == is allowed for $SERVER[\"socket\"].");
+
+ return -1;
+ }
+
+ /* check if we already know this socket,
+ * if yes, don't init it */
+ for (j = 0; j < srv->srv_sockets.used; j++) {
+ if (buffer_is_equal(srv->srv_sockets.ptr[j]->srv_token, dc->string)) {
+ break;
+ }
+ }
+
+ if (j == srv->srv_sockets.used) {
+ if (0 != network_server_init(srv, dc->string, s)) return -1;
+ }
+ }
+
+ return 0;
+}
+
+int network_register_fdevents(server *srv) {
+ size_t i;
+
+ if (-1 == fdevent_reset(srv->ev)) {
+ return -1;
+ }
+
+ /* register fdevents after reset */
+ for (i = 0; i < srv->srv_sockets.used; i++) {
+ server_socket *srv_socket = srv->srv_sockets.ptr[i];
+
+ fdevent_register(srv->ev, srv_socket->fd, network_server_handle_fdevent, srv_socket);
+ fdevent_event_add(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
+ }
+ return 0;
+}
+
+int network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq) {
+ int ret = -1;
+ off_t written = 0;
+#ifdef TCP_CORK
+ int corked = 0;
+#endif
+ server_socket *srv_socket = con->srv_socket;
+
+ if (con->conf.global_kbytes_per_second &&
+ *(con->conf.global_bytes_per_second_cnt_ptr) > con->conf.global_kbytes_per_second * 1024) {
+ /* we reached the global traffic limit */
+
+ con->traffic_limit_reached = 1;
+ joblist_append(srv, con);
+
+ return 1;
+ }
+
+ written = cq->bytes_out;
+
+#ifdef TCP_CORK
+ /* Linux: put a cork into the socket as we want to combine the write() calls
+ * but only if we really have multiple chunks
+ */
+ if (cq->first && cq->first->next) {
+ corked = 1;
+ setsockopt(con->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
+ }
+#endif
+
+ if (srv_socket->is_ssl) {
+#ifdef USE_OPENSSL
+ ret = srv->network_ssl_backend_write(srv, con, con->ssl, cq);
+#endif
+ } else {
+ ret = srv->network_backend_write(srv, con, con->fd, cq);
+ }
+
+ if (ret >= 0) {
+ chunkqueue_remove_finished_chunks(cq);
+ ret = chunkqueue_is_empty(cq) ? 0 : 1;
+ }
+
+#ifdef TCP_CORK
+ if (corked) {
+ corked = 0;
+ setsockopt(con->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
+ }
+#endif
+
+ written = cq->bytes_out - written;
+ con->bytes_written += written;
+ con->bytes_written_cur_second += written;
+
+ *(con->conf.global_bytes_per_second_cnt_ptr) += written;
+
+ if (con->conf.kbytes_per_second &&
+ (con->bytes_written_cur_second > con->conf.kbytes_per_second * 1024)) {
+ /* we reached the traffic limit */
+
+ con->traffic_limit_reached = 1;
+ joblist_append(srv, con);
+ }
+ return ret;
+}
Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network.h
URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network.h?rev=678637&view=auto
==============================================================================
--- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network.h (added)
+++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network.h Mon Jul 21 21:35:35 2008
@@ -0,0 +1,13 @@
+#ifndef _NETWORK_H_
+#define _NETWORK_H_
+
+#include "server.h"
+
+int network_write_chunkqueue(server *srv, connection *con, chunkqueue *c);
+
+int network_init(server *srv);
+int network_close(server *srv);
+
+int network_register_fdevents(server *srv);
+
+#endif
Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network_backends.h
URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network_backends.h?rev=678637&view=auto
==============================================================================
--- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network_backends.h (added)
+++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network_backends.h Mon Jul 21 21:35:35 2008
@@ -0,0 +1,58 @@
+#ifndef _NETWORK_BACKENDS_H_
+#define _NETWORK_BACKENDS_H_
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+
+/* 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
+
+#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
+#endif
+
+#if defined HAVE_SYS_UIO_H && defined HAVE_WRITEV && defined HAVE_SEND_FILE && defined(__aix)
+# define USE_AIX_SENDFILE
+#endif
+
+#include "base.h"
+
+
+int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqueue *cq);
+int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq);
+int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq);
+int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int fd, chunkqueue *cq);
+int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq);
+#ifdef USE_OPENSSL
+int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq);
+#endif
+
+#endif
Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network_freebsd_sendfile.c
URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network_freebsd_sendfile.c?rev=678637&view=auto
==============================================================================
--- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network_freebsd_sendfile.c (added)
+++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network_freebsd_sendfile.c Mon Jul 21 21:35:35 2008
@@ -0,0 +1,227 @@
+#include "network_backends.h"
+
+#ifdef USE_FREEBSD_SENDFILE
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "network.h"
+#include "fdevent.h"
+#include "log.h"
+#include "stat_cache.h"
+
+
+#ifndef UIO_MAXIOV
+# if defined(__FreeBSD__) || defined(__DragonFly__)
+/* FreeBSD 4.7, 4.9 defined it in sys/uio.h only if _KERNEL is specified */
+# define UIO_MAXIOV 1024
+# endif
+#endif
+
+int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int fd, chunkqueue *cq) {
+ chunk *c;
+ size_t chunks_written = 0;
+
+ for(c = cq->first; c; c = c->next, chunks_written++) {
+ int chunk_finished = 0;
+
+ switch(c->type) {
+ case MEM_CHUNK: {
+ char * offset;
+ size_t toSend;
+ ssize_t r;
+
+ size_t num_chunks, i;
+ struct iovec chunks[UIO_MAXIOV];
+ chunk *tc;
+ size_t num_bytes = 0;
+
+ /* we can't send more then SSIZE_MAX bytes in one chunk */
+
+ /* build writev list
+ *
+ * 1. limit: num_chunks < UIO_MAXIOV
+ * 2. limit: num_bytes < SSIZE_MAX
+ */
+ for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
+
+ for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
+ if (tc->mem->used == 0) {
+ chunks[i].iov_base = tc->mem->ptr;
+ chunks[i].iov_len = 0;
+ } else {
+ offset = tc->mem->ptr + tc->offset;
+ toSend = tc->mem->used - 1 - tc->offset;
+
+ chunks[i].iov_base = offset;
+
+ /* protect the return value of writev() */
+ if (toSend > SSIZE_MAX ||
+ num_bytes + toSend > SSIZE_MAX) {
+ chunks[i].iov_len = SSIZE_MAX - num_bytes;
+
+ num_chunks = i + 1;
+ break;
+ } else {
+ chunks[i].iov_len = toSend;
+ }
+
+ num_bytes += toSend;
+ }
+ }
+
+ if ((r = writev(fd, chunks, num_chunks)) < 0) {
+ switch (errno) {
+ case EAGAIN:
+ case EINTR:
+ r = 0;
+ break;
+ case ENOTCONN:
+ case EPIPE:
+ case ECONNRESET:
+ return -2;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "ssd",
+ "writev failed:", strerror(errno), fd);
+
+ return -1;
+ }
+
+ r = 0;
+ }
+
+ /* check which chunks have been written */
+ cq->bytes_out += r;
+
+ for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
+ if (r >= (ssize_t)chunks[i].iov_len) {
+ /* written */
+ r -= chunks[i].iov_len;
+ tc->offset += chunks[i].iov_len;
+
+ if (chunk_finished) {
+ /* skip the chunks from further touches */
+ chunks_written++;
+ c = c->next;
+ } else {
+ /* chunks_written + c = c->next is done in the for()*/
+ chunk_finished++;
+ }
+ } else {
+ /* partially written */
+
+ tc->offset += r;
+ chunk_finished = 0;
+
+ break;
+ }
+ }
+
+ break;
+ }
+ case FILE_CHUNK: {
+ off_t offset, r;
+ size_t toSend;
+ stat_cache_entry *sce = NULL;
+
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ strerror(errno), c->file.name);
+ return -1;
+ }
+
+ offset = c->file.start + c->offset;
+ /* limit the toSend to 2^31-1 bytes in a chunk */
+ toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
+ ((1 << 30) - 1) : c->file.length - c->offset;
+
+ if (-1 == c->file.fd) {
+ if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
+
+ return -1;
+ }
+
+#ifdef FD_CLOEXEC
+ fcntl(c->file.fd, F_SETFD, FD_CLOEXEC);
+#endif
+ }
+
+ r = 0;
+
+ /* FreeBSD sendfile() */
+ if (-1 == sendfile(c->file.fd, fd, offset, toSend, NULL, &r, 0)) {
+ switch(errno) {
+ case EAGAIN:
+ break;
+ case ENOTCONN:
+ return -2;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile: ", strerror(errno), errno);
+ return -1;
+ }
+ }
+
+ if (r == 0) {
+ int oerrno = errno;
+ /* We got an event to write but we wrote nothing
+ *
+ * - the file shrinked -> error
+ * - the remote side closed inbetween -> remote-close */
+
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
+ /* file is gone ? */
+ return -1;
+ }
+
+ if (offset >= sce->st.st_size) {
+ /* file shrinked, close the connection */
+ errno = oerrno;
+
+ return -1;
+ }
+
+ errno = oerrno;
+ return -2;
+ }
+
+ c->offset += r;
+ cq->bytes_out += r;
+
+ if (c->offset == c->file.length) {
+ chunk_finished = 1;
+ }
+
+ break;
+ }
+ default:
+
+ log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
+
+ return -1;
+ }
+
+ if (!chunk_finished) {
+ /* not finished yet */
+
+ break;
+ }
+ }
+
+ return chunks_written;
+}
+
+#endif
Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network_linux_sendfile.c
URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network_linux_sendfile.c?rev=678637&view=auto
==============================================================================
--- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network_linux_sendfile.c (added)
+++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network_linux_sendfile.c Mon Jul 21 21:35:35 2008
@@ -0,0 +1,253 @@
+#include "network_backends.h"
+
+#ifdef USE_LINUX_SENDFILE
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+#include "network.h"
+#include "fdevent.h"
+#include "log.h"
+#include "stat_cache.h"
+
+/* on linux 2.4.29 + debian/ubuntu we have crashes if this is enabled */
+#undef HAVE_POSIX_FADVISE
+
+int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq) {
+ chunk *c;
+ size_t chunks_written = 0;
+
+ for(c = cq->first; c; c = c->next, chunks_written++) {
+ int chunk_finished = 0;
+
+ switch(c->type) {
+ case MEM_CHUNK: {
+ char * offset;
+ size_t toSend;
+ ssize_t r;
+
+ size_t num_chunks, i;
+ struct iovec chunks[UIO_MAXIOV];
+ chunk *tc;
+ size_t num_bytes = 0;
+
+ /* we can't send more then SSIZE_MAX bytes in one chunk */
+
+ /* build writev list
+ *
+ * 1. limit: num_chunks < UIO_MAXIOV
+ * 2. limit: num_bytes < SSIZE_MAX
+ */
+ for (num_chunks = 0, tc = c;
+ tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV;
+ tc = tc->next, num_chunks++);
+
+ for (tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
+ if (tc->mem->used == 0) {
+ chunks[i].iov_base = tc->mem->ptr;
+ chunks[i].iov_len = 0;
+ } else {
+ offset = tc->mem->ptr + tc->offset;
+ toSend = tc->mem->used - 1 - tc->offset;
+
+ chunks[i].iov_base = offset;
+
+ /* protect the return value of writev() */
+ if (toSend > SSIZE_MAX ||
+ num_bytes + toSend > SSIZE_MAX) {
+ chunks[i].iov_len = SSIZE_MAX - num_bytes;
+
+ num_chunks = i + 1;
+ break;
+ } else {
+ chunks[i].iov_len = toSend;
+ }
+
+ num_bytes += toSend;
+ }
+ }
+
+ if ((r = writev(fd, chunks, num_chunks)) < 0) {
+ switch (errno) {
+ case EAGAIN:
+ case EINTR:
+ r = 0;
+ break;
+ case EPIPE:
+ case ECONNRESET:
+ return -2;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "ssd",
+ "writev failed:", strerror(errno), fd);
+
+ return -1;
+ }
+ }
+
+ /* check which chunks have been written */
+ cq->bytes_out += r;
+
+ for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
+ if (r >= (ssize_t)chunks[i].iov_len) {
+ /* written */
+ r -= chunks[i].iov_len;
+ tc->offset += chunks[i].iov_len;
+
+ if (chunk_finished) {
+ /* skip the chunks from further touches */
+ chunks_written++;
+ c = c->next;
+ } else {
+ /* chunks_written + c = c->next is done in the for()*/
+ chunk_finished++;
+ }
+ } else {
+ /* partially written */
+
+ tc->offset += r;
+ chunk_finished = 0;
+
+ break;
+ }
+ }
+
+ break;
+ }
+ case FILE_CHUNK: {
+ ssize_t r;
+ off_t offset;
+ size_t toSend;
+ stat_cache_entry *sce = NULL;
+
+ offset = c->file.start + c->offset;
+ /* limit the toSend to 2^31-1 bytes in a chunk */
+ toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
+ ((1 << 30) - 1) : c->file.length - c->offset;
+
+ /* open file if not already opened */
+ if (-1 == c->file.fd) {
+ if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
+
+ return -1;
+ }
+#ifdef FD_CLOEXEC
+ fcntl(c->file.fd, F_SETFD, FD_CLOEXEC);
+#endif
+#ifdef HAVE_POSIX_FADVISE
+ /* tell the kernel that we want to stream the file */
+ if (-1 == posix_fadvise(c->file.fd, 0, 0, POSIX_FADV_SEQUENTIAL)) {
+ if (ENOSYS != errno) {
+ log_error_write(srv, __FILE__, __LINE__, "ssd",
+ "posix_fadvise failed:", strerror(errno), c->file.fd);
+ }
+ }
+#endif
+ }
+
+ if (-1 == (r = sendfile(fd, c->file.fd, &offset, toSend))) {
+ switch (errno) {
+ case EAGAIN:
+ case EINTR:
+ /* ok, we can't send more, let's try later again */
+ r = 0;
+ break;
+ case EPIPE:
+ case ECONNRESET:
+ return -2;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "ssd",
+ "sendfile failed:", strerror(errno), fd);
+ return -1;
+ }
+ } else if (r == 0) {
+ int oerrno = errno;
+ /* We got an event to write but we wrote nothing
+ *
+ * - the file shrinked -> error
+ * - the remote side closed inbetween -> remote-close */
+
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
+ /* file is gone ? */
+ return -1;
+ }
+
+ if (offset > sce->st.st_size) {
+ /* file shrinked, close the connection */
+ errno = oerrno;
+
+ return -1;
+ }
+
+ errno = oerrno;
+ return -2;
+ }
+
+#ifdef HAVE_POSIX_FADVISE
+#if 0
+#define K * 1024
+#define M * 1024 K
+#define READ_AHEAD 4 M
+ /* check if we need a new chunk */
+ if ((c->offset & ~(READ_AHEAD - 1)) != ((c->offset + r) & ~(READ_AHEAD - 1))) {
+ /* tell the kernel that we want to stream the file */
+ if (-1 == posix_fadvise(c->file.fd, (c->offset + r) & ~(READ_AHEAD - 1), READ_AHEAD, POSIX_FADV_NOREUSE)) {
+ log_error_write(srv, __FILE__, __LINE__, "ssd",
+ "posix_fadvise failed:", strerror(errno), c->file.fd);
+ }
+ }
+#endif
+#endif
+
+ c->offset += r;
+ cq->bytes_out += r;
+
+ if (c->offset == c->file.length) {
+ chunk_finished = 1;
+
+ /* chunk_free() / chunk_reset() will cleanup for us but it is a ok to be faster :) */
+
+ if (c->file.fd != -1) {
+ close(c->file.fd);
+ c->file.fd = -1;
+ }
+ }
+
+ break;
+ }
+ default:
+
+ log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
+
+ return -1;
+ }
+
+ if (!chunk_finished) {
+ /* not finished yet */
+
+ break;
+ }
+ }
+
+ return chunks_written;
+}
+
+#endif
+#if 0
+network_linuxsendfile_init(void) {
+ p->write = network_linuxsendfile_write_chunkset;
+}
+#endif
Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network_openssl.c
URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network_openssl.c?rev=678637&view=auto
==============================================================================
--- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network_openssl.c (added)
+++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network_openssl.c Mon Jul 21 21:35:35 2008
@@ -0,0 +1,275 @@
+#include "network_backends.h"
+
+#ifdef USE_OPENSSL
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "network.h"
+#include "fdevent.h"
+#include "log.h"
+#include "stat_cache.h"
+
+# include <openssl/ssl.h>
+# include <openssl/err.h>
+
+int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq) {
+ int ssl_r;
+ chunk *c;
+ size_t chunks_written = 0;
+
+ /* this is a 64k sendbuffer
+ *
+ * it has to stay at the same location all the time to satisfy the needs
+ * of SSL_write to pass the SAME parameter in case of a _WANT_WRITE
+ *
+ * the buffer is allocated once, is NOT realloced and is NOT freed at shutdown
+ * -> we expect a 64k block to 'leak' in valgrind
+ *
+ *
+ * In reality we would like to use mmap() but we don't have a guarantee that
+ * we get the same mmap() address for each call. On openbsd the mmap() address
+ * even randomized.
+ * That means either we keep the mmap() open or we do a read() into a
+ * constant buffer
+ * */
+#define LOCAL_SEND_BUFSIZE (64 * 1024)
+ static char *local_send_buffer = NULL;
+
+ /* the remote side closed the connection before without shutdown request
+ * - IE
+ * - wget
+ * if keep-alive is disabled */
+
+ if (con->keep_alive == 0) {
+ SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
+ }
+
+ for(c = cq->first; c; c = c->next) {
+ int chunk_finished = 0;
+
+ switch(c->type) {
+ case MEM_CHUNK: {
+ char * offset;
+ size_t toSend;
+ ssize_t r;
+
+ if (c->mem->used == 0 || c->mem->used == 1) {
+ chunk_finished = 1;
+ break;
+ }
+
+ offset = c->mem->ptr + c->offset;
+ toSend = c->mem->used - 1 - c->offset;
+
+ /**
+ * SSL_write man-page
+ *
+ * WARNING
+ * When an SSL_write() operation has to be repeated because of
+ * SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, it must be
+ * repeated with the same arguments.
+ *
+ */
+
+ if ((r = SSL_write(ssl, offset, toSend)) <= 0) {
+ unsigned long err;
+
+ switch ((ssl_r = SSL_get_error(ssl, r))) {
+ case SSL_ERROR_WANT_WRITE:
+ break;
+ case SSL_ERROR_SYSCALL:
+ /* perhaps we have error waiting in our error-queue */
+ if (0 != (err = ERR_get_error())) {
+ do {
+ log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
+ ssl_r, r,
+ ERR_error_string(err, NULL));
+ } while((err = ERR_get_error()));
+ } else if (r == -1) {
+ /* no, but we have errno */
+ switch(errno) {
+ case EPIPE:
+ case ECONNRESET:
+ return -2;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
+ ssl_r, r, errno,
+ strerror(errno));
+ break;
+ }
+ } else {
+ /* neither error-queue nor errno ? */
+ log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
+ ssl_r, r, errno,
+ strerror(errno));
+ }
+
+ return -1;
+ case SSL_ERROR_ZERO_RETURN:
+ /* clean shutdown on the remote side */
+
+ if (r == 0) return -2;
+
+ /* fall through */
+ default:
+ while((err = ERR_get_error())) {
+ log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
+ ssl_r, r,
+ ERR_error_string(err, NULL));
+ }
+
+ return -1;
+ }
+ } else {
+ c->offset += r;
+ cq->bytes_out += r;
+ }
+
+ if (c->offset == (off_t)c->mem->used - 1) {
+ chunk_finished = 1;
+ }
+
+ break;
+ }
+ case FILE_CHUNK: {
+ char *s;
+ ssize_t r;
+ stat_cache_entry *sce = NULL;
+ int ifd;
+ int write_wait = 0;
+
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ strerror(errno), c->file.name);
+ return -1;
+ }
+
+ if (NULL == local_send_buffer) {
+ local_send_buffer = malloc(LOCAL_SEND_BUFSIZE);
+ assert(local_send_buffer);
+ }
+
+ do {
+ off_t offset = c->file.start + c->offset;
+ off_t toSend = c->file.length - c->offset;
+
+ if (toSend > LOCAL_SEND_BUFSIZE) toSend = LOCAL_SEND_BUFSIZE;
+
+ if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "open failed:", strerror(errno));
+
+ return -1;
+ }
+
+
+ lseek(ifd, offset, SEEK_SET);
+ if (-1 == (toSend = read(ifd, local_send_buffer, toSend))) {
+ close(ifd);
+ log_error_write(srv, __FILE__, __LINE__, "ss", "read failed:", strerror(errno));
+ return -1;
+ }
+
+ s = local_send_buffer;
+
+ close(ifd);
+
+ if ((r = SSL_write(ssl, s, toSend)) <= 0) {
+ unsigned long err;
+
+ switch ((ssl_r = SSL_get_error(ssl, r))) {
+ case SSL_ERROR_WANT_WRITE:
+ write_wait = 1;
+ break;
+ case SSL_ERROR_SYSCALL:
+ /* perhaps we have error waiting in our error-queue */
+ if (0 != (err = ERR_get_error())) {
+ do {
+ log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
+ ssl_r, r,
+ ERR_error_string(err, NULL));
+ } while((err = ERR_get_error()));
+ } else if (r == -1) {
+ /* no, but we have errno */
+ switch(errno) {
+ case EPIPE:
+ case ECONNRESET:
+ return -2;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
+ ssl_r, r, errno,
+ strerror(errno));
+ break;
+ }
+ } else {
+ /* neither error-queue nor errno ? */
+ log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
+ ssl_r, r, errno,
+ strerror(errno));
+ }
+
+ return -1;
+ case SSL_ERROR_ZERO_RETURN:
+ /* clean shutdown on the remote side */
+
+ if (r == 0) return -2;
+
+ /* fall thourgh */
+ default:
+ while((err = ERR_get_error())) {
+ log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
+ ssl_r, r,
+ ERR_error_string(err, NULL));
+ }
+
+ return -1;
+ }
+ } else {
+ c->offset += r;
+ cq->bytes_out += r;
+ }
+
+ if (c->offset == c->file.length) {
+ chunk_finished = 1;
+ }
+ } while(!chunk_finished && !write_wait);
+
+ break;
+ }
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "s", "type not known");
+
+ return -1;
+ }
+
+ if (!chunk_finished) {
+ /* not finished yet */
+
+ break;
+ }
+
+ chunks_written++;
+ }
+
+ return chunks_written;
+}
+#endif
+
+#if 0
+network_openssl_init(void) {
+ p->write_ssl = network_openssl_write_chunkset;
+}
+#endif
Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network_solaris_sendfilev.c
URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network_solaris_sendfilev.c?rev=678637&view=auto
==============================================================================
--- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network_solaris_sendfilev.c (added)
+++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network_solaris_sendfilev.c Mon Jul 21 21:35:35 2008
@@ -0,0 +1,213 @@
+#include "network_backends.h"
+
+#ifdef USE_SOLARIS_SENDFILEV
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include "network.h"
+#include "fdevent.h"
+#include "log.h"
+#include "stat_cache.h"
+
+#ifndef UIO_MAXIOV
+#define UIO_MAXIOV IOV_MAX
+#endif
+
+/**
+ * a very simple sendfilev() interface for solaris which can be optimised a lot more
+ * as solaris sendfilev() supports 'sending everythin in one syscall()'
+ *
+ * If you want such an interface and need the performance, just give me an account on
+ * a solaris box.
+ * - jan@kneschke.de
+ */
+
+
+int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq) {
+ chunk *c;
+ size_t chunks_written = 0;
+
+ for(c = cq->first; c; c = c->next, chunks_written++) {
+ int chunk_finished = 0;
+
+ switch(c->type) {
+ case MEM_CHUNK: {
+ char * offset;
+ size_t toSend;
+ ssize_t r;
+
+ size_t num_chunks, i;
+ struct iovec chunks[UIO_MAXIOV];
+ chunk *tc;
+
+ size_t num_bytes = 0;
+
+ /* we can't send more then SSIZE_MAX bytes in one chunk */
+
+ /* build writev list
+ *
+ * 1. limit: num_chunks < UIO_MAXIOV
+ * 2. limit: num_bytes < SSIZE_MAX
+ */
+ for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
+
+ for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
+ if (tc->mem->used == 0) {
+ chunks[i].iov_base = tc->mem->ptr;
+ chunks[i].iov_len = 0;
+ } else {
+ offset = tc->mem->ptr + tc->offset;
+ toSend = tc->mem->used - 1 - tc->offset;
+
+ chunks[i].iov_base = offset;
+
+ /* protect the return value of writev() */
+ if (toSend > SSIZE_MAX ||
+ num_bytes + toSend > SSIZE_MAX) {
+ chunks[i].iov_len = SSIZE_MAX - num_bytes;
+
+ num_chunks = i + 1;
+ break;
+ } else {
+ chunks[i].iov_len = toSend;
+ }
+
+ num_bytes += toSend;
+ }
+ }
+
+ if ((r = writev(fd, chunks, num_chunks)) < 0) {
+ switch (errno) {
+ case EAGAIN:
+ case EINTR:
+ r = 0;
+ break;
+ case EPIPE:
+ case ECONNRESET:
+ return -2;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "ssd",
+ "writev failed:", strerror(errno), fd);
+
+ return -1;
+ }
+ }
+
+ /* check which chunks have been written */
+ cq->bytes_out += r;
+
+ for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
+ if (r >= (ssize_t)chunks[i].iov_len) {
+ /* written */
+ r -= chunks[i].iov_len;
+ tc->offset += chunks[i].iov_len;
+
+ if (chunk_finished) {
+ /* skip the chunks from further touches */
+ chunks_written++;
+ c = c->next;
+ } else {
+ /* chunks_written + c = c->next is done in the for()*/
+ chunk_finished++;
+ }
+ } else {
+ /* partially written */
+
+ tc->offset += r;
+ chunk_finished = 0;
+
+ break;
+ }
+ }
+
+ break;
+ }
+ case FILE_CHUNK: {
+ ssize_t r;
+ off_t offset;
+ size_t toSend, written;
+ sendfilevec_t fvec;
+ stat_cache_entry *sce = NULL;
+ int ifd;
+
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ strerror(errno), c->file.name);
+ return -1;
+ }
+
+ offset = c->file.start + c->offset;
+ toSend = c->file.length - c->offset;
+
+ if (offset > sce->st.st_size) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
+
+ return -1;
+ }
+
+ if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
+
+ return -1;
+ }
+
+ fvec.sfv_fd = ifd;
+ fvec.sfv_flag = 0;
+ fvec.sfv_off = offset;
+ fvec.sfv_len = toSend;
+
+ /* Solaris sendfilev() */
+ if (-1 == (r = sendfilev(fd, &fvec, 1, &written))) {
+ if (errno != EAGAIN) {
+ log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile: ", strerror(errno), errno);
+
+ close(ifd);
+ return -1;
+ }
+
+ r = 0;
+ }
+
+ close(ifd);
+ c->offset += written;
+ cq->bytes_out += written;
+
+ if (c->offset == c->file.length) {
+ chunk_finished = 1;
+ }
+
+ break;
+ }
+ default:
+
+ log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
+
+ return -1;
+ }
+
+ if (!chunk_finished) {
+ /* not finished yet */
+
+ break;
+ }
+ }
+
+ return chunks_written;
+}
+
+#endif
Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network_write.c
URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network_write.c?rev=678637&view=auto
==============================================================================
--- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network_write.c (added)
+++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network_write.c Mon Jul 21 21:35:35 2008
@@ -0,0 +1,168 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "network.h"
+#include "fdevent.h"
+#include "log.h"
+#include "stat_cache.h"
+
+#include "sys-socket.h"
+
+#include "network_backends.h"
+
+#ifdef HAVE_SYS_FILIO_H
+# include <sys/filio.h>
+#endif
+
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
+int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqueue *cq) {
+ chunk *c;
+ size_t chunks_written = 0;
+
+ for(c = cq->first; c; c = c->next) {
+ int chunk_finished = 0;
+
+ switch(c->type) {
+ case MEM_CHUNK: {
+ char * offset;
+ size_t toSend;
+ ssize_t r;
+
+ if (c->mem->used == 0) {
+ chunk_finished = 1;
+ break;
+ }
+
+ offset = c->mem->ptr + c->offset;
+ toSend = c->mem->used - 1 - c->offset;
+#ifdef __WIN32
+ if ((r = send(fd, offset, toSend, 0)) < 0) {
+ log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), fd);
+
+ return -1;
+ }
+#else
+ if ((r = write(fd, offset, toSend)) < 0) {
+ log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), fd);
+
+ return -1;
+ }
+#endif
+
+ c->offset += r;
+ cq->bytes_out += r;
+
+ if (c->offset == (off_t)c->mem->used - 1) {
+ chunk_finished = 1;
+ }
+
+ break;
+ }
+ case FILE_CHUNK: {
+#ifdef USE_MMAP
+ char *p = NULL;
+#endif
+ ssize_t r;
+ off_t offset;
+ size_t toSend;
+ stat_cache_entry *sce = NULL;
+ int ifd;
+
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ strerror(errno), c->file.name);
+ return -1;
+ }
+
+ offset = c->file.start + c->offset;
+ toSend = c->file.length - c->offset;
+
+ if (offset > sce->st.st_size) {
+ log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
+
+ return -1;
+ }
+
+ if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
+
+ return -1;
+ }
+
+#if defined USE_MMAP
+ if (MAP_FAILED == (p = mmap(0, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "mmap failed: ", strerror(errno));
+
+ close(ifd);
+
+ return -1;
+ }
+ close(ifd);
+
+ if ((r = write(fd, p + offset, toSend)) <= 0) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "write failed: ", strerror(errno));
+ munmap(p, sce->st.st_size);
+ return -1;
+ }
+
+ munmap(p, sce->st.st_size);
+#else
+ buffer_prepare_copy(srv->tmp_buf, toSend);
+
+ lseek(ifd, offset, SEEK_SET);
+ if (-1 == (toSend = read(ifd, srv->tmp_buf->ptr, toSend))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "read: ", strerror(errno));
+ close(ifd);
+
+ return -1;
+ }
+ close(ifd);
+
+ if (-1 == (r = send(fd, srv->tmp_buf->ptr, toSend, 0))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "write: ", strerror(errno));
+
+ return -1;
+ }
+#endif
+ c->offset += r;
+ cq->bytes_out += r;
+
+ if (c->offset == c->file.length) {
+ chunk_finished = 1;
+ }
+
+ break;
+ }
+ default:
+
+ log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
+
+ return -1;
+ }
+
+ if (!chunk_finished) {
+ /* not finished yet */
+
+ break;
+ }
+
+ chunks_written++;
+ }
+
+ return chunks_written;
+}
+
+#if 0
+network_write_init(void) {
+ p->write = network_write_write_chunkset;
+}
+#endif
Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network_writev.c
URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network_writev.c?rev=678637&view=auto
==============================================================================
--- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network_writev.c (added)
+++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/network_writev.c Mon Jul 21 21:35:35 2008
@@ -0,0 +1,344 @@
+#include "network_backends.h"
+
+#ifdef USE_WRITEV
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "network.h"
+#include "fdevent.h"
+#include "log.h"
+#include "stat_cache.h"
+
+#if 0
+#define LOCAL_BUFFERING 1
+#endif
+
+int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq) {
+ chunk *c;
+ size_t chunks_written = 0;
+
+ for(c = cq->first; c; c = c->next) {
+ int chunk_finished = 0;
+
+ switch(c->type) {
+ case MEM_CHUNK: {
+ char * offset;
+ size_t toSend;
+ ssize_t r;
+
+ size_t num_chunks, i;
+ struct iovec *chunks;
+ chunk *tc;
+ size_t num_bytes = 0;
+#if defined(_SC_IOV_MAX) /* IRIX, MacOS X, FreeBSD, Solaris, ... */
+ const size_t max_chunks = sysconf(_SC_IOV_MAX);
+#elif defined(IOV_MAX) /* Linux x86 (glibc-2.3.6-3) */
+ const size_t max_chunks = IOV_MAX;
+#elif defined(MAX_IOVEC) /* Linux ia64 (glibc-2.3.3-98.28) */
+ const size_t max_chunks = MAX_IOVEC;
+#elif defined(UIO_MAXIOV) /* Linux x86 (glibc-2.2.5-233) */
+ const size_t max_chunks = UIO_MAXIOV;
+#elif (defined(__FreeBSD__) && __FreeBSD_version < 500000) || defined(__DragonFly__) || defined(__APPLE__)
+ /* - FreeBSD 4.x
+ * - MacOS X 10.3.x
+ * (covered in -DKERNEL)
+ * */
+ const size_t max_chunks = 1024; /* UIO_MAXIOV value from sys/uio.h */
+#else
+#error "sysconf() doesnt return _SC_IOV_MAX ..., check the output of 'man writev' for the EINVAL error and send the output to jan@kneschke.de"
+#endif
+
+ /* we can't send more then SSIZE_MAX bytes in one chunk */
+
+ /* build writev list
+ *
+ * 1. limit: num_chunks < max_chunks
+ * 2. limit: num_bytes < SSIZE_MAX
+ */
+ for (num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < max_chunks; num_chunks++, tc = tc->next);
+
+ chunks = calloc(num_chunks, sizeof(*chunks));
+
+ for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
+ if (tc->mem->used == 0) {
+ chunks[i].iov_base = tc->mem->ptr;
+ chunks[i].iov_len = 0;
+ } else {
+ offset = tc->mem->ptr + tc->offset;
+ toSend = tc->mem->used - 1 - tc->offset;
+
+ chunks[i].iov_base = offset;
+
+ /* protect the return value of writev() */
+ if (toSend > SSIZE_MAX ||
+ num_bytes + toSend > SSIZE_MAX) {
+ chunks[i].iov_len = SSIZE_MAX - num_bytes;
+
+ num_chunks = i + 1;
+ break;
+ } else {
+ chunks[i].iov_len = toSend;
+ }
+
+ num_bytes += toSend;
+ }
+ }
+
+ if ((r = writev(fd, chunks, num_chunks)) < 0) {
+ switch (errno) {
+ case EAGAIN:
+ case EINTR:
+ r = 0;
+ break;
+ case EPIPE:
+ case ECONNRESET:
+ free(chunks);
+ return -2;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "ssd",
+ "writev failed:", strerror(errno), fd);
+
+ free(chunks);
+ return -1;
+ }
+ }
+
+ cq->bytes_out += r;
+
+ /* check which chunks have been written */
+
+ for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
+ if (r >= (ssize_t)chunks[i].iov_len) {
+ /* written */
+ r -= chunks[i].iov_len;
+ tc->offset += chunks[i].iov_len;
+
+ if (chunk_finished) {
+ /* skip the chunks from further touches */
+ chunks_written++;
+ c = c->next;
+ } else {
+ /* chunks_written + c = c->next is done in the for()*/
+ chunk_finished++;
+ }
+ } else {
+ /* partially written */
+
+ tc->offset += r;
+ chunk_finished = 0;
+
+ break;
+ }
+ }
+ free(chunks);
+
+ break;
+ }
+ case FILE_CHUNK: {
+ ssize_t r;
+ off_t abs_offset;
+ off_t toSend;
+ stat_cache_entry *sce = NULL;
+
+#define KByte * 1024
+#define MByte * 1024 KByte
+#define GByte * 1024 MByte
+ const off_t we_want_to_mmap = 512 KByte;
+ char *start = NULL;
+
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ strerror(errno), c->file.name);
+ return -1;
+ }
+
+ abs_offset = c->file.start + c->offset;
+
+ if (abs_offset > sce->st.st_size) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "file was shrinked:", c->file.name);
+
+ return -1;
+ }
+
+ /* mmap the buffer
+ * - first mmap
+ * - new mmap as the we are at the end of the last one */
+ if (c->file.mmap.start == MAP_FAILED ||
+ abs_offset == (off_t)(c->file.mmap.offset + c->file.mmap.length)) {
+
+ /* Optimizations for the future:
+ *
+ * adaptive mem-mapping
+ * the problem:
+ * we mmap() the whole file. If someone has alot large files and 32bit
+ * machine the virtual address area will be unrun and we will have a failing
+ * mmap() call.
+ * solution:
+ * only mmap 16M in one chunk and move the window as soon as we have finished
+ * the first 8M
+ *
+ * read-ahead buffering
+ * the problem:
+ * sending out several large files in parallel trashes the read-ahead of the
+ * kernel leading to long wait-for-seek times.
+ * solutions: (increasing complexity)
+ * 1. use madvise
+ * 2. use a internal read-ahead buffer in the chunk-structure
+ * 3. use non-blocking IO for file-transfers
+ * */
+
+ /* all mmap()ed areas are 512kb expect the last which might be smaller */
+ off_t we_want_to_send;
+ size_t to_mmap;
+
+ /* this is a remap, move the mmap-offset */
+ if (c->file.mmap.start != MAP_FAILED) {
+ munmap(c->file.mmap.start, c->file.mmap.length);
+ c->file.mmap.offset += we_want_to_mmap;
+ } else {
+ /* in case the range-offset is after the first mmap()ed area we skip the area */
+ c->file.mmap.offset = 0;
+
+ while (c->file.mmap.offset + we_want_to_mmap < c->file.start) {
+ c->file.mmap.offset += we_want_to_mmap;
+ }
+ }
+
+ /* length is rel, c->offset too, assume there is no limit at the mmap-boundaries */
+ we_want_to_send = c->file.length - c->offset;
+ to_mmap = (c->file.start + c->file.length) - c->file.mmap.offset;
+
+ /* we have more to send than we can mmap() at once */
+ if (abs_offset + we_want_to_send > c->file.mmap.offset + we_want_to_mmap) {
+ we_want_to_send = (c->file.mmap.offset + we_want_to_mmap) - abs_offset;
+ to_mmap = we_want_to_mmap;
+ }
+
+ if (-1 == c->file.fd) { /* open the file if not already open */
+ if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs", "open failed for:", c->file.name, strerror(errno));
+
+ return -1;
+ }
+#ifdef FD_CLOEXEC
+ fcntl(c->file.fd, F_SETFD, FD_CLOEXEC);
+#endif
+ }
+
+ if (MAP_FAILED == (c->file.mmap.start = mmap(0, to_mmap, PROT_READ, MAP_SHARED, c->file.fd, c->file.mmap.offset))) {
+ /* close it here, otherwise we'd have to set FD_CLOEXEC */
+
+ log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed:",
+ strerror(errno), c->file.name, c->file.fd);
+
+ return -1;
+ }
+
+ c->file.mmap.length = to_mmap;
+#ifdef LOCAL_BUFFERING
+ buffer_copy_string_len(c->mem, c->file.mmap.start, c->file.mmap.length);
+#else
+#ifdef HAVE_MADVISE
+ /* don't advise files < 64Kb */
+ if (c->file.mmap.length > (64 KByte)) {
+ /* darwin 7 is returning EINVAL all the time and I don't know how to
+ * detect this at runtime.i
+ *
+ * ignore the return value for now */
+ madvise(c->file.mmap.start, c->file.mmap.length, MADV_WILLNEED);
+ }
+#endif
+#endif
+
+ /* chunk_reset() or chunk_free() will cleanup for us */
+ }
+
+ /* to_send = abs_mmap_end - abs_offset */
+ toSend = (c->file.mmap.offset + c->file.mmap.length) - (abs_offset);
+
+ if (toSend < 0) {
+ log_error_write(srv, __FILE__, __LINE__, "soooo",
+ "toSend is negative:",
+ toSend,
+ c->file.mmap.length,
+ abs_offset,
+ c->file.mmap.offset);
+ assert(toSend < 0);
+ }
+
+#ifdef LOCAL_BUFFERING
+ start = c->mem->ptr;
+#else
+ start = c->file.mmap.start;
+#endif
+
+ if ((r = write(fd, start + (abs_offset - c->file.mmap.offset), toSend)) < 0) {
+ switch (errno) {
+ case EAGAIN:
+ case EINTR:
+ r = 0;
+ break;
+ case EPIPE:
+ case ECONNRESET:
+ return -2;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "ssd",
+ "write failed:", strerror(errno), fd);
+
+ return -1;
+ }
+ }
+
+ c->offset += r;
+ cq->bytes_out += r;
+
+ if (c->offset == c->file.length) {
+ chunk_finished = 1;
+
+ /* we don't need the mmaping anymore */
+ if (c->file.mmap.start != MAP_FAILED) {
+ munmap(c->file.mmap.start, c->file.mmap.length);
+ c->file.mmap.start = MAP_FAILED;
+ }
+ }
+
+ break;
+ }
+ default:
+
+ log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
+
+ return -1;
+ }
+
+ if (!chunk_finished) {
+ /* not finished yet */
+
+ break;
+ }
+
+ chunks_written++;
+ }
+
+ return chunks_written;
+}
+
+#endif
Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/plugin.c
URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/plugin.c?rev=678637&view=auto
==============================================================================
--- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/plugin.c (added)
+++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/plugin.c Mon Jul 21 21:35:35 2008
@@ -0,0 +1,451 @@
+#include <string.h>
+#include <stdlib.h>
+
+#include <stdio.h>
+
+#include "plugin.h"
+#include "log.h"
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_VALGRIND_VALGRIND_H
+#include <valgrind/valgrind.h>
+#endif
+
+#ifndef __WIN32
+#include <dlfcn.h>
+#endif
+/*
+ *
+ * if you change this enum to add a new callback, be sure
+ * - that PLUGIN_FUNC_SIZEOF is the last entry
+ * - that you add PLUGIN_TO_SLOT twice:
+ * 1. as callback-dispatcher
+ * 2. in plugins_call_init()
+ *
+ */
+
+typedef struct {
+ PLUGIN_DATA;
+} plugin_data;
+
+typedef enum {
+ PLUGIN_FUNC_UNSET,
+ PLUGIN_FUNC_HANDLE_URI_CLEAN,
+ PLUGIN_FUNC_HANDLE_URI_RAW,
+ PLUGIN_FUNC_HANDLE_REQUEST_DONE,
+ PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE,
+ PLUGIN_FUNC_HANDLE_TRIGGER,
+ PLUGIN_FUNC_HANDLE_SIGHUP,
+ PLUGIN_FUNC_HANDLE_SUBREQUEST,
+ PLUGIN_FUNC_HANDLE_SUBREQUEST_START,
+ PLUGIN_FUNC_HANDLE_JOBLIST,
+ PLUGIN_FUNC_HANDLE_DOCROOT,
+ PLUGIN_FUNC_HANDLE_PHYSICAL,
+ PLUGIN_FUNC_CONNECTION_RESET,
+ PLUGIN_FUNC_INIT,
+ PLUGIN_FUNC_CLEANUP,
+ PLUGIN_FUNC_SET_DEFAULTS,
+
+ PLUGIN_FUNC_SIZEOF
+} plugin_t;
+
+static plugin *plugin_init(void) {
+ plugin *p;
+
+ p = calloc(1, sizeof(*p));
+
+ return p;
+}
+
+static void plugin_free(plugin *p) {
+ int use_dlclose = 1;
+ if (p->name) buffer_free(p->name);
+#ifdef HAVE_VALGRIND_VALGRIND_H
+ /*if (RUNNING_ON_VALGRIND) use_dlclose = 0;*/
+#endif
+
+#ifndef LIGHTTPD_STATIC
+ if (use_dlclose && p->lib) {
+#ifdef __WIN32
+ FreeLibrary(p->lib);
+#else
+ dlclose(p->lib);
+#endif
+ }
+#endif
+
+ free(p);
+}
+
+static int plugins_register(server *srv, plugin *p) {
+ plugin **ps;
+ if (0 == srv->plugins.size) {
+ srv->plugins.size = 4;
+ srv->plugins.ptr = malloc(srv->plugins.size * sizeof(*ps));
+ srv->plugins.used = 0;
+ } else if (srv->plugins.used == srv->plugins.size) {
+ srv->plugins.size += 4;
+ srv->plugins.ptr = realloc(srv->plugins.ptr, srv->plugins.size * sizeof(*ps));
+ }
+
+ ps = srv->plugins.ptr;
+ ps[srv->plugins.used++] = p;
+
+ return 0;
+}
+
+/**
+ *
+ *
+ *
+ */
+
+#ifdef LIGHTTPD_STATIC
+int plugins_load(server *srv) {
+ plugin *p;
+#define PLUGIN_INIT(x)\
+ p = plugin_init(); \
+ if (x ## _plugin_init(p)) { \
+ log_error_write(srv, __FILE__, __LINE__, "ss", #x, "plugin init failed" ); \
+ plugin_free(p); \
+ return -1;\
+ }\
+ plugins_register(srv, p);
+
+#include "plugin-static.h"
+
+ return 0;
+}
+#else
+int plugins_load(server *srv) {
+ plugin *p;
+ int (*init)(plugin *pl);
+ const char *error;
+ size_t i;
+
+ for (i = 0; i < srv->srvconf.modules->used; i++) {
+ data_string *d = (data_string *)srv->srvconf.modules->data[i];
+ char *modules = d->value->ptr;
+
+ buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.modules_dir);
+
+ buffer_append_string(srv->tmp_buf, "/");
+ buffer_append_string(srv->tmp_buf, modules);
+#if defined(__WIN32) || defined(__CYGWIN__)
+ buffer_append_string(srv->tmp_buf, ".dll");
+#else
+ buffer_append_string(srv->tmp_buf, ".so");
+#endif
+
+ p = plugin_init();
+#ifdef __WIN32
+ if (NULL == (p->lib = LoadLibrary(srv->tmp_buf->ptr))) {
+ LPVOID lpMsgBuf;
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf,
+ 0, NULL );
+
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed",
+ lpMsgBuf, srv->tmp_buf);
+
+ plugin_free(p);
+
+ return -1;
+
+ }
+#else
+ if (NULL == (p->lib = dlopen(srv->tmp_buf->ptr, RTLD_NOW|RTLD_GLOBAL))) {
+ log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:",
+ srv->tmp_buf, dlerror());
+
+ plugin_free(p);
+
+ return -1;
+ }
+
+#endif
+ buffer_reset(srv->tmp_buf);
+ buffer_copy_string(srv->tmp_buf, modules);
+ buffer_append_string(srv->tmp_buf, "_plugin_init");
+
+#ifdef __WIN32
+ init = GetProcAddress(p->lib, srv->tmp_buf->ptr);
+
+ if (init == NULL) {
+ LPVOID lpMsgBuf;
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf,
+ 0, NULL );
+
+ log_error_write(srv, __FILE__, __LINE__, "sbs", "getprocaddress failed:", srv->tmp_buf, lpMsgBuf);
+
+ plugin_free(p);
+ return -1;
+ }
+
+#else
+#if 1
+ init = (int (*)(plugin *))dlsym(p->lib, srv->tmp_buf->ptr);
+#else
+ *(void **)(&init) = dlsym(p->lib, srv->tmp_buf->ptr);
+#endif
+ if ((error = dlerror()) != NULL) {
+ log_error_write(srv, __FILE__, __LINE__, "s", error);
+
+ plugin_free(p);
+ return -1;
+ }
+
+#endif
+ if ((*init)(p)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", modules, "plugin init failed" );
+
+ plugin_free(p);
+ return -1;
+ }
+#if 0
+ log_error_write(srv, __FILE__, __LINE__, "ss", modules, "plugin loaded" );
+#endif
+ plugins_register(srv, p);
+ }
+
+ return 0;
+}
+#endif
+
+#define PLUGIN_TO_SLOT(x, y) \
+ handler_t plugins_call_##y(server *srv, connection *con) {\
+ plugin **slot;\
+ size_t j;\
+ if (!srv->plugin_slots) return HANDLER_GO_ON;\
+ slot = ((plugin ***)(srv->plugin_slots))[x];\
+ if (!slot) return HANDLER_GO_ON;\
+ for (j = 0; j < srv->plugins.used && slot[j]; j++) { \
+ plugin *p = slot[j];\
+ handler_t r;\
+ switch(r = p->y(srv, con, p->data)) {\
+ case HANDLER_GO_ON:\
+ break;\
+ case HANDLER_FINISHED:\
+ case HANDLER_COMEBACK:\
+ case HANDLER_WAIT_FOR_EVENT:\
+ case HANDLER_WAIT_FOR_FD:\
+ case HANDLER_ERROR:\
+ return r;\
+ default:\
+ log_error_write(srv, __FILE__, __LINE__, "sbs", #x, p->name, "unknown state");\
+ return HANDLER_ERROR;\
+ }\
+ }\
+ return HANDLER_GO_ON;\
+ }
+
+/**
+ * plugins that use
+ *
+ * - server *srv
+ * - connection *con
+ * - void *p_d (plugin_data *)
+ */
+
+PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean)
+PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw)
+PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done)
+PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close)
+PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest)
+PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start)
+PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_JOBLIST, handle_joblist)
+PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot)
+PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical)
+PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset)
+
+#undef PLUGIN_TO_SLOT
+
+#define PLUGIN_TO_SLOT(x, y) \
+ handler_t plugins_call_##y(server *srv) {\
+ plugin **slot;\
+ size_t j;\
+ if (!srv->plugin_slots) return HANDLER_GO_ON;\
+ slot = ((plugin ***)(srv->plugin_slots))[x];\
+ if (!slot) return HANDLER_GO_ON;\
+ for (j = 0; j < srv->plugins.used && slot[j]; j++) { \
+ plugin *p = slot[j];\
+ handler_t r;\
+ switch(r = p->y(srv, p->data)) {\
+ case HANDLER_GO_ON:\
+ break;\
+ case HANDLER_FINISHED:\
+ case HANDLER_COMEBACK:\
+ case HANDLER_WAIT_FOR_EVENT:\
+ case HANDLER_WAIT_FOR_FD:\
+ case HANDLER_ERROR:\
+ return r;\
+ default:\
+ log_error_write(srv, __FILE__, __LINE__, "sbsd", #x, p->name, "unknown state:", r);\
+ return HANDLER_ERROR;\
+ }\
+ }\
+ return HANDLER_GO_ON;\
+ }
+
+/**
+ * plugins that use
+ *
+ * - server *srv
+ * - void *p_d (plugin_data *)
+ */
+
+PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger)
+PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup)
+PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup)
+PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults)
+
+#undef PLUGIN_TO_SLOT
+
+#if 0
+/**
+ *
+ * special handler
+ *
+ */
+handler_t plugins_call_handle_fdevent(server *srv, const fd_conn *fdc) {
+ size_t i;
+ plugin **ps;
+
+ ps = srv->plugins.ptr;
+
+ for (i = 0; i < srv->plugins.used; i++) {
+ plugin *p = ps[i];
+ if (p->handle_fdevent) {
+ handler_t r;
+ switch(r = p->handle_fdevent(srv, fdc, p->data)) {
+ case HANDLER_GO_ON:
+ break;
+ case HANDLER_FINISHED:
+ case HANDLER_COMEBACK:
+ case HANDLER_WAIT_FOR_EVENT:
+ case HANDLER_ERROR:
+ return r;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "d", r);
+ break;
+ }
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+#endif
+/**
+ *
+ * - call init function of all plugins to init the plugin-internals
+ * - added each plugin that supports has callback to the corresponding slot
+ *
+ * - is only called once.
+ */
+
+handler_t plugins_call_init(server *srv) {
+ size_t i;
+ plugin **ps;
+
+ ps = srv->plugins.ptr;
+
+ /* fill slots */
+
+ srv->plugin_slots = calloc(PLUGIN_FUNC_SIZEOF, sizeof(ps));
+
+ for (i = 0; i < srv->plugins.used; i++) {
+ size_t j;
+ /* check which calls are supported */
+
+ plugin *p = ps[i];
+
+#define PLUGIN_TO_SLOT(x, y) \
+ if (p->y) { \
+ plugin **slot = ((plugin ***)(srv->plugin_slots))[x]; \
+ if (!slot) { \
+ slot = calloc(srv->plugins.used, sizeof(*slot));\
+ ((plugin ***)(srv->plugin_slots))[x] = slot; \
+ } \
+ for (j = 0; j < srv->plugins.used; j++) { \
+ if (slot[j]) continue;\
+ slot[j] = p;\
+ break;\
+ }\
+ }
+
+
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_JOBLIST, handle_joblist);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup);
+ PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults);
+#undef PLUGIN_TO_SLOT
+
+ if (p->init) {
+ if (NULL == (p->data = p->init())) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "plugin-init failed for module", p->name);
+ return HANDLER_ERROR;
+ }
+
+ /* used for con->mode, DIRECT == 0, plugins above that */
+ ((plugin_data *)(p->data))->id = i + 1;
+
+ if (p->version != LIGHTTPD_VERSION_ID) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "plugin-version doesn't match lighttpd-version for", p->name);
+ return HANDLER_ERROR;
+ }
+ } else {
+ p->data = NULL;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+void plugins_free(server *srv) {
+ size_t i;
+ plugins_call_cleanup(srv);
+
+ for (i = 0; i < srv->plugins.used; i++) {
+ plugin *p = ((plugin **)srv->plugins.ptr)[i];
+
+ plugin_free(p);
+ }
+
+ for (i = 0; srv->plugin_slots && i < PLUGIN_FUNC_SIZEOF; i++) {
+ plugin **slot = ((plugin ***)(srv->plugin_slots))[i];
+
+ if (slot) free(slot);
+ }
+
+ free(srv->plugin_slots);
+ srv->plugin_slots = NULL;
+
+ free(srv->plugins.ptr);
+ srv->plugins.ptr = NULL;
+ srv->plugins.used = 0;
+}
Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/plugin.h
URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/plugin.h?rev=678637&view=auto
==============================================================================
--- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/plugin.h (added)
+++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/plugin.h Mon Jul 21 21:35:35 2008
@@ -0,0 +1,103 @@
+#ifndef _PLUGIN_H_
+#define _PLUGIN_H_
+
+#include "base.h"
+#include "buffer.h"
+
+#define SERVER_FUNC(x) \
+ static handler_t x(server *srv, void *p_d)
+
+#define CONNECTION_FUNC(x) \
+ static handler_t x(server *srv, connection *con, void *p_d)
+
+#define INIT_FUNC(x) \
+ static void *x()
+
+#define FREE_FUNC SERVER_FUNC
+#define TRIGGER_FUNC SERVER_FUNC
+#define SETDEFAULTS_FUNC SERVER_FUNC
+#define SIGHUP_FUNC SERVER_FUNC
+
+#define SUBREQUEST_FUNC CONNECTION_FUNC
+#define JOBLIST_FUNC CONNECTION_FUNC
+#define PHYSICALPATH_FUNC CONNECTION_FUNC
+#define REQUESTDONE_FUNC CONNECTION_FUNC
+#define URIHANDLER_FUNC CONNECTION_FUNC
+
+#define PLUGIN_DATA size_t id
+
+typedef struct {
+ size_t version;
+
+ buffer *name; /* name of the plugin */
+
+ void *(* init) ();
+ handler_t (* set_defaults) (server *srv, void *p_d);
+ handler_t (* cleanup) (server *srv, void *p_d);
+ /* is called ... */
+ handler_t (* handle_trigger) (server *srv, void *p_d); /* once a second */
+ handler_t (* handle_sighup) (server *srv, void *p_d); /* at a signup */
+
+ handler_t (* handle_uri_raw) (server *srv, connection *con, void *p_d); /* after uri_raw is set */
+ handler_t (* handle_uri_clean) (server *srv, connection *con, void *p_d); /* after uri is set */
+ handler_t (* handle_docroot) (server *srv, connection *con, void *p_d); /* getting the document-root */
+ handler_t (* handle_physical) (server *srv, connection *con, void *p_d); /* mapping url to physical path */
+ handler_t (* handle_request_done) (server *srv, connection *con, void *p_d); /* at the end of a request */
+ handler_t (* handle_connection_close)(server *srv, connection *con, void *p_d); /* at the end of a connection */
+ handler_t (* handle_joblist) (server *srv, connection *con, void *p_d); /* after all events are handled */
+
+
+
+ handler_t (* handle_subrequest_start)(server *srv, connection *con, void *p_d);
+
+ /* when a handler for the request
+ * has to be found
+ */
+ handler_t (* handle_subrequest) (server *srv, connection *con, void *p_d); /* */
+ handler_t (* connection_reset) (server *srv, connection *con, void *p_d); /* */
+ void *data;
+
+ /* dlopen handle */
+ void *lib;
+} plugin;
+
+int plugins_load(server *srv);
+void plugins_free(server *srv);
+
+handler_t plugins_call_handle_uri_raw(server *srv, connection *con);
+handler_t plugins_call_handle_uri_clean(server *srv, connection *con);
+handler_t plugins_call_handle_subrequest_start(server *srv, connection *con);
+handler_t plugins_call_handle_subrequest(server *srv, connection *con);
+handler_t plugins_call_handle_request_done(server *srv, connection *con);
+handler_t plugins_call_handle_docroot(server *srv, connection *con);
+handler_t plugins_call_handle_physical(server *srv, connection *con);
+handler_t plugins_call_handle_connection_close(server *srv, connection *con);
+handler_t plugins_call_handle_joblist(server *srv, connection *con);
+handler_t plugins_call_connection_reset(server *srv, connection *con);
+
+handler_t plugins_call_handle_trigger(server *srv);
+handler_t plugins_call_handle_sighup(server *srv);
+
+handler_t plugins_call_init(server *srv);
+handler_t plugins_call_set_defaults(server *srv);
+handler_t plugins_call_cleanup(server *srv);
+
+int config_insert_values_global(server *srv, array *ca, const config_values_t *cv);
+int config_insert_values_internal(server *srv, array *ca, const config_values_t *cv);
+int config_setup_connection(server *srv, connection *con);
+int config_patch_connection(server *srv, connection *con, comp_key_t comp);
+int config_check_cond(server *srv, connection *con, data_config *dc);
+int config_append_cond_match_buffer(connection *con, data_config *dc, buffer *buf, int n);
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/proc_open.c
URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/proc_open.c?rev=678637&view=auto
==============================================================================
--- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/proc_open.c (added)
+++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/proc_open.c Mon Jul 21 21:35:35 2008
@@ -0,0 +1,394 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include "proc_open.h"
+
+#ifdef WIN32
+#include <io.h>
+#include <fcntl.h>
+#else
+#include <sys/wait.h>
+#include <unistd.h>
+#endif
+
+
+#ifdef WIN32
+/* {{{ win32 stuff */
+# define SHELLENV "ComSpec"
+# define SECURITY_DC , SECURITY_ATTRIBUTES *security
+# define SECURITY_CC , security
+# define pipe(pair) (CreatePipe(&pair[0], &pair[1], security, 2048L) ? 0 : -1)
+static inline HANDLE dup_handle(HANDLE src, BOOL inherit, BOOL closeorig)
+{
+ HANDLE copy, self = GetCurrentProcess();
+
+ if (!DuplicateHandle(self, src, self, ©, 0, inherit, DUPLICATE_SAME_ACCESS |
+ (closeorig ? DUPLICATE_CLOSE_SOURCE : 0)))
+ return NULL;
+ return copy;
+}
+# define close_descriptor(fd) CloseHandle(fd)
+static void pipe_close_parent(pipe_t *p) {
+ /* don't let the child inherit the parent side of the pipe */
+ p->parent = dup_handle(p->parent, FALSE, TRUE);
+}
+static void pipe_close_child(pipe_t *p) {
+ close_descriptor(p->child);
+ p->fd = _open_osfhandle((long)p->parent,
+ (p->fd == 0 ? O_RDONLY : O_WRONLY)|O_BINARY);
+}
+/* }}} */
+#else /* WIN32 */
+/* {{{ unix way */
+# define SHELLENV "SHELL"
+# define SECURITY_DC
+# define SECURITY_CC
+# define close_descriptor(fd) close(fd)
+static void pipe_close_parent(pipe_t *p) {
+ /* don't close stdin */
+ close_descriptor(p->parent);
+ if (dup2(p->child, p->fd) != p->fd) {
+ perror("pipe_child dup2");
+ } else {
+ close_descriptor(p->child);
+ p->child = p->fd;
+ }
+}
+static void pipe_close_child(pipe_t *p) {
+ close_descriptor(p->child);
+ p->fd = p->parent;
+}
+/* }}} */
+#endif /* WIN32 */
+
+/* {{{ pipe_close */
+static void pipe_close(pipe_t *p) {
+ close_descriptor(p->parent);
+ close_descriptor(p->child);
+#ifdef WIN32
+ close(p->fd);
+#endif
+}
+/* }}} */
+/* {{{ pipe_open */
+static int pipe_open(pipe_t *p, int fd SECURITY_DC) {
+ descriptor_t newpipe[2];
+
+ if (0 != pipe(newpipe)) {
+ fprintf(stderr, "can't open pipe");
+ return -1;
+ }
+ if (0 == fd) {
+ p->parent = newpipe[1]; /* write */
+ p->child = newpipe[0]; /* read */
+ } else {
+ p->parent = newpipe[0]; /* read */
+ p->child = newpipe[1]; /* write */
+ }
+ p->fd = fd;
+
+ return 0;
+}
+/* }}} */
+
+/* {{{ proc_open_pipes */
+static int proc_open_pipes(proc_handler_t *proc SECURITY_DC) {
+ if (pipe_open(&(proc->in), 0 SECURITY_CC) != 0) {
+ return -1;
+ }
+ if (pipe_open(&(proc->out), 1 SECURITY_CC) != 0) {
+ return -1;
+ }
+ if (pipe_open(&(proc->err), 2 SECURITY_CC) != 0) {
+ return -1;
+ }
+ return 0;
+}
+/* }}} */
+/* {{{ proc_close_pipes */
+static void proc_close_pipes(proc_handler_t *proc) {
+ pipe_close(&proc->in);
+ pipe_close(&proc->out);
+ pipe_close(&proc->err);
+}
+/* }}} */
+/* {{{ proc_close_parents */
+static void proc_close_parents(proc_handler_t *proc) {
+ pipe_close_parent(&proc->in);
+ pipe_close_parent(&proc->out);
+ pipe_close_parent(&proc->err);
+}
+/* }}} */
+/* {{{ proc_close_childs */
+static void proc_close_childs(proc_handler_t *proc) {
+ pipe_close_child(&proc->in);
+ pipe_close_child(&proc->out);
+ pipe_close_child(&proc->err);
+}
+/* }}} */
+
+#ifdef WIN32
+/* {{{ proc_close */
+int proc_close(proc_handler_t *proc) {
+ proc_pid_t child = proc->child;
+ DWORD wstatus;
+
+ proc_close_pipes(proc);
+ WaitForSingleObject(child, INFINITE);
+ GetExitCodeProcess(child, &wstatus);
+ CloseHandle(child);
+
+ return wstatus;
+}
+/* }}} */
+/* {{{ proc_open */
+int proc_open(proc_handler_t *proc, const char *command) {
+ PROCESS_INFORMATION pi;
+ STARTUPINFO si;
+ BOOL procok;
+ SECURITY_ATTRIBUTES security;
+ const char *shell = NULL;
+ const char *windir = NULL;
+ buffer *cmdline;
+
+ if (NULL == (shell = getenv(SHELLENV)) &&
+ NULL == (windir = getenv("SystemRoot")) &&
+ NULL == (windir = getenv("windir"))) {
+ fprintf(stderr, "One of %s,%%SystemRoot,%%windir is required", SHELLENV);
+ return -1;
+ }
+
+ /* we use this to allow the child to inherit handles */
+ memset(&security, 0, sizeof(security));
+ security.nLength = sizeof(security);
+ security.bInheritHandle = TRUE;
+ security.lpSecurityDescriptor = NULL;
+
+ if (proc_open_pipes(proc, &security) != 0) {
+ return -1;
+ }
+ proc_close_parents(proc);
+
+ memset(&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+ si.dwFlags = STARTF_USESTDHANDLES;
+ si.hStdInput = proc->in.child;
+ si.hStdOutput = proc->out.child;
+ si.hStdError = proc->err.child;
+
+ memset(&pi, 0, sizeof(pi));
+
+ cmdline = buffer_init();
+ if (shell) {
+ buffer_append_string(cmdline, shell);
+ } else {
+ buffer_append_string(cmdline, windir);
+ buffer_append_string(cmdline, "\\system32\\cmd.exe");
+ }
+ buffer_append_string_len(cmdline, CONST_STR_LEN(" /c "));
+ buffer_append_string(cmdline, command);
+ procok = CreateProcess(NULL, cmdline->ptr, &security, &security, TRUE,
+ NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
+
+ if (FALSE == procok) {
+ fprintf(stderr, "failed to CreateProcess: %s", cmdline->ptr);
+ buffer_free(cmdline);
+ return -1;
+ }
+ buffer_free(cmdline);
+
+ proc->child = pi.hProcess;
+ CloseHandle(pi.hThread);
+
+ proc_close_childs(proc);
+
+ return 0;
+}
+/* }}} */
+#else /* WIN32 */
+/* {{{ proc_close */
+int proc_close(proc_handler_t *proc) {
+ pid_t child = proc->child;
+ int wstatus;
+ pid_t wait_pid;
+
+ proc_close_pipes(proc);
+
+ do {
+ wait_pid = waitpid(child, &wstatus, 0);
+ } while (wait_pid == -1 && errno == EINTR);
+
+ if (wait_pid == -1) {
+ return -1;
+ } else {
+ if (WIFEXITED(wstatus))
+ wstatus = WEXITSTATUS(wstatus);
+ }
+
+ return wstatus;
+}
+/* }}} */
+/* {{{ proc_open */
+int proc_open(proc_handler_t *proc, const char *command) {
+ pid_t child;
+ const char *shell;
+
+ if (NULL == (shell = getenv(SHELLENV))) {
+ shell = "/bin/sh";
+ }
+
+ if (proc_open_pipes(proc) != 0) {
+ return -1;
+ }
+
+ /* the unix way */
+
+ child = fork();
+
+ if (child == 0) {
+ /* this is the child process */
+
+ /* close those descriptors that we just opened for the parent stuff,
+ * dup new descriptors into required descriptors and close the original
+ * cruft
+ */
+ proc_close_parents(proc);
+
+ execl(shell, shell, "-c", command, (char *)NULL);
+ _exit(127);
+
+ } else if (child < 0) {
+ fprintf(stderr, "failed to forking");
+ proc_close(proc);
+ return -1;
+
+ } else {
+ proc->child = child;
+ proc_close_childs(proc);
+ return 0;
+ }
+}
+/* }}} */
+#endif /* WIN32 */
+
+/* {{{ proc_read_fd_to_buffer */
+static void proc_read_fd_to_buffer(int fd, buffer *b) {
+ ssize_t s;
+
+ for (;;) {
+ buffer_prepare_append(b, 512);
+ if ((s = read(fd, (void *)(b->ptr + b->used), 512 - 1)) <= 0) {
+ break;
+ }
+ b->used += s;
+ }
+ b->ptr[b->used] = '\0';
+}
+/* }}} */
+/* {{{ proc_open_buffer */
+int proc_open_buffer(proc_handler_t *proc, const char *command, buffer *in, buffer *out, buffer *err) {
+
+ UNUSED(err);
+
+ if (proc_open(proc, command) != 0) {
+ return -1;
+ }
+
+ if (in) {
+ if (write(proc->in.fd, (void *)in->ptr, in->used) < 0) {
+ perror("error writing pipe");
+ return -1;
+ }
+ }
+ pipe_close(&proc->in);
+
+ if (out) {
+ proc_read_fd_to_buffer(proc->out.fd, out);
+ }
+ pipe_close(&proc->out);
+
+ if (err) {
+ proc_read_fd_to_buffer(proc->err.fd, err);
+ }
+ pipe_close(&proc->err);
+
+ return 0;
+}
+/* }}} */
+
+/* {{{ test */
+#ifdef DEBUG_PROC_OPEN
+int main() {
+ proc_handler_t proc;
+ buffer *in = buffer_init(), *out = buffer_init(), *err = buffer_init();
+ int wstatus;
+
+#define FREE() do { \
+ buffer_free(in); \
+ buffer_free(out); \
+ buffer_free(err); \
+} while (0)
+
+#define RESET() do { \
+ buffer_reset(in); \
+ buffer_reset(out); \
+ buffer_reset(err); \
+ wstatus = proc_close(&proc); \
+ if (0&&wstatus != 0) { \
+ fprintf(stdout, "exitstatus %d\n", wstatus); \
+ return __LINE__ - 200; \
+ } \
+} while (0)
+
+#define ERROR_OUT() do { \
+ fprintf(stdout, "failed opening proc\n"); \
+ wstatus = proc_close(&proc); \
+ fprintf(stdout, "exitstatus %d\n", wstatus); \
+ FREE(); \
+ return __LINE__ - 300; \
+} while (0)
+
+#ifdef WIN32
+#define CMD_CAT "pause"
+#else
+#define CMD_CAT "cat"
+#endif
+
+ do {
+ fprintf(stdout, "test: echo 123 without read\n");
+ if (proc_open(&proc, "echo 321") != 0) {
+ ERROR_OUT();
+ }
+ close_descriptor(proc.in.parent);
+ close_descriptor(proc.out.parent);
+ close_descriptor(proc.err.parent);
+ RESET();
+
+ fprintf(stdout, "test: echo 321 with read\n"); fflush(stdout);
+ if (proc_open_buffer(&proc, "echo 321", NULL, out, err) != 0) {
+ ERROR_OUT();
+ }
+ fprintf(stdout, "result: ->%s<-\n\n", out->ptr); fflush(stdout);
+ RESET();
+
+ fprintf(stdout, "test: echo 123 | " CMD_CAT "\n"); fflush(stdout);
+ buffer_copy_string_len(in, CONST_STR_LEN("123\n"));
+ if (proc_open_buffer(&proc, CMD_CAT, in, out, err) != 0) {
+ ERROR_OUT();
+ }
+ fprintf(stdout, "result: ->%s<-\n\n", out->ptr); fflush(stdout);
+ RESET();
+ } while (0);
+
+#undef RESET
+#undef ERROR_OUT
+
+ fprintf(stdout, "ok\n");
+
+ FREE();
+ return 0;
+}
+#endif /* DEBUG_PROC_OPEN */
+/* }}} */
+
Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/proc_open.h
URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/proc_open.h?rev=678637&view=auto
==============================================================================
--- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/proc_open.h (added)
+++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/proc_open.h Mon Jul 21 21:35:35 2008
@@ -0,0 +1,25 @@
+
+#include "buffer.h"
+
+#ifdef WIN32
+#include <windows.h>
+typedef HANDLE descriptor_t;
+typedef HANDLE proc_pid_t;
+#else
+typedef int descriptor_t;
+typedef pid_t proc_pid_t;
+#endif
+
+typedef struct {
+ descriptor_t parent, child;
+ int fd;
+} pipe_t;
+
+typedef struct {
+ pipe_t in, out, err;
+ proc_pid_t child;
+} proc_handler_t;
+
+int proc_close(proc_handler_t *ht);
+int proc_open(proc_handler_t *ht, const char *command);
+int proc_open_buffer(proc_handler_t *ht, const char *command, buffer *in, buffer *out, buffer *err);