summaryrefslogtreecommitdiffstats
path: root/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_connect.c
diff options
context:
space:
mode:
Diffstat (limited to 'rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_connect.c')
-rw-r--r--rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_connect.c1190
1 files changed, 0 insertions, 1190 deletions
diff --git a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_connect.c b/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_connect.c
deleted file mode 100644
index edf8c33b..00000000
--- a/rubbos/app/tomcat-connectors-1.2.32-src/native/common/jk_connect.c
+++ /dev/null
@@ -1,1190 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Description: Socket/Naming manipulation functions
- * Based on: Various Jserv files
- */
-/**
- * @package jk_connect
- * @author Gal Shachor <shachor@il.ibm.com>
- * @author Mladen Turk <mturk@apache.org>
- * @version $Revision: 1125651 $
- */
-
-
-#include "jk_connect.h"
-#include "jk_util.h"
-
-#ifdef HAVE_APR
-#include "apr_network_io.h"
-#include "apr_errno.h"
-#include "apr_general.h"
-#include "apr_pools.h"
-static apr_pool_t *jk_apr_pool = NULL;
-#endif
-
-#ifdef HAVE_SYS_FILIO_H
-/* FIONREAD on Solaris et al. */
-#include <sys/filio.h>
-#endif
-#ifdef HAVE_POLL_H
-/* Use poll instead select */
-#include <poll.h>
-#endif
-
-#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
-#define JK_IS_SOCKET_ERROR(x) ((x) == SOCKET_ERROR)
-#define JK_GET_SOCKET_ERRNO() errno = WSAGetLastError() - WSABASEERR
-#else
-#define JK_IS_SOCKET_ERROR(x) ((x) == -1)
-#define JK_GET_SOCKET_ERRNO() ((void)0)
-#endif /* WIN32 */
-
-#if defined(NETWARE) && defined(__NOVELL_LIBC__)
-#define USE_SOCK_CLOEXEC
-#endif
-
-/* our compiler cant deal with char* <-> const char* ... */
-#if defined(NETWARE) && !defined(__NOVELL_LIBC__)
-typedef char* SET_TYPE;
-#else
-typedef const char* SET_TYPE;
-#endif
-
-/** Set socket to blocking
- * @param sd socket to manipulate
- * @return errno: fcntl returns -1 (!WIN32)
- * pseudo errno: ioctlsocket returns SOCKET_ERROR (WIN32)
- * 0: success
- */
-static int soblock(jk_sock_t sd)
-{
-/* BeOS uses setsockopt at present for non blocking... */
-#if defined (WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
- u_long on = 0;
- if (JK_IS_SOCKET_ERROR(ioctlsocket(sd, FIONBIO, &on))) {
- JK_GET_SOCKET_ERRNO();
- return errno;
- }
-#else
- int fd_flags;
-
- fd_flags = fcntl(sd, F_GETFL, 0);
-#if defined(O_NONBLOCK)
- fd_flags &= ~O_NONBLOCK;
-#elif defined(O_NDELAY)
- fd_flags &= ~O_NDELAY;
-#elif defined(FNDELAY)
- fd_flags &= ~FNDELAY;
-#else
-#error Please teach JK how to make sockets blocking on your platform.
-#endif
- if (fcntl(sd, F_SETFL, fd_flags) == -1) {
- return errno;
- }
-#endif /* WIN32 || (NETWARE && __NOVELL_LIBC__) */
- return 0;
-}
-
-/** Set socket to non-blocking
- * @param sd socket to manipulate
- * @return errno: fcntl returns -1 (!WIN32)
- * pseudo errno: ioctlsocket returns SOCKET_ERROR (WIN32)
- * 0: success
- */
-static int sononblock(jk_sock_t sd)
-{
-#if defined (WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
- u_long on = 1;
- if (JK_IS_SOCKET_ERROR(ioctlsocket(sd, FIONBIO, &on))) {
- JK_GET_SOCKET_ERRNO();
- return errno;
- }
-#else
- int fd_flags;
-
- fd_flags = fcntl(sd, F_GETFL, 0);
-#if defined(O_NONBLOCK)
- fd_flags |= O_NONBLOCK;
-#elif defined(O_NDELAY)
- fd_flags |= O_NDELAY;
-#elif defined(FNDELAY)
- fd_flags |= FNDELAY;
-#else
-#error Please teach JK how to make sockets non-blocking on your platform.
-#endif
- if (fcntl(sd, F_SETFL, fd_flags) == -1) {
- return errno;
- }
-#endif /* WIN32 || (NETWARE && __NOVELL_LIBC__) */
- return 0;
-}
-
-#if defined (WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
-/* WIN32 implementation */
-/** Non-blocking socket connect
- * @param sd socket to connect
- * @param addr address to connect to
- * @param timeout connect timeout in seconds
- * (<=0: no timeout=blocking)
- * @param l logger
- * @return -1: some kind of error occured
- * SOCKET_ERROR: no timeout given and error
- * during blocking connect
- * 0: success
- */
-static int nb_connect(jk_sock_t sd, struct sockaddr *addr, int timeout, jk_logger_t *l)
-{
- int rc;
-
- JK_TRACE_ENTER(l);
-
- if (timeout <= 0) {
- rc = connect(sd, addr, sizeof(struct sockaddr_in));
- JK_TRACE_EXIT(l);
- return rc;
- }
-
- if ((rc = sononblock(sd))) {
- JK_TRACE_EXIT(l);
- return -1;
- }
- if (JK_IS_SOCKET_ERROR(connect(sd, addr, sizeof(struct sockaddr_in)))) {
- struct timeval tv;
- fd_set wfdset, efdset;
-
- if ((rc = WSAGetLastError()) != WSAEWOULDBLOCK) {
- soblock(sd);
- WSASetLastError(rc);
- JK_TRACE_EXIT(l);
- return -1;
- }
- /* wait for the connect to complete or timeout */
- FD_ZERO(&wfdset);
- FD_SET(sd, &wfdset);
- FD_ZERO(&efdset);
- FD_SET(sd, &efdset);
-
- tv.tv_sec = timeout / 1000;
- tv.tv_usec = (timeout % 1000) * 1000;
-
- rc = select((int)sd + 1, NULL, &wfdset, &efdset, &tv);
- if (JK_IS_SOCKET_ERROR(rc) || rc == 0) {
- rc = WSAGetLastError();
- soblock(sd);
- WSASetLastError(rc);
- JK_TRACE_EXIT(l);
- return -1;
- }
- /* Evaluate the efdset */
- if (FD_ISSET(sd, &efdset)) {
- /* The connect failed. */
- int rclen = (int)sizeof(rc);
- if (getsockopt(sd, SOL_SOCKET, SO_ERROR, (char*) &rc, &rclen))
- rc = 0;
- soblock(sd);
- if (rc)
- WSASetLastError(rc);
- JK_TRACE_EXIT(l);
- return -1;
- }
- }
- soblock(sd);
- JK_TRACE_EXIT(l);
- return 0;
-}
-
-#elif !defined(NETWARE)
-/* POSIX implementation */
-/** Non-blocking socket connect
- * @param sd socket to connect
- * @param addr address to connect to
- * @param timeout connect timeout in seconds
- * (<=0: no timeout=blocking)
- * @param l logger
- * @return -1: some kind of error occured
- * 0: success
- */
-static int nb_connect(jk_sock_t sd, struct sockaddr *addr, int timeout, jk_logger_t *l)
-{
- int rc = 0;
-
- JK_TRACE_ENTER(l);
-
- if (timeout > 0) {
- if (sononblock(sd)) {
- JK_TRACE_EXIT(l);
- return -1;
- }
- }
- do {
- rc = connect(sd, addr, sizeof(struct sockaddr_in));
- } while (rc == -1 && errno == EINTR);
-
- if ((rc == -1) && (errno == EINPROGRESS || errno == EALREADY)
- && (timeout > 0)) {
- fd_set wfdset;
- struct timeval tv;
- socklen_t rclen = (socklen_t)sizeof(rc);
-
- FD_ZERO(&wfdset);
- FD_SET(sd, &wfdset);
- tv.tv_sec = timeout / 1000;
- tv.tv_usec = (timeout % 1000) * 1000;
- rc = select(sd + 1, NULL, &wfdset, NULL, &tv);
- if (rc <= 0) {
- /* Save errno */
- int err = errno;
- soblock(sd);
- errno = err;
- JK_TRACE_EXIT(l);
- return -1;
- }
- rc = 0;
-#ifdef SO_ERROR
- if (!FD_ISSET(sd, &wfdset) ||
- (getsockopt(sd, SOL_SOCKET, SO_ERROR,
- (char *)&rc, &rclen) < 0) || rc) {
- if (rc)
- errno = rc;
- rc = -1;
- }
-#endif /* SO_ERROR */
- }
- /* Not sure we can be already connected */
- if (rc == -1 && errno == EISCONN)
- rc = 0;
- soblock(sd);
- JK_TRACE_EXIT(l);
- return rc;
-}
-#else
-/* NETWARE implementation - blocking for now */
-/** Non-blocking socket connect
- * @param sd socket to connect
- * @param addr address to connect to
- * @param timeout connect timeout in seconds (ignored!)
- * @param l logger
- * @return -1: some kind of error occured
- * 0: success
- */
-static int nb_connect(jk_sock_t sd, struct sockaddr *addr, int timeout, jk_logger_t *l)
-{
- int rc;
-
- JK_TRACE_ENTER(l);
-
- rc = connect(sd, addr, sizeof(struct sockaddr_in));
- JK_TRACE_EXIT(l);
- return rc;
-}
-#endif
-
-
-#ifdef AS400_UTF8
-
-/*
- * i5/OS V5R4 need EBCDIC for its runtime calls but APR/APACHE works in UTF
- */
-in_addr_t jk_inet_addr(const char * addrstr)
-{
- in_addr_t addr;
- char *ptr;
-
- ptr = (char *)malloc(strlen(addrstr) + 1);
- jk_ascii2ebcdic((char *)addrstr, ptr);
- addr = inet_addr(ptr);
- free(ptr);
-
- return(addr);
-}
-
-#endif
-
-/** Resolve the host IP
- * @param host host or ip address
- * @param port port
- * @param rc return value pointer
- * @param l logger
- * @return JK_FALSE: some kind of error occured
- * JK_TRUE: success
- */
-int jk_resolve(const char *host, int port, struct sockaddr_in *rc,
- void *pool, jk_logger_t *l)
-{
- int x;
- struct in_addr laddr;
-
- JK_TRACE_ENTER(l);
-
- memset(rc, 0, sizeof(struct sockaddr_in));
-
- rc->sin_port = htons((short)port);
- rc->sin_family = AF_INET;
-
- /* Check if we only have digits in the string */
- for (x = 0; host[x] != '\0'; x++) {
- if (!isdigit((int)(host[x])) && host[x] != '.') {
- break;
- }
- }
-
- /* If we found also characters we should make name to IP resolution */
- if (host[x] != '\0') {
-
-#ifdef HAVE_APR
- apr_sockaddr_t *remote_sa, *temp_sa;
- char *remote_ipaddr;
-
- if (!jk_apr_pool) {
- if (apr_pool_create(&jk_apr_pool, (apr_pool_t *)pool) != APR_SUCCESS) {
- JK_TRACE_EXIT(l);
- return JK_FALSE;
- }
- }
- apr_pool_clear(jk_apr_pool);
- if (apr_sockaddr_info_get
- (&remote_sa, host, APR_UNSPEC, (apr_port_t) port, 0, jk_apr_pool)
- != APR_SUCCESS) {
- JK_TRACE_EXIT(l);
- return JK_FALSE;
- }
-
- /* Since we are only handling AF_INET (IPV4) address (in_addr_t) */
- /* make sure we find one of those. */
- temp_sa = remote_sa;
- while ((NULL != temp_sa) && (AF_INET != temp_sa->family))
- temp_sa = temp_sa->next;
-
- /* if temp_sa is set, we have a valid address otherwise, just return */
- if (NULL != temp_sa)
- remote_sa = temp_sa;
- else {
- JK_TRACE_EXIT(l);
- return JK_FALSE;
- }
-
- apr_sockaddr_ip_get(&remote_ipaddr, remote_sa);
-
- laddr.s_addr = jk_inet_addr(remote_ipaddr);
-
-#else /* HAVE_APR */
-
- /* XXX : WARNING : We should really use gethostbyname_r in multi-threaded env */
- /* Fortunatly when APR is available, ie under Apache 2.0, we use it */
-#if defined(NETWARE) && !defined(__NOVELL_LIBC__)
- struct hostent *hoste = gethostbyname((char*)host);
-#else
- struct hostent *hoste = gethostbyname(host);
-#endif
- if (!hoste) {
- JK_TRACE_EXIT(l);
- return JK_FALSE;
- }
-
- laddr = *((struct in_addr *)hoste->h_addr_list[0]);
-
-#endif /* HAVE_APR */
- }
- else {
- /* If we found only digits we use inet_addr() */
- laddr.s_addr = jk_inet_addr(host);
- }
- memcpy(&(rc->sin_addr), &laddr, sizeof(laddr));
-
- JK_TRACE_EXIT(l);
- return JK_TRUE;
-}
-
-/** Connect to Tomcat
- * @param addr address to connect to
- * @param keepalive should we set SO_KEEPALIVE (if !=0)
- * @param timeout connect timeout in seconds
- * (<=0: no timeout=blocking)
- * @param sock_buf size of send and recv buffer
- * (<=0: use default)
- * @param l logger
- * @return JK_INVALID_SOCKET: some kind of error occured
- * created socket: success
- * @remark Cares about errno
- */
-jk_sock_t jk_open_socket(struct sockaddr_in *addr, int keepalive,
- int timeout, int connect_timeout,
- int sock_buf, jk_logger_t *l)
-{
- char buf[64];
- jk_sock_t sd;
- int set = 1;
- int ret = 0;
- int flags = 0;
-#ifdef SO_LINGER
- struct linger li;
-#endif
-
- JK_TRACE_ENTER(l);
-
- errno = 0;
-#if defined(SOCK_CLOEXEC) && defined(USE_SOCK_CLOEXEC)
- flags |= SOCK_CLOEXEC;
-#endif
- sd = socket(AF_INET, SOCK_STREAM | flags, 0);
- if (!IS_VALID_SOCKET(sd)) {
- JK_GET_SOCKET_ERRNO();
- jk_log(l, JK_LOG_ERROR,
- "socket() failed (errno=%d)", errno);
- JK_TRACE_EXIT(l);
- return JK_INVALID_SOCKET;
- }
-#if defined(FD_CLOEXEC) && !defined(USE_SOCK_CLOEXEC)
- if ((flags = fcntl(sd, F_GETFD)) == -1) {
- JK_GET_SOCKET_ERRNO();
- jk_log(l, JK_LOG_ERROR,
- "fcntl() failed (errno=%d)", errno);
- jk_close_socket(sd, l);
- JK_TRACE_EXIT(l);
- return JK_INVALID_SOCKET;
- }
- flags |= FD_CLOEXEC;
- if (fcntl(sd, F_SETFD, flags) == -1) {
- JK_GET_SOCKET_ERRNO();
- jk_log(l, JK_LOG_ERROR,
- "fcntl() failed (errno=%d)", errno);
- jk_close_socket(sd, l);
- JK_TRACE_EXIT(l);
- return JK_INVALID_SOCKET;
- }
-#endif
-
- /* Disable Nagle algorithm */
- if (setsockopt(sd, IPPROTO_TCP, TCP_NODELAY, (SET_TYPE)&set,
- sizeof(set))) {
- JK_GET_SOCKET_ERRNO();
- jk_log(l, JK_LOG_ERROR,
- "failed setting TCP_NODELAY (errno=%d)", errno);
- jk_close_socket(sd, l);
- JK_TRACE_EXIT(l);
- return JK_INVALID_SOCKET;
- }
- if (JK_IS_DEBUG_LEVEL(l))
- jk_log(l, JK_LOG_DEBUG,
- "socket TCP_NODELAY set to On");
- if (keepalive) {
-#if defined(WIN32) && !defined(NETWARE)
- DWORD dw;
- struct tcp_keepalive ka = { 0 }, ks = { 0 };
- if (timeout)
- ka.keepalivetime = timeout * 10000;
- else
- ka.keepalivetime = 60 * 10000; /* 10 minutes */
- ka.keepaliveinterval = 1000;
- ka.onoff = 1;
- if (WSAIoctl(sd, SIO_KEEPALIVE_VALS, &ka, sizeof(ka),
- &ks, sizeof(ks), &dw, NULL, NULL)) {
- JK_GET_SOCKET_ERRNO();
- jk_log(l, JK_LOG_ERROR,
- "failed setting SIO_KEEPALIVE_VALS (errno=%d)", errno);
- jk_close_socket(sd, l);
- JK_TRACE_EXIT(l);
- return JK_INVALID_SOCKET;
- }
- if (JK_IS_DEBUG_LEVEL(l))
- jk_log(l, JK_LOG_DEBUG,
- "socket SO_KEEPALIVE set to %d seconds",
- ka.keepalivetime / 1000);
-#else
- set = 1;
- if (setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE, (SET_TYPE)&set,
- sizeof(set))) {
- JK_GET_SOCKET_ERRNO();
- jk_log(l, JK_LOG_ERROR,
- "failed setting SO_KEEPALIVE (errno=%d)", errno);
- jk_close_socket(sd, l);
- JK_TRACE_EXIT(l);
- return JK_INVALID_SOCKET;
- }
- if (JK_IS_DEBUG_LEVEL(l))
- jk_log(l, JK_LOG_DEBUG,
- "socket SO_KEEPALIVE set to On");
-#endif
- }
-
- if (sock_buf > 0) {
- set = sock_buf;
- /* Set socket send buffer size */
- if (setsockopt(sd, SOL_SOCKET, SO_SNDBUF, (SET_TYPE)&set,
- sizeof(set))) {
- JK_GET_SOCKET_ERRNO();
- jk_log(l, JK_LOG_ERROR,
- "failed setting SO_SNDBUF (errno=%d)", errno);
- jk_close_socket(sd, l);
- JK_TRACE_EXIT(l);
- return JK_INVALID_SOCKET;
- }
- set = sock_buf;
- /* Set socket receive buffer size */
- if (setsockopt(sd, SOL_SOCKET, SO_RCVBUF, (SET_TYPE)&set,
- sizeof(set))) {
- JK_GET_SOCKET_ERRNO();
- jk_log(l, JK_LOG_ERROR,
- "failed setting SO_RCVBUF (errno=%d)", errno);
- jk_close_socket(sd, l);
- JK_TRACE_EXIT(l);
- return JK_INVALID_SOCKET;
- }
- if (JK_IS_DEBUG_LEVEL(l))
- jk_log(l, JK_LOG_DEBUG,
- "socket SO_SNDBUF and SO_RCVBUF set to %d",
- sock_buf);
- }
-
- if (timeout > 0) {
-#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
- int tmout = timeout * 1000;
- setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO,
- (const char *) &tmout, sizeof(int));
- setsockopt(sd, SOL_SOCKET, SO_SNDTIMEO,
- (const char *) &tmout, sizeof(int));
- JK_GET_SOCKET_ERRNO();
-#elif defined(SO_RCVTIMEO) && defined(USE_SO_RCVTIMEO) && defined(SO_SNDTIMEO) && defined(USE_SO_SNDTIMEO)
- struct timeval tv;
- tv.tv_sec = timeout;
- tv.tv_usec = 0;
- setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO,
- (const void *) &tv, sizeof(tv));
- setsockopt(sd, SOL_SOCKET, SO_SNDTIMEO,
- (const void *) &tv, sizeof(tv));
-#endif
- if (JK_IS_DEBUG_LEVEL(l))
- jk_log(l, JK_LOG_DEBUG,
- "timeout %d set for socket=%d",
- timeout, sd);
- }
-#ifdef SO_NOSIGPIPE
- /* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
- * sending data to a dead peer. Possibly also existing and in use on other BSD
- * systems?
- */
- set = 1;
- if (setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, (const char *)&set,
- sizeof(int))) {
- JK_GET_SOCKET_ERRNO();
- jk_log(l, JK_LOG_ERROR,
- "failed setting SO_NOSIGPIPE (errno=%d)", errno);
- jk_close_socket(sd, l);
- JK_TRACE_EXIT(l);
- return JK_INVALID_SOCKET;
- }
-#endif
-#ifdef SO_LINGER
- /* Make hard closesocket by disabling lingering */
- li.l_linger = li.l_onoff = 0;
- if (setsockopt(sd, SOL_SOCKET, SO_LINGER, (SET_TYPE)&li,
- sizeof(li))) {
- JK_GET_SOCKET_ERRNO();
- jk_log(l, JK_LOG_ERROR,
- "failed setting SO_LINGER (errno=%d)", errno);
- jk_close_socket(sd, l);
- JK_TRACE_EXIT(l);
- return JK_INVALID_SOCKET;
- }
-#endif
- /* Tries to connect to Tomcat (continues trying while error is EINTR) */
- if (JK_IS_DEBUG_LEVEL(l))
- jk_log(l, JK_LOG_DEBUG,
- "trying to connect socket %d to %s", sd,
- jk_dump_hinfo(addr, buf));
-
-/* Need more infos for BSD 4.4 and Unix 98 defines, for now only
-iSeries when Unix98 is required at compil time */
-#if (_XOPEN_SOURCE >= 520) && defined(AS400)
- ((struct sockaddr *)addr)->sa_len = sizeof(struct sockaddr_in);
-#endif
- ret = nb_connect(sd, (struct sockaddr *)addr, connect_timeout, l);
-#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
- if (JK_IS_SOCKET_ERROR(ret)) {
- JK_GET_SOCKET_ERRNO();
- }
-#endif /* WIN32 */
-
- /* Check if we are connected */
- if (ret) {
- jk_log(l, JK_LOG_INFO,
- "connect to %s failed (errno=%d)",
- jk_dump_hinfo(addr, buf), errno);
- jk_close_socket(sd, l);
- sd = JK_INVALID_SOCKET;
- }
- else {
- if (JK_IS_DEBUG_LEVEL(l))
- jk_log(l, JK_LOG_DEBUG, "socket %d [%s] connected",
- sd, jk_dump_sinfo(sd, buf));
- }
- JK_TRACE_EXIT(l);
- return sd;
-}
-
-/** Close the socket
- * @param sd socket to close
- * @param l logger
- * @return -1: some kind of error occured (!WIN32)
- * SOCKET_ERROR: some kind of error occured (WIN32)
- * 0: success
- * @remark Does not change errno
- */
-int jk_close_socket(jk_sock_t sd, jk_logger_t *l)
-{
- int rc;
- int save_errno;
-
- JK_TRACE_ENTER(l);
-
- if (!IS_VALID_SOCKET(sd)) {
- JK_TRACE_EXIT(l);
- return -1;
- }
-
- save_errno = errno;
-#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
- rc = closesocket(sd) ? -1 : 0;
-#else
- do {
- rc = close(sd);
- } while (JK_IS_SOCKET_ERROR(rc) && (errno == EINTR || errno == EAGAIN));
-#endif
- JK_TRACE_EXIT(l);
- errno = save_errno;
- return rc;
-}
-
-#ifndef MAX_SECS_TO_LINGER
-#define MAX_SECS_TO_LINGER 2
-#endif
-#define MS_TO_LINGER 500
-#define MS_TO_LINGER_LAST 2
-
-#ifndef MAX_LINGER_BYTES
-#define MAX_LINGER_BYTES 32768
-#endif
-
-#ifndef SHUT_WR
-#ifdef SD_SEND
-#define SHUT_WR SD_SEND
-#else
-#define SHUT_WR 0x01
-#endif
-#endif
-
-#ifndef SHUT_RD
-#ifdef SD_RECEIVE
-#define SHUT_RD SD_RECEIVE
-#else
-#define SHUT_RD 0x00
-#endif
-#endif
-
-/** Drain and close the socket
- * @param sd socket to close
- * @param l logger
- * @return -1: socket to close is invalid
- * -1: some kind of error occured (!WIN32)
- * SOCKET_ERROR: some kind of error occured (WIN32)
- * 0: success
- * @remark Does not change errno
- */
-int jk_shutdown_socket(jk_sock_t sd, jk_logger_t *l)
-{
- char dummy[512];
- char buf[64];
- char *sb = NULL;
- int rc = 0;
- size_t rd = 0;
- size_t rp = 0;
- int save_errno;
- int timeout = MS_TO_LINGER;
- time_t start = time(NULL);
-
- JK_TRACE_ENTER(l);
-
- if (!IS_VALID_SOCKET(sd)) {
- JK_TRACE_EXIT(l);
- return -1;
- }
-
- save_errno = errno;
- if (JK_IS_DEBUG_LEVEL(l)) {
- sb = jk_dump_sinfo(sd, buf);
- jk_log(l, JK_LOG_DEBUG, "About to shutdown socket %d [%s]",
- sd, sb);
- }
- /* Shut down the socket for write, which will send a FIN
- * to the peer.
- */
- if (shutdown(sd, SHUT_WR)) {
- rc = jk_close_socket(sd, l);
- if (JK_IS_DEBUG_LEVEL(l))
- jk_log(l, JK_LOG_DEBUG,
- "Failed sending SHUT_WR for socket %d [%s]",
- sd, sb);
- errno = save_errno;
- JK_TRACE_EXIT(l);
- return rc;
- }
-
- do {
- rp = 0;
- if (jk_is_input_event(sd, timeout, l)) {
- /* Do a restartable read on the socket
- * draining out all the data currently in the socket buffer.
- */
- do {
-#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
- rc = recv(sd, &dummy[0], sizeof(dummy), 0);
- if (JK_IS_SOCKET_ERROR(rc))
- JK_GET_SOCKET_ERRNO();
-#else
- rc = read(sd, &dummy[0], sizeof(dummy));
-#endif
- if (rc > 0)
- rp += rc;
- } while (JK_IS_SOCKET_ERROR(rc) && (errno == EINTR || errno == EAGAIN));
-
- if (rc < 0) {
- /* Read failed.
- * Bail out from the loop.
- */
- break;
- }
- }
- else {
- /* Error or timeout (reason is logged within jk_is_input_event)
- * Exit the drain loop
- */
- break;
- }
- rd += rp;
- if (rp < sizeof(dummy)) {
- if (timeout > MS_TO_LINGER_LAST) {
- /* Try one last time with a short timeout
- */
- timeout = MS_TO_LINGER_LAST;
- continue;
- }
- /* We have read less then size of buffer
- * It's a good chance there will be no more data
- * to read.
- */
- if ((rc = sononblock(sd))) {
- rc = jk_close_socket(sd, l);
- if (JK_IS_DEBUG_LEVEL(l))
- jk_log(l, JK_LOG_DEBUG,
- "error setting socket %d [%s] to nonblocking",
- sd, sb);
- errno = save_errno;
- JK_TRACE_EXIT(l);
- return rc;
- }
- if (JK_IS_DEBUG_LEVEL(l))
- jk_log(l, JK_LOG_DEBUG,
- "shutting down the read side of socket %d [%s]",
- sd, sb);
- shutdown(sd, SHUT_RD);
- break;
- }
- timeout = MS_TO_LINGER;
- } while ((rd < MAX_LINGER_BYTES) && (difftime(time(NULL), start) < MAX_SECS_TO_LINGER));
-
- rc = jk_close_socket(sd, l);
- if (JK_IS_DEBUG_LEVEL(l))
- jk_log(l, JK_LOG_DEBUG,
- "Shutdown socket %d [%s] and read %d lingering bytes in %d sec.",
- sd, sb, rd, (int)difftime(time(NULL), start));
- errno = save_errno;
- JK_TRACE_EXIT(l);
- return rc;
-}
-
-/** send a message
- * @param sd socket to use
- * @param b buffer containing the data
- * @param len length to send
- * @param l logger
- * @return negative errno: write returns a fatal -1 (!WIN32)
- * negative pseudo errno: send returns SOCKET_ERROR (WIN32)
- * JK_SOCKET_EOF: no bytes could be sent
- * >0: success, provided number of bytes send
- * @remark Always closes socket in case of error
- * @remark Cares about errno
- * @bug this fails on Unixes if len is too big for the underlying
- * protocol
- */
-int jk_tcp_socket_sendfull(jk_sock_t sd, const unsigned char *b, int len, jk_logger_t *l)
-{
- int sent = 0;
- int wr;
-
- JK_TRACE_ENTER(l);
-
- errno = 0;
- while (sent < len) {
- do {
-#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
- wr = send(sd, (const char*)(b + sent),
- len - sent, 0);
- if (JK_IS_SOCKET_ERROR(wr))
- JK_GET_SOCKET_ERRNO();
-#else
- wr = write(sd, b + sent, len - sent);
-#endif
- } while (JK_IS_SOCKET_ERROR(wr) && (errno == EINTR || errno == EAGAIN));
-
- if (JK_IS_SOCKET_ERROR(wr)) {
- int err;
- jk_shutdown_socket(sd, l);
- err = (errno > 0) ? -errno : errno;
- JK_TRACE_EXIT(l);
- return err;
- }
- else if (wr == 0) {
- jk_shutdown_socket(sd, l);
- JK_TRACE_EXIT(l);
- return JK_SOCKET_EOF;
- }
- sent += wr;
- }
-
- JK_TRACE_EXIT(l);
- return sent;
-}
-
-/** receive a message
- * @param sd socket to use
- * @param b buffer to store the data
- * @param len length to receive
- * @param l logger
- * @return negative errno: read returns a fatal -1 (!WIN32)
- * negative pseudo errno: recv returns SOCKET_ERROR (WIN32)
- * JK_SOCKET_EOF: no bytes could be read
- * >0: success, requested number of bytes received
- * @remark Always closes socket in case of error
- * @remark Cares about errno
- */
-int jk_tcp_socket_recvfull(jk_sock_t sd, unsigned char *b, int len, jk_logger_t *l)
-{
- int rdlen = 0;
- int rd;
-
- JK_TRACE_ENTER(l);
-
- errno = 0;
- while (rdlen < len) {
- do {
-#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
- rd = recv(sd, (char *)b + rdlen,
- len - rdlen, 0);
- if (JK_IS_SOCKET_ERROR(rd))
- JK_GET_SOCKET_ERRNO();
-#else
- rd = read(sd, (char *)b + rdlen, len - rdlen);
-#endif
- } while (JK_IS_SOCKET_ERROR(rd) && errno == EINTR);
-
- if (JK_IS_SOCKET_ERROR(rd)) {
- int err = (errno > 0) ? -errno : errno;
- jk_shutdown_socket(sd, l);
- JK_TRACE_EXIT(l);
- return (err == 0) ? JK_SOCKET_EOF : err;
- }
- else if (rd == 0) {
- jk_shutdown_socket(sd, l);
- JK_TRACE_EXIT(l);
- return JK_SOCKET_EOF;
- }
- rdlen += rd;
- }
-
- JK_TRACE_EXIT(l);
- return rdlen;
-}
-
-/**
- * dump a sockaddr_in in A.B.C.D:P in ASCII buffer
- *
- */
-char *jk_dump_hinfo(struct sockaddr_in *saddr, char *buf)
-{
- unsigned long laddr = (unsigned long)htonl(saddr->sin_addr.s_addr);
- unsigned short lport = (unsigned short)htons(saddr->sin_port);
-
- sprintf(buf, "%d.%d.%d.%d:%d",
- (int)(laddr >> 24), (int)((laddr >> 16) & 0xff),
- (int)((laddr >> 8) & 0xff), (int)(laddr & 0xff), (int)lport);
-
- return buf;
-}
-
-char *jk_dump_sinfo(jk_sock_t sd, char *buf)
-{
- struct sockaddr_in rsaddr;
- struct sockaddr_in lsaddr;
- socklen_t salen;
-
- salen = sizeof(struct sockaddr);
- if (getsockname(sd, (struct sockaddr *)&lsaddr, &salen) == 0) {
- salen = sizeof(struct sockaddr);
- if (getpeername(sd, (struct sockaddr *)&rsaddr, &salen) == 0) {
- unsigned long laddr = (unsigned long)htonl(lsaddr.sin_addr.s_addr);
- unsigned short lport = (unsigned short)htons(lsaddr.sin_port);
- unsigned long raddr = (unsigned long)htonl(rsaddr.sin_addr.s_addr);
- unsigned short rport = (unsigned short)htons(rsaddr.sin_port);
- sprintf(buf, "%d.%d.%d.%d:%d -> %d.%d.%d.%d:%d",
- (int)(laddr >> 24), (int)((laddr >> 16) & 0xff),
- (int)((laddr >> 8) & 0xff), (int)(laddr & 0xff), (int)lport,
- (int)(raddr >> 24), (int)((raddr >> 16) & 0xff),
- (int)((raddr >> 8) & 0xff), (int)(raddr & 0xff), (int)rport);
- return buf;
- }
- }
- sprintf(buf, "error=%d", errno);
- return buf;
-}
-
-/** Wait for input event on socket until timeout
- * @param sd socket to use
- * @param timeout wait timeout in milliseconds
- * @param l logger
- * @return JK_FALSE: Timeout expired without something to read
- * JK_FALSE: Error during waiting
- * JK_TRUE: success
- * @remark Does not close socket in case of error
- * to allow for iterative waiting
- * @remark Cares about errno
- */
-#ifdef HAVE_POLL
-int jk_is_input_event(jk_sock_t sd, int timeout, jk_logger_t *l)
-{
- struct pollfd fds;
- int rc;
- int save_errno;
- char buf[64];
-
- JK_TRACE_ENTER(l);
-
- errno = 0;
- fds.fd = sd;
- fds.events = POLLIN;
- fds.revents = 0;
-
- do {
- rc = poll(&fds, 1, timeout);
- } while (rc < 0 && errno == EINTR);
-
- if (rc == 0) {
- if (JK_IS_DEBUG_LEVEL(l)) {
- jk_log(l, JK_LOG_DEBUG,
- "timeout during poll on socket %d [%s] (timeout=%d)",
- sd, jk_dump_sinfo(sd, buf), timeout);
- }
- /* Timeout. Set the errno to timeout */
- errno = ETIMEDOUT;
- JK_TRACE_EXIT(l);
- return JK_FALSE;
- }
- else if (rc < 0) {
- save_errno = errno;
- if (JK_IS_DEBUG_LEVEL(l)) {
- jk_log(l, JK_LOG_DEBUG,
- "error during poll on socket %d [%s] (errno=%d)",
- sd, jk_dump_sinfo(sd, buf), errno);
- }
- errno = save_errno;
- JK_TRACE_EXIT(l);
- return JK_FALSE;
- }
- if ((fds.revents & (POLLERR | POLLHUP))) {
- save_errno = fds.revents & (POLLERR | POLLHUP);
- if (JK_IS_DEBUG_LEVEL(l)) {
- jk_log(l, JK_LOG_DEBUG,
- "error event during poll on socket %d [%s] (event=%d)",
- sd, jk_dump_sinfo(sd, buf), save_errno);
- }
- errno = save_errno;
- JK_TRACE_EXIT(l);
- return JK_FALSE;
- }
- errno = 0;
- JK_TRACE_EXIT(l);
- return JK_TRUE;
-}
-#else
-int jk_is_input_event(jk_sock_t sd, int timeout, jk_logger_t *l)
-{
- fd_set rset;
- struct timeval tv;
- int rc;
- int save_errno;
- char buf[64];
-
- JK_TRACE_ENTER(l);
-
- errno = 0;
- FD_ZERO(&rset);
- FD_SET(sd, &rset);
- tv.tv_sec = timeout / 1000;
- tv.tv_usec = (timeout % 1000) * 1000;
-
- do {
- rc = select((int)sd + 1, &rset, NULL, NULL, &tv);
- } while (rc < 0 && errno == EINTR);
-
- if (rc == 0) {
- if (JK_IS_DEBUG_LEVEL(l)) {
- jk_log(l, JK_LOG_DEBUG,
- "timeout during select on socket %d [%s] (timeout=%d)",
- sd, jk_dump_sinfo(sd, buf), timeout);
- }
- /* Timeout. Set the errno to timeout */
-#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
- errno = WSAETIMEDOUT - WSABASEERR;
-#else
- errno = ETIMEDOUT;
-#endif
- JK_TRACE_EXIT(l);
- return JK_FALSE;
- }
- else if (rc < 0) {
- save_errno = errno;
- if (JK_IS_DEBUG_LEVEL(l)) {
- jk_log(l, JK_LOG_DEBUG,
- "error during select on socket %d [%s] (errno=%d)",
- sd, jk_dump_sinfo(sd, buf), errno);
- }
- errno = save_errno;
- JK_TRACE_EXIT(l);
- return JK_FALSE;
- }
- errno = 0;
- JK_TRACE_EXIT(l);
- return JK_TRUE;
-}
-#endif
-
-/** Test if a socket is still connected
- * @param sd socket to use
- * @param l logger
- * @return JK_FALSE: failure
- * JK_TRUE: success
- * @remark Always closes socket in case of error
- * @remark Cares about errno
- */
-#ifdef HAVE_POLL
-int jk_is_socket_connected(jk_sock_t sd, jk_logger_t *l)
-{
- struct pollfd fds;
- int rc;
-
- JK_TRACE_ENTER(l);
-
- errno = 0;
- fds.fd = sd;
- fds.events = POLLIN;
-
- do {
- rc = poll(&fds, 1, 0);
- } while (rc < 0 && errno == EINTR);
-
- if (rc == 0) {
- /* If we get a timeout, then we are still connected */
- JK_TRACE_EXIT(l);
- return JK_TRUE;
- }
- else if (rc == 1 && fds.revents == POLLIN) {
- char buf;
- do {
- rc = (int)recvfrom(sd, &buf, 1, MSG_PEEK, NULL, NULL);
- } while (rc < 0 && errno == EINTR);
- if (rc == 1) {
- /* There is at least one byte to read. */
- JK_TRACE_EXIT(l);
- return JK_TRUE;
- }
- }
- jk_shutdown_socket(sd, l);
-
- JK_TRACE_EXIT(l);
- return JK_FALSE;
-}
-
-#else
-int jk_is_socket_connected(jk_sock_t sd, jk_logger_t *l)
-{
- fd_set fd;
- struct timeval tv;
- int rc;
-
- JK_TRACE_ENTER(l);
-
- errno = 0;
- FD_ZERO(&fd);
- FD_SET(sd, &fd);
-
- /* Initially test the socket without any blocking.
- */
- tv.tv_sec = 0;
- tv.tv_usec = 0;
-
- do {
- rc = select((int)sd + 1, &fd, NULL, NULL, &tv);
- JK_GET_SOCKET_ERRNO();
- /* Wait one microsecond on next select, if EINTR */
- tv.tv_sec = 0;
- tv.tv_usec = 1;
- } while (JK_IS_SOCKET_ERROR(rc) && errno == EINTR);
-
- errno = 0;
- if (rc == 0) {
- /* If we get a timeout, then we are still connected */
- JK_TRACE_EXIT(l);
- return JK_TRUE;
- }
- else if (rc == 1) {
-#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
- u_long nr;
- rc = ioctlsocket(sd, FIONREAD, &nr);
- if (rc == 0) {
- if (WSAGetLastError() == 0)
- errno = 0;
- else
- JK_GET_SOCKET_ERRNO();
- }
-#else
- int nr;
- rc = ioctl(sd, FIONREAD, (void*)&nr);
-#endif
- if (rc == 0 && nr != 0) {
- JK_TRACE_EXIT(l);
- return JK_TRUE;
- }
- JK_GET_SOCKET_ERRNO();
- }
- jk_shutdown_socket(sd, l);
-
- JK_TRACE_EXIT(l);
- return JK_FALSE;
-}
-#endif
-