2
* Copyright 1999-2004 The Apache Software Foundation
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
* you may not use this file except in compliance with the License.
6
* You may obtain a copy of the License at
8
* http://www.apache.org/licenses/LICENSE-2.0
10
* Unless required by applicable law or agreed to in writing, software
11
* distributed under the License is distributed on an "AS IS" BASIS,
12
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
* See the License for the specific language governing permissions and
14
* limitations under the License.
18
* Description: Socket/Naming manipulation functions
19
* Based on: Various Jserv files
23
* @author Gal Shachor <shachor@il.ibm.com>
24
* @author Mladen Turk <mturk@apache.org>
25
* @version $Revision: 1.61 $
29
#include "jk_connect.h"
33
#include "apr_network_io.h"
34
#include "apr_errno.h"
35
#include "apr_general.h"
36
#include "apr_pools.h"
37
static apr_pool_t *jk_apr_pool = NULL;
40
#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
41
#define JK_IS_SOCKET_ERROR(x) ((x) == SOCKET_ERROR)
42
#define JK_GET_SOCKET_ERRNO() errno = WSAGetLastError() - WSABASEERR
44
#define JK_IS_SOCKET_ERROR(x) ((x) == -1)
45
#define JK_GET_SOCKET_ERRNO() ((void)0)
48
/* our compiler cant deal with char* <-> const char* ... */
49
#if defined(NETWARE) && !defined(__NOVELL_LIBC__)
50
typedef char* SET_TYPE;
52
typedef const char* SET_TYPE;
55
static int soblock(int sd)
57
/* BeOS uses setsockopt at present for non blocking... */
61
fd_flags = fcntl(sd, F_GETFL, 0);
62
#if defined(O_NONBLOCK)
63
fd_flags &= ~O_NONBLOCK;
64
#elif defined(O_NDELAY)
65
fd_flags &= ~O_NDELAY;
66
#elif defined(FNDELAY)
69
#error Please teach JK how to make sockets blocking on your platform.
71
if (fcntl(sd, F_SETFL, fd_flags) == -1) {
76
if (ioctlsocket(sd, FIONBIO, &on) == SOCKET_ERROR) {
77
errno = WSAGetLastError() - WSABASEERR;
84
static int sononblock(int sd)
89
fd_flags = fcntl(sd, F_GETFL, 0);
90
#if defined(O_NONBLOCK)
91
fd_flags |= O_NONBLOCK;
92
#elif defined(O_NDELAY)
94
#elif defined(FNDELAY)
97
#error Please teach JK how to make sockets non-blocking on your platform.
99
if (fcntl(sd, F_SETFL, fd_flags) == -1) {
104
if (ioctlsocket(sd, FIONBIO, &on) == SOCKET_ERROR) {
105
errno = WSAGetLastError() - WSABASEERR;
112
#if defined (WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
113
/* WIN32 implementation */
114
static int nb_connect(int sock, struct sockaddr *addr, int timeout)
118
return connect(sock, addr, sizeof(struct sockaddr_in));
120
if ((rc = sononblock(sock)))
122
if (connect(sock, addr, sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
124
fd_set wfdset, efdset;
126
if ((rc = WSAGetLastError()) != WSAEWOULDBLOCK) {
131
/* wait for the connect to complete or timeout */
133
FD_SET(sock, &wfdset);
135
FD_SET(sock, &efdset);
139
rc = select(FD_SETSIZE+1, NULL, &wfdset, &efdset, &tv);
140
if (rc == SOCKET_ERROR || rc == 0) {
141
rc = WSAGetLastError();
146
/* Evaluate the efdset */
147
if (FD_ISSET(sock, &efdset)) {
148
/* The connect failed. */
149
int rclen = sizeof(rc);
150
if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char*) &rc, &rclen))
162
#elif !defined(NETWARE)
163
/* POSIX implementation */
164
static int nb_connect(int sock, struct sockaddr *addr, int timeout)
169
if (sononblock(sock))
173
rc = connect(sock, addr, sizeof(struct sockaddr_in));
174
} while (rc == -1 && errno == EINTR);
176
if ((rc == -1) && (errno == EINPROGRESS || errno == EALREADY)
180
int rclen = sizeof(rc);
183
FD_SET(sock, &wfdset);
186
rc = select(sock+1, NULL, &wfdset, NULL, &tv);
196
if (!FD_ISSET(sock, &wfdset) ||
197
(getsockopt(sock, SOL_SOCKET, SO_ERROR,
198
(char *)&rc, &rclen) < 0) || rc) {
203
#endif /* SO_ERROR */
205
/* Not sure we can be already connected */
206
if (rc == -1 && errno == EISCONN)
212
/* NETWARE implementation - blocking for now */
213
static int nb_connect(int sock, struct sockaddr *addr, int timeout)
215
return connect(sock, addr, sizeof(struct sockaddr_in));
219
/** resolve the host IP */
221
int jk_resolve(const char *host, int port, struct sockaddr_in *rc)
224
struct in_addr laddr;
226
memset(rc, 0, sizeof(struct sockaddr_in));
228
rc->sin_port = htons((short)port);
229
rc->sin_family = AF_INET;
231
/* Check if we only have digits in the string */
232
for (x = 0; host[x] != '\0'; x++) {
233
if (!isdigit(host[x]) && host[x] != '.') {
238
/* If we found also characters we shoud make name to IP resolution */
239
if (host[x] != '\0') {
242
apr_sockaddr_t *remote_sa, *temp_sa;
246
if (apr_pool_create(&jk_apr_pool, NULL) != APR_SUCCESS)
249
if (apr_sockaddr_info_get
250
(&remote_sa, host, APR_UNSPEC, (apr_port_t) port, 0, jk_apr_pool)
254
/* Since we are only handling AF_INET (IPV4) address (in_addr_t) */
255
/* make sure we find one of those. */
257
while ((NULL != temp_sa) && (AF_INET != temp_sa->family))
258
temp_sa = temp_sa->next;
260
/* if temp_sa is set, we have a valid address otherwise, just return */
266
apr_sockaddr_ip_get(&remote_ipaddr, remote_sa);
267
laddr.s_addr = inet_addr(remote_ipaddr);
271
/* XXX : WARNING : We should really use gethostbyname_r in multi-threaded env */
272
/* Fortunatly when APR is available, ie under Apache 2.0, we use it */
273
#if defined(NETWARE) && !defined(__NOVELL_LIBC__)
274
struct hostent *hoste = gethostbyname((char*)host);
276
struct hostent *hoste = gethostbyname(host);
282
laddr = *((struct in_addr *)hoste->h_addr_list[0]);
284
#endif /* HAVE_APR */
287
/* If we found only digits we use inet_addr() */
288
laddr.s_addr = inet_addr(host);
290
memcpy(&(rc->sin_addr), &laddr, sizeof(laddr));
295
/** connect to Tomcat */
297
int jk_open_socket(struct sockaddr_in *addr, int keepalive,
298
int timeout, int sock_buf, jk_logger_t *l)
310
sock = socket(AF_INET, SOCK_STREAM, 0);
312
JK_GET_SOCKET_ERRNO();
313
jk_log(l, JK_LOG_ERROR,
314
"socket() failed with errno=%d", errno);
318
/* Disable Nagle algorithm */
319
if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (SET_TYPE)&set,
321
jk_log(l, JK_LOG_ERROR,
322
"failed setting TCP_NODELAY with errno=%d", errno);
323
jk_close_socket(sock);
327
if (JK_IS_DEBUG_LEVEL(l))
328
jk_log(l, JK_LOG_DEBUG,
329
"socket TCP_NODELAY set to On");
332
if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (SET_TYPE)&set,
334
jk_log(l, JK_LOG_ERROR,
335
"failed setting SO_KEEPALIVE with errno=%d", errno);
336
jk_close_socket(sock);
340
if (JK_IS_DEBUG_LEVEL(l))
341
jk_log(l, JK_LOG_DEBUG,
342
"socket SO_KEEPALIVE set to On");
347
/* Set socket send buffer size */
348
if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (SET_TYPE)&set,
350
JK_GET_SOCKET_ERRNO();
351
jk_log(l, JK_LOG_ERROR,
352
"failed setting SO_SNDBUF with errno=%d", errno);
353
jk_close_socket(sock);
358
/* Set socket receive buffer size */
359
if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (SET_TYPE)&set,
361
JK_GET_SOCKET_ERRNO();
362
jk_log(l, JK_LOG_ERROR,
363
"failed setting SO_RCVBUF with errno=%d", errno);
364
jk_close_socket(sock);
368
if (JK_IS_DEBUG_LEVEL(l))
369
jk_log(l, JK_LOG_DEBUG,
370
"socket SO_SNDBUF and SO_RCVBUF set to %d",
375
#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
376
int tmout = timeout * 1000;
377
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,
378
(const char *) &tmout, sizeof(int));
379
setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO,
380
(const char *) &tmout, sizeof(int));
381
#elif defined(SO_RCVTIMEO) && defined(USE_SO_RCVTIMEO) && defined(SO_SNDTIMEO) && defined(USE_SO_SNDTIMEO)
385
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,
386
(const void *) &tv, sizeof(tv));
387
setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO,
388
(const void *) &tv, sizeof(tv));
390
if (JK_IS_DEBUG_LEVEL(l))
391
jk_log(l, JK_LOG_DEBUG,
392
"timeout %d set for socket=%d",
396
/* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
397
* sending data to a dead peer. Possibly also existing and in use on other BSD
401
if (setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (const char *)&set,
403
JK_GET_SOCKET_ERRNO();
404
jk_log(l, JK_LOG_ERROR,
405
"failed setting SO_NOSIGPIPE with errno=%d", errno);
406
jk_close_socket(sock);
412
/* Make hard closesocket by disabling lingering */
413
li.l_linger = li.l_onoff = 0;
414
if (setsockopt(sock, SOL_SOCKET, SO_LINGER, (SET_TYPE)&li,
416
JK_GET_SOCKET_ERRNO();
417
jk_log(l, JK_LOG_ERROR,
418
"failed setting SO_LINGER with errno=%d", errno);
419
jk_close_socket(sock);
424
/* Tries to connect to Tomcat (continues trying while error is EINTR) */
425
if (JK_IS_DEBUG_LEVEL(l))
426
jk_log(l, JK_LOG_DEBUG,
427
"trying to connect socket %d to %s", sock,
428
jk_dump_hinfo(addr, buf));
430
/* Need more infos for BSD 4.4 and Unix 98 defines, for now only
431
iSeries when Unix98 is required at compil time */
432
#if (_XOPEN_SOURCE >= 520) && defined(AS400)
433
((struct sockaddr *)addr)->sa_len = sizeof(struct sockaddr_in);
435
ret = nb_connect(sock, (struct sockaddr *)addr, timeout);
436
#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
437
if (ret == SOCKET_ERROR) {
438
errno = WSAGetLastError() - WSABASEERR;
442
/* Check if we are connected */
444
jk_log(l, JK_LOG_INFO,
445
"connect to %s failed with errno=%d",
446
jk_dump_hinfo(addr, buf), errno);
447
jk_close_socket(sock);
451
if (JK_IS_DEBUG_LEVEL(l))
452
jk_log(l, JK_LOG_DEBUG, "socket %d connected to %s",
453
sock, jk_dump_hinfo(addr, buf));
459
/** close the socket */
461
int jk_close_socket(int s)
463
#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
464
if (s != INVALID_SOCKET)
465
return closesocket(s) ? -1 : 0;
474
#ifndef MAX_SECS_TO_LINGER
475
#define MAX_SECS_TO_LINGER 16
477
#define SECONDS_TO_LINGER 1
481
#define SHUT_WR SD_SEND
486
int jk_shutdown_socket(int s)
488
unsigned char dummy[512];
491
#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
492
int tmout = SECONDS_TO_LINGER * 1000;
493
if (s == INVALID_SOCKET)
500
/* Shut down the socket for write, which will send a FIN
503
if (shutdown(s, SHUT_WR)) {
504
return jk_close_socket(s);
506
#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
507
setsockopt(s, SOL_SOCKET, SO_RCVTIMEO,
508
(const char *) &tmout, sizeof(int));
509
#elif defined(SO_RCVTIMEO) && defined(USE_SO_RCVTIMEO)
510
tv.tv_sec = SECONDS_TO_LINGER;
512
setsockopt(s, SOL_SOCKET, SO_RCVTIMEO,
513
(const void *) &tv, sizeof(tv));
515
/* Read all data from the peer until we reach "end-of-file" (FIN
516
* from peer) or we've exceeded our overall timeout. If the client does
517
* not send us bytes within12 second, close the connection.
520
nbytes = jk_tcp_socket_recvfull(s, dummy, sizeof(dummy));
523
ttl += SECONDS_TO_LINGER;
524
if (ttl > MAX_SECS_TO_LINGER)
527
return jk_close_socket(s);
530
/** send a long message
531
* @param sd opened socket.
532
* @param b buffer containing the data.
533
* @param len length to send.
534
* @return -2: send returned 0 ? what this that ?
536
* >0: total size send.
537
* @bug this fails on Unixes if len is too big for the underlying
540
int jk_tcp_socket_sendfull(int sd, const unsigned char *b, int len)
547
#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
548
wr = send(sd, (const char*)(b + sent),
550
if (wr == SOCKET_ERROR)
551
errno = WSAGetLastError() - WSABASEERR;
553
wr = write(sd, b + sent, len - sent);
555
} while (wr == -1 && (errno == EINTR || errno == EAGAIN));
558
return (errno > 0) ? -errno : errno;
560
return JK_SOCKET_EOF;
567
/** receive len bytes. Used in ajp_common.
568
* @param sd opened socket.
569
* @param b buffer to store the data.
570
* @param len length to receive.
571
* @return <0: receive failed or connection closed.
572
* >0: length of the received data.
574
int jk_tcp_socket_recvfull(int sd, unsigned char *b, int len)
579
while (rdlen < len) {
581
#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
582
rd = recv(sd, (char *)b + rdlen,
584
/* Assuming SOCKET_ERROR is -1 on NETWARE too */
585
if (rd == SOCKET_ERROR)
586
errno = WSAGetLastError() - WSABASEERR;
588
rd = read(sd, (char *)b + rdlen, len - rdlen);
590
} while (rd == -1 && (errno == EINTR || errno == EAGAIN));
593
return (errno > 0) ? -errno : errno;
595
return JK_SOCKET_EOF;
603
* dump a sockaddr_in in A.B.C.D:P in ASCII buffer
606
char *jk_dump_hinfo(struct sockaddr_in *saddr, char *buf)
608
unsigned long laddr = (unsigned long)htonl(saddr->sin_addr.s_addr);
609
unsigned short lport = (unsigned short)htons(saddr->sin_port);
611
sprintf(buf, "%d.%d.%d.%d:%d",
612
(int)(laddr >> 24), (int)((laddr >> 16) & 0xff),
613
(int)((laddr >> 8) & 0xff), (int)(laddr & 0xff), (int)lport);
618
#if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
619
int jk_is_socket_connected(int sd)
628
/* Wait one microsecond */
632
/* If we get a timeout, then we are still connected */
633
if ((rc = select(1, &fd, NULL, NULL, &tv)) == 0) {
638
if (rc == SOCKET_ERROR)
639
errno = WSAGetLastError() - WSABASEERR;
646
int jk_is_socket_connected(int sd)
653
/* Set socket to nonblocking */
654
if (sononblock(sd) != 0)
657
rd = read(sd, test_buffer, 1);
658
} while (rd == -1 && errno == EINTR);
661
if (rd == -1 && saved_errno == EWOULDBLOCK) {
666
errno = saved_errno ? saved_errno : EOF;