Return-Path: Delivered-To: apmail-ws-axis-dev-archive@www.apache.org Received: (qmail 50953 invoked from network); 22 Jul 2008 04:38:34 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 22 Jul 2008 04:38:34 -0000 Received: (qmail 68424 invoked by uid 500); 22 Jul 2008 04:38:33 -0000 Delivered-To: apmail-ws-axis-dev-archive@ws.apache.org Received: (qmail 68310 invoked by uid 500); 22 Jul 2008 04:38:33 -0000 Mailing-List: contact axis-cvs-help@ws.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: List-Post: List-Id: Delivered-To: mailing list axis-cvs@ws.apache.org Received: (qmail 68285 invoked by uid 500); 22 Jul 2008 04:38:33 -0000 Delivered-To: apmail-ws-axis2-cvs@ws.apache.org Received: (qmail 68282 invoked by uid 99); 22 Jul 2008 04:38:32 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 21 Jul 2008 21:38:32 -0700 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 22 Jul 2008 04:37:31 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 396F22388B20; Mon, 21 Jul 2008 21:36:10 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: 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/ ... Date: Tue, 22 Jul 2008 04:35:46 -0000 To: axis2-cvs@ws.apache.org From: dinesh@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20080722043610.396F22388B20@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org 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 +#include +#include + +#include +#include +#include +#include +#include +#include + +#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 +# include +# include +#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 + +/* 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 +# include +#endif + +#if defined HAVE_SYS_UIO_H && defined HAVE_SENDFILE && defined HAVE_WRITEV && (defined(__FreeBSD__) || defined(__DragonFly__)) +# define USE_FREEBSD_SENDFILE +# include +#endif + +#if defined HAVE_SYS_SENDFILE_H && defined HAVE_SENDFILEV && defined HAVE_WRITEV && defined(__sun) +# define USE_SOLARIS_SENDFILEV +# include +# include +#endif + +#if defined HAVE_SYS_UIO_H && defined HAVE_WRITEV +# define USE_WRITEV +# include +#endif + +#if defined HAVE_SYS_MMAN_H && defined HAVE_MMAP +# define USE_MMAP +# include +/* 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 +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "network.h" +#include "fdevent.h" +#include "log.h" +#include "stat_cache.h" + +# include +# include + +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 +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include + +#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 +#endif + +#ifdef HAVE_SYS_RESOURCE_H +#include +#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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include + +#include + +#include "plugin.h" +#include "log.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_VALGRIND_VALGRIND_H +#include +#endif + +#ifndef __WIN32 +#include +#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 +#include +#include +#include +#include "proc_open.h" + +#ifdef WIN32 +#include +#include +#else +#include +#include +#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 +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);