in native/common/jk_connect.c [617:831]
jk_sock_t jk_open_socket(jk_sockaddr_t *addr, jk_sockaddr_t *source,
int keepalive,
int timeout, int connect_timeout,
int sock_buf, jk_log_context_t *l)
{
char buf[DUMP_SINFO_BUF_SZ];
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(addr->family, 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, (const char*)&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)
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, (const char*)&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, (const char*)&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, (const char*)&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)
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, (const char*)&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, sizeof(buf)));
/* Need more infos for BSD 4.4 and Unix 98 defines, for now only
iSeries when Unix98 is required at compile time */
#if (_XOPEN_SOURCE >= 520) && defined(AS400)
((struct sockaddr *)addr)->sa.sin.sa_len = sizeof(struct sockaddr_in);
#endif
ret = nb_connect(sd, addr, source, connect_timeout, l);
#if defined(WIN32)
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, sizeof(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, sizeof(buf)));
}
JK_TRACE_EXIT(l);
return sd;
}