bottleneck testcase based on rubbos
[bottlenecks.git] / rubbos / app / tomcat-connectors-1.2.32-src / native / common / jk_connect.c
1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17
18 /*
19  * Description: Socket/Naming manipulation functions
20  * Based on:    Various Jserv files
21  */
22 /**
23  * @package jk_connect
24  * @author      Gal Shachor <shachor@il.ibm.com>
25  * @author      Mladen Turk <mturk@apache.org>
26  * @version     $Revision: 1125651 $
27  */
28
29
30 #include "jk_connect.h"
31 #include "jk_util.h"
32
33 #ifdef HAVE_APR
34 #include "apr_network_io.h"
35 #include "apr_errno.h"
36 #include "apr_general.h"
37 #include "apr_pools.h"
38 static apr_pool_t *jk_apr_pool = NULL;
39 #endif
40
41 #ifdef HAVE_SYS_FILIO_H
42 /* FIONREAD on Solaris et al. */
43 #include <sys/filio.h>
44 #endif
45 #ifdef HAVE_POLL_H
46 /* Use poll instead select */
47 #include <poll.h>
48 #endif
49
50 #if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
51 #define JK_IS_SOCKET_ERROR(x) ((x) == SOCKET_ERROR)
52 #define JK_GET_SOCKET_ERRNO() errno = WSAGetLastError() - WSABASEERR
53 #else
54 #define JK_IS_SOCKET_ERROR(x) ((x) == -1)
55 #define JK_GET_SOCKET_ERRNO() ((void)0)
56 #endif /* WIN32 */
57
58 #if defined(NETWARE) && defined(__NOVELL_LIBC__)
59 #define USE_SOCK_CLOEXEC
60 #endif
61
62 /* our compiler cant deal with char* <-> const char* ... */
63 #if defined(NETWARE) && !defined(__NOVELL_LIBC__)
64 typedef char* SET_TYPE;
65 #else
66 typedef const char* SET_TYPE;
67 #endif
68
69 /** Set socket to blocking
70  * @param sd  socket to manipulate
71  * @return    errno: fcntl returns -1 (!WIN32)
72  *            pseudo errno: ioctlsocket returns SOCKET_ERROR (WIN32)
73  *            0: success
74  */
75 static int soblock(jk_sock_t sd)
76 {
77 /* BeOS uses setsockopt at present for non blocking... */
78 #if defined (WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
79     u_long on = 0;
80     if (JK_IS_SOCKET_ERROR(ioctlsocket(sd, FIONBIO, &on))) {
81         JK_GET_SOCKET_ERRNO();
82         return errno;
83     }
84 #else
85     int fd_flags;
86
87     fd_flags = fcntl(sd, F_GETFL, 0);
88 #if defined(O_NONBLOCK)
89     fd_flags &= ~O_NONBLOCK;
90 #elif defined(O_NDELAY)
91     fd_flags &= ~O_NDELAY;
92 #elif defined(FNDELAY)
93     fd_flags &= ~FNDELAY;
94 #else
95 #error Please teach JK how to make sockets blocking on your platform.
96 #endif
97     if (fcntl(sd, F_SETFL, fd_flags) == -1) {
98         return errno;
99     }
100 #endif /* WIN32 || (NETWARE && __NOVELL_LIBC__) */
101     return 0;
102 }
103
104 /** Set socket to non-blocking
105  * @param sd  socket to manipulate
106  * @return    errno: fcntl returns -1 (!WIN32)
107  *            pseudo errno: ioctlsocket returns SOCKET_ERROR (WIN32)
108  *            0: success
109  */
110 static int sononblock(jk_sock_t sd)
111 {
112 #if defined (WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
113     u_long on = 1;
114     if (JK_IS_SOCKET_ERROR(ioctlsocket(sd, FIONBIO, &on))) {
115         JK_GET_SOCKET_ERRNO();
116         return errno;
117     }
118 #else
119     int fd_flags;
120
121     fd_flags = fcntl(sd, F_GETFL, 0);
122 #if defined(O_NONBLOCK)
123     fd_flags |= O_NONBLOCK;
124 #elif defined(O_NDELAY)
125     fd_flags |= O_NDELAY;
126 #elif defined(FNDELAY)
127     fd_flags |= FNDELAY;
128 #else
129 #error Please teach JK how to make sockets non-blocking on your platform.
130 #endif
131     if (fcntl(sd, F_SETFL, fd_flags) == -1) {
132         return errno;
133     }
134 #endif /* WIN32 || (NETWARE && __NOVELL_LIBC__) */
135     return 0;
136 }
137
138 #if defined (WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
139 /* WIN32 implementation */
140 /** Non-blocking socket connect
141  * @param sd       socket to connect
142  * @param addr     address to connect to
143  * @param timeout  connect timeout in seconds
144  *                 (<=0: no timeout=blocking)
145  * @param l        logger
146  * @return         -1: some kind of error occured
147  *                 SOCKET_ERROR: no timeout given and error
148  *                               during blocking connect
149  *                 0: success
150  */
151 static int nb_connect(jk_sock_t sd, struct sockaddr *addr, int timeout, jk_logger_t *l)
152 {
153     int rc;
154
155     JK_TRACE_ENTER(l);
156
157     if (timeout <= 0) {
158         rc = connect(sd, addr, sizeof(struct sockaddr_in));
159         JK_TRACE_EXIT(l);
160         return rc;
161     }
162
163     if ((rc = sononblock(sd))) {
164         JK_TRACE_EXIT(l);
165         return -1;
166     }
167     if (JK_IS_SOCKET_ERROR(connect(sd, addr, sizeof(struct sockaddr_in)))) {
168         struct timeval tv;
169         fd_set wfdset, efdset;
170
171         if ((rc = WSAGetLastError()) != WSAEWOULDBLOCK) {
172             soblock(sd);
173             WSASetLastError(rc);
174             JK_TRACE_EXIT(l);
175             return -1;
176         }
177         /* wait for the connect to complete or timeout */
178         FD_ZERO(&wfdset);
179         FD_SET(sd, &wfdset);
180         FD_ZERO(&efdset);
181         FD_SET(sd, &efdset);
182
183         tv.tv_sec = timeout / 1000;
184         tv.tv_usec = (timeout % 1000) * 1000;
185
186         rc = select((int)sd + 1, NULL, &wfdset, &efdset, &tv);
187         if (JK_IS_SOCKET_ERROR(rc) || rc == 0) {
188             rc = WSAGetLastError();
189             soblock(sd);
190             WSASetLastError(rc);
191             JK_TRACE_EXIT(l);
192             return -1;
193         }
194         /* Evaluate the efdset */
195         if (FD_ISSET(sd, &efdset)) {
196             /* The connect failed. */
197             int rclen = (int)sizeof(rc);
198             if (getsockopt(sd, SOL_SOCKET, SO_ERROR, (char*) &rc, &rclen))
199                 rc = 0;
200             soblock(sd);
201             if (rc)
202                 WSASetLastError(rc);
203             JK_TRACE_EXIT(l);
204             return -1;
205         }
206     }
207     soblock(sd);
208     JK_TRACE_EXIT(l);
209     return 0;
210 }
211
212 #elif !defined(NETWARE)
213 /* POSIX implementation */
214 /** Non-blocking socket connect
215  * @param sd       socket to connect
216  * @param addr     address to connect to
217  * @param timeout  connect timeout in seconds
218  *                 (<=0: no timeout=blocking)
219  * @param l        logger
220  * @return         -1: some kind of error occured
221  *                 0: success
222  */
223 static int nb_connect(jk_sock_t sd, struct sockaddr *addr, int timeout, jk_logger_t *l)
224 {
225     int rc = 0;
226
227     JK_TRACE_ENTER(l);
228
229     if (timeout > 0) {
230         if (sononblock(sd)) {
231             JK_TRACE_EXIT(l);
232             return -1;
233         }
234     }
235     do {
236         rc = connect(sd, addr, sizeof(struct sockaddr_in));
237     } while (rc == -1 && errno == EINTR);
238
239     if ((rc == -1) && (errno == EINPROGRESS || errno == EALREADY)
240                    && (timeout > 0)) {
241         fd_set wfdset;
242         struct timeval tv;
243         socklen_t rclen = (socklen_t)sizeof(rc);
244
245         FD_ZERO(&wfdset);
246         FD_SET(sd, &wfdset);
247         tv.tv_sec = timeout / 1000;
248         tv.tv_usec = (timeout % 1000) * 1000;
249         rc = select(sd + 1, NULL, &wfdset, NULL, &tv);
250         if (rc <= 0) {
251             /* Save errno */
252             int err = errno;
253             soblock(sd);
254             errno = err;
255             JK_TRACE_EXIT(l);
256             return -1;
257         }
258         rc = 0;
259 #ifdef SO_ERROR
260         if (!FD_ISSET(sd, &wfdset) ||
261             (getsockopt(sd, SOL_SOCKET, SO_ERROR,
262                         (char *)&rc, &rclen) < 0) || rc) {
263             if (rc)
264                 errno = rc;
265             rc = -1;
266         }
267 #endif /* SO_ERROR */
268     }
269     /* Not sure we can be already connected */
270     if (rc == -1 && errno == EISCONN)
271         rc = 0;
272     soblock(sd);
273     JK_TRACE_EXIT(l);
274     return rc;
275 }
276 #else
277 /* NETWARE implementation - blocking for now */
278 /** Non-blocking socket connect
279  * @param sd       socket to connect
280  * @param addr     address to connect to
281  * @param timeout  connect timeout in seconds (ignored!)
282  * @param l        logger
283  * @return         -1: some kind of error occured
284  *                 0: success
285  */
286 static int nb_connect(jk_sock_t sd, struct sockaddr *addr, int timeout, jk_logger_t *l)
287 {
288     int rc;
289
290     JK_TRACE_ENTER(l);
291
292     rc = connect(sd, addr, sizeof(struct sockaddr_in));
293     JK_TRACE_EXIT(l);
294     return rc;
295 }
296 #endif
297
298
299 #ifdef AS400_UTF8
300
301 /*
302  *  i5/OS V5R4 need EBCDIC for its runtime calls but APR/APACHE works in UTF
303  */
304 in_addr_t jk_inet_addr(const char * addrstr)
305 {
306     in_addr_t addr;
307     char *ptr;
308
309     ptr = (char *)malloc(strlen(addrstr) + 1);
310     jk_ascii2ebcdic((char *)addrstr, ptr);
311     addr = inet_addr(ptr);
312     free(ptr);
313
314     return(addr);
315 }
316
317 #endif
318
319 /** Resolve the host IP
320  * @param host     host or ip address
321  * @param port     port
322  * @param rc       return value pointer
323  * @param l        logger
324  * @return         JK_FALSE: some kind of error occured
325  *                 JK_TRUE: success
326  */
327 int jk_resolve(const char *host, int port, struct sockaddr_in *rc,
328                void *pool, jk_logger_t *l)
329 {
330     int x;
331     struct in_addr laddr;
332
333     JK_TRACE_ENTER(l);
334
335     memset(rc, 0, sizeof(struct sockaddr_in));
336
337     rc->sin_port = htons((short)port);
338     rc->sin_family = AF_INET;
339
340     /* Check if we only have digits in the string */
341     for (x = 0; host[x] != '\0'; x++) {
342         if (!isdigit((int)(host[x])) && host[x] != '.') {
343             break;
344         }
345     }
346
347     /* If we found also characters we should make name to IP resolution */
348     if (host[x] != '\0') {
349
350 #ifdef HAVE_APR
351         apr_sockaddr_t *remote_sa, *temp_sa;
352         char *remote_ipaddr;
353
354         if (!jk_apr_pool) {
355             if (apr_pool_create(&jk_apr_pool, (apr_pool_t *)pool) != APR_SUCCESS) {
356                 JK_TRACE_EXIT(l);
357                 return JK_FALSE;
358             }
359         }
360         apr_pool_clear(jk_apr_pool);
361         if (apr_sockaddr_info_get
362             (&remote_sa, host, APR_UNSPEC, (apr_port_t) port, 0, jk_apr_pool)
363             != APR_SUCCESS) {
364             JK_TRACE_EXIT(l);
365             return JK_FALSE;
366         }
367
368         /* Since we are only handling AF_INET (IPV4) address (in_addr_t) */
369         /* make sure we find one of those.                               */
370         temp_sa = remote_sa;
371         while ((NULL != temp_sa) && (AF_INET != temp_sa->family))
372             temp_sa = temp_sa->next;
373
374         /* if temp_sa is set, we have a valid address otherwise, just return */
375         if (NULL != temp_sa)
376             remote_sa = temp_sa;
377         else {
378             JK_TRACE_EXIT(l);
379             return JK_FALSE;
380         }
381
382         apr_sockaddr_ip_get(&remote_ipaddr, remote_sa);
383
384         laddr.s_addr = jk_inet_addr(remote_ipaddr);
385
386 #else /* HAVE_APR */
387
388         /* XXX : WARNING : We should really use gethostbyname_r in multi-threaded env */
389         /* Fortunatly when APR is available, ie under Apache 2.0, we use it */
390 #if defined(NETWARE) && !defined(__NOVELL_LIBC__)
391         struct hostent *hoste = gethostbyname((char*)host);
392 #else
393         struct hostent *hoste = gethostbyname(host);
394 #endif
395         if (!hoste) {
396             JK_TRACE_EXIT(l);
397             return JK_FALSE;
398         }
399
400         laddr = *((struct in_addr *)hoste->h_addr_list[0]);
401
402 #endif /* HAVE_APR */
403     }
404     else {
405         /* If we found only digits we use inet_addr() */
406         laddr.s_addr = jk_inet_addr(host);
407     }
408     memcpy(&(rc->sin_addr), &laddr, sizeof(laddr));
409
410     JK_TRACE_EXIT(l);
411     return JK_TRUE;
412 }
413
414 /** Connect to Tomcat
415  * @param addr      address to connect to
416  * @param keepalive should we set SO_KEEPALIVE (if !=0)
417  * @param timeout   connect timeout in seconds
418  *                  (<=0: no timeout=blocking)
419  * @param sock_buf  size of send and recv buffer
420  *                  (<=0: use default)
421  * @param l         logger
422  * @return          JK_INVALID_SOCKET: some kind of error occured
423  *                  created socket: success
424  * @remark          Cares about errno
425  */
426 jk_sock_t jk_open_socket(struct sockaddr_in *addr, int keepalive,
427                          int timeout, int connect_timeout,
428                          int sock_buf, jk_logger_t *l)
429 {
430     char buf[64];
431     jk_sock_t sd;
432     int set = 1;
433     int ret = 0;
434     int flags = 0;
435 #ifdef SO_LINGER
436     struct linger li;
437 #endif
438
439     JK_TRACE_ENTER(l);
440
441     errno = 0;
442 #if defined(SOCK_CLOEXEC) && defined(USE_SOCK_CLOEXEC)
443     flags |= SOCK_CLOEXEC;
444 #endif
445     sd = socket(AF_INET, SOCK_STREAM | flags, 0);
446     if (!IS_VALID_SOCKET(sd)) {
447         JK_GET_SOCKET_ERRNO();
448         jk_log(l, JK_LOG_ERROR,
449                "socket() failed (errno=%d)", errno);
450         JK_TRACE_EXIT(l);
451         return JK_INVALID_SOCKET;
452     }
453 #if defined(FD_CLOEXEC) && !defined(USE_SOCK_CLOEXEC)
454     if ((flags = fcntl(sd, F_GETFD)) == -1) {
455         JK_GET_SOCKET_ERRNO();
456         jk_log(l, JK_LOG_ERROR,
457                "fcntl() failed (errno=%d)", errno);
458         jk_close_socket(sd, l);
459         JK_TRACE_EXIT(l);
460         return JK_INVALID_SOCKET;
461     }
462     flags |= FD_CLOEXEC;
463     if (fcntl(sd, F_SETFD, flags) == -1) {
464         JK_GET_SOCKET_ERRNO();
465         jk_log(l, JK_LOG_ERROR,
466                "fcntl() failed (errno=%d)", errno);
467         jk_close_socket(sd, l);
468         JK_TRACE_EXIT(l);
469         return JK_INVALID_SOCKET;
470     }
471 #endif
472
473     /* Disable Nagle algorithm */
474     if (setsockopt(sd, IPPROTO_TCP, TCP_NODELAY, (SET_TYPE)&set,
475                    sizeof(set))) {
476         JK_GET_SOCKET_ERRNO();
477         jk_log(l, JK_LOG_ERROR,
478                 "failed setting TCP_NODELAY (errno=%d)", errno);
479         jk_close_socket(sd, l);
480         JK_TRACE_EXIT(l);
481         return JK_INVALID_SOCKET;
482     }
483     if (JK_IS_DEBUG_LEVEL(l))
484         jk_log(l, JK_LOG_DEBUG,
485                "socket TCP_NODELAY set to On");
486     if (keepalive) {
487 #if defined(WIN32) && !defined(NETWARE)
488         DWORD dw;
489         struct tcp_keepalive ka = { 0 }, ks = { 0 };
490         if (timeout)
491             ka.keepalivetime = timeout * 10000;
492         else
493             ka.keepalivetime = 60 * 10000; /* 10 minutes */
494         ka.keepaliveinterval = 1000;
495         ka.onoff = 1;
496         if (WSAIoctl(sd, SIO_KEEPALIVE_VALS, &ka, sizeof(ka),
497                      &ks, sizeof(ks), &dw, NULL, NULL)) {
498             JK_GET_SOCKET_ERRNO();
499             jk_log(l, JK_LOG_ERROR,
500                    "failed setting SIO_KEEPALIVE_VALS (errno=%d)", errno);
501             jk_close_socket(sd, l);
502             JK_TRACE_EXIT(l);
503             return JK_INVALID_SOCKET;
504         }
505         if (JK_IS_DEBUG_LEVEL(l))
506             jk_log(l, JK_LOG_DEBUG,
507                    "socket SO_KEEPALIVE set to %d seconds",
508                    ka.keepalivetime / 1000);
509 #else
510         set = 1;
511         if (setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE, (SET_TYPE)&set,
512                        sizeof(set))) {
513             JK_GET_SOCKET_ERRNO();
514             jk_log(l, JK_LOG_ERROR,
515                    "failed setting SO_KEEPALIVE (errno=%d)", errno);
516             jk_close_socket(sd, l);
517             JK_TRACE_EXIT(l);
518             return JK_INVALID_SOCKET;
519         }
520         if (JK_IS_DEBUG_LEVEL(l))
521             jk_log(l, JK_LOG_DEBUG,
522                    "socket SO_KEEPALIVE set to On");
523 #endif
524     }
525
526     if (sock_buf > 0) {
527         set = sock_buf;
528         /* Set socket send buffer size */
529         if (setsockopt(sd, SOL_SOCKET, SO_SNDBUF, (SET_TYPE)&set,
530                         sizeof(set))) {
531             JK_GET_SOCKET_ERRNO();
532             jk_log(l, JK_LOG_ERROR,
533                     "failed setting SO_SNDBUF (errno=%d)", errno);
534             jk_close_socket(sd, l);
535             JK_TRACE_EXIT(l);
536             return JK_INVALID_SOCKET;
537         }
538         set = sock_buf;
539         /* Set socket receive buffer size */
540         if (setsockopt(sd, SOL_SOCKET, SO_RCVBUF, (SET_TYPE)&set,
541                                 sizeof(set))) {
542             JK_GET_SOCKET_ERRNO();
543             jk_log(l, JK_LOG_ERROR,
544                     "failed setting SO_RCVBUF (errno=%d)", errno);
545             jk_close_socket(sd, l);
546             JK_TRACE_EXIT(l);
547             return JK_INVALID_SOCKET;
548         }
549         if (JK_IS_DEBUG_LEVEL(l))
550             jk_log(l, JK_LOG_DEBUG,
551                    "socket SO_SNDBUF and SO_RCVBUF set to %d",
552                    sock_buf);
553     }
554
555     if (timeout > 0) {
556 #if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
557         int tmout = timeout * 1000;
558         setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO,
559                    (const char *) &tmout, sizeof(int));
560         setsockopt(sd, SOL_SOCKET, SO_SNDTIMEO,
561                    (const char *) &tmout, sizeof(int));
562         JK_GET_SOCKET_ERRNO();
563 #elif defined(SO_RCVTIMEO) && defined(USE_SO_RCVTIMEO) && defined(SO_SNDTIMEO) && defined(USE_SO_SNDTIMEO)
564         struct timeval tv;
565         tv.tv_sec  = timeout;
566         tv.tv_usec = 0;
567         setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO,
568                    (const void *) &tv, sizeof(tv));
569         setsockopt(sd, SOL_SOCKET, SO_SNDTIMEO,
570                    (const void *) &tv, sizeof(tv));
571 #endif
572         if (JK_IS_DEBUG_LEVEL(l))
573             jk_log(l, JK_LOG_DEBUG,
574                    "timeout %d set for socket=%d",
575                    timeout, sd);
576     }
577 #ifdef SO_NOSIGPIPE
578     /* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
579      * sending data to a dead peer. Possibly also existing and in use on other BSD
580      * systems?
581     */
582     set = 1;
583     if (setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, (const char *)&set,
584                    sizeof(int))) {
585         JK_GET_SOCKET_ERRNO();
586         jk_log(l, JK_LOG_ERROR,
587                 "failed setting SO_NOSIGPIPE (errno=%d)", errno);
588         jk_close_socket(sd, l);
589         JK_TRACE_EXIT(l);
590         return JK_INVALID_SOCKET;
591     }
592 #endif
593 #ifdef SO_LINGER
594     /* Make hard closesocket by disabling lingering */
595     li.l_linger = li.l_onoff = 0;
596     if (setsockopt(sd, SOL_SOCKET, SO_LINGER, (SET_TYPE)&li,
597                    sizeof(li))) {
598         JK_GET_SOCKET_ERRNO();
599         jk_log(l, JK_LOG_ERROR,
600                 "failed setting SO_LINGER (errno=%d)", errno);
601         jk_close_socket(sd, l);
602         JK_TRACE_EXIT(l);
603         return JK_INVALID_SOCKET;
604     }
605 #endif
606     /* Tries to connect to Tomcat (continues trying while error is EINTR) */
607     if (JK_IS_DEBUG_LEVEL(l))
608         jk_log(l, JK_LOG_DEBUG,
609                 "trying to connect socket %d to %s", sd,
610                 jk_dump_hinfo(addr, buf));
611
612 /* Need more infos for BSD 4.4 and Unix 98 defines, for now only
613 iSeries when Unix98 is required at compil time */
614 #if (_XOPEN_SOURCE >= 520) && defined(AS400)
615     ((struct sockaddr *)addr)->sa_len = sizeof(struct sockaddr_in);
616 #endif
617     ret = nb_connect(sd, (struct sockaddr *)addr, connect_timeout, l);
618 #if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
619     if (JK_IS_SOCKET_ERROR(ret)) {
620         JK_GET_SOCKET_ERRNO();
621     }
622 #endif /* WIN32 */
623
624     /* Check if we are connected */
625     if (ret) {
626         jk_log(l, JK_LOG_INFO,
627                "connect to %s failed (errno=%d)",
628                jk_dump_hinfo(addr, buf), errno);
629         jk_close_socket(sd, l);
630         sd = JK_INVALID_SOCKET;
631     }
632     else {
633         if (JK_IS_DEBUG_LEVEL(l))
634             jk_log(l, JK_LOG_DEBUG, "socket %d [%s] connected",
635                    sd, jk_dump_sinfo(sd, buf));
636     }
637     JK_TRACE_EXIT(l);
638     return sd;
639 }
640
641 /** Close the socket
642  * @param sd        socket to close
643  * @param l         logger
644  * @return          -1: some kind of error occured (!WIN32)
645  *                  SOCKET_ERROR: some kind of error occured  (WIN32)
646  *                  0: success
647  * @remark          Does not change errno
648  */
649 int jk_close_socket(jk_sock_t sd, jk_logger_t *l)
650 {
651     int rc;
652     int save_errno;
653
654     JK_TRACE_ENTER(l);
655
656     if (!IS_VALID_SOCKET(sd)) {
657         JK_TRACE_EXIT(l);
658         return -1;
659     }
660
661     save_errno = errno;
662 #if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
663     rc = closesocket(sd) ? -1 : 0;
664 #else
665     do {
666         rc = close(sd);
667     } while (JK_IS_SOCKET_ERROR(rc) && (errno == EINTR || errno == EAGAIN));
668 #endif
669     JK_TRACE_EXIT(l);
670     errno = save_errno;
671     return rc;
672 }
673
674 #ifndef MAX_SECS_TO_LINGER
675 #define MAX_SECS_TO_LINGER 2
676 #endif
677 #define MS_TO_LINGER  500
678 #define MS_TO_LINGER_LAST 2
679
680 #ifndef MAX_LINGER_BYTES
681 #define MAX_LINGER_BYTES 32768
682 #endif
683
684 #ifndef SHUT_WR
685 #ifdef SD_SEND
686 #define SHUT_WR SD_SEND
687 #else
688 #define SHUT_WR 0x01
689 #endif
690 #endif
691
692 #ifndef SHUT_RD
693 #ifdef SD_RECEIVE
694 #define SHUT_RD SD_RECEIVE
695 #else
696 #define SHUT_RD 0x00
697 #endif
698 #endif
699
700 /** Drain and close the socket
701  * @param sd        socket to close
702  * @param l         logger
703  * @return          -1: socket to close is invalid
704  *                  -1: some kind of error occured (!WIN32)
705  *                  SOCKET_ERROR: some kind of error occured  (WIN32)
706  *                  0: success
707  * @remark          Does not change errno
708  */
709 int jk_shutdown_socket(jk_sock_t sd, jk_logger_t *l)
710 {
711     char dummy[512];
712     char buf[64];
713     char *sb = NULL;
714     int rc = 0;
715     size_t rd = 0;
716     size_t rp = 0;
717     int save_errno;
718     int timeout = MS_TO_LINGER;
719     time_t start = time(NULL);
720
721     JK_TRACE_ENTER(l);
722
723     if (!IS_VALID_SOCKET(sd)) {
724         JK_TRACE_EXIT(l);
725         return -1;
726     }
727
728     save_errno = errno;
729     if (JK_IS_DEBUG_LEVEL(l)) {
730         sb = jk_dump_sinfo(sd, buf);
731         jk_log(l, JK_LOG_DEBUG, "About to shutdown socket %d [%s]",
732                sd, sb);
733     }
734     /* Shut down the socket for write, which will send a FIN
735      * to the peer.
736      */
737     if (shutdown(sd, SHUT_WR)) {
738         rc = jk_close_socket(sd, l);
739         if (JK_IS_DEBUG_LEVEL(l))
740             jk_log(l, JK_LOG_DEBUG,
741                    "Failed sending SHUT_WR for socket %d [%s]",
742                    sd, sb);
743         errno = save_errno;
744         JK_TRACE_EXIT(l);
745         return rc;
746     }
747
748     do {
749         rp = 0;
750         if (jk_is_input_event(sd, timeout, l)) {
751             /* Do a restartable read on the socket
752              * draining out all the data currently in the socket buffer.
753              */
754             do {
755 #if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
756                 rc = recv(sd, &dummy[0], sizeof(dummy), 0);
757                 if (JK_IS_SOCKET_ERROR(rc))
758                     JK_GET_SOCKET_ERRNO();
759 #else
760                 rc = read(sd, &dummy[0], sizeof(dummy));
761 #endif
762                 if (rc > 0)
763                     rp += rc;
764             } while (JK_IS_SOCKET_ERROR(rc) && (errno == EINTR || errno == EAGAIN));
765
766             if (rc < 0) {
767                 /* Read failed.
768                  * Bail out from the loop.
769                  */
770                 break;
771             }
772         }
773         else {
774             /* Error or timeout (reason is logged within jk_is_input_event)
775              * Exit the drain loop
776              */
777             break;
778         }
779         rd += rp;
780         if (rp < sizeof(dummy)) {
781             if (timeout > MS_TO_LINGER_LAST) {
782                 /* Try one last time with a short timeout 
783                 */
784                 timeout = MS_TO_LINGER_LAST;
785                 continue;
786             }
787             /* We have read less then size of buffer
788              * It's a good chance there will be no more data
789              * to read.
790              */
791             if ((rc = sononblock(sd))) {
792                 rc = jk_close_socket(sd, l);
793                 if (JK_IS_DEBUG_LEVEL(l))
794                     jk_log(l, JK_LOG_DEBUG,
795                            "error setting socket %d [%s] to nonblocking",
796                            sd, sb);
797                 errno = save_errno;
798                 JK_TRACE_EXIT(l);
799                 return rc;
800             }
801             if (JK_IS_DEBUG_LEVEL(l))
802                 jk_log(l, JK_LOG_DEBUG,
803                        "shutting down the read side of socket %d [%s]",
804                        sd, sb);
805             shutdown(sd, SHUT_RD);
806             break;
807         }
808         timeout = MS_TO_LINGER;
809     } while ((rd < MAX_LINGER_BYTES) && (difftime(time(NULL), start) < MAX_SECS_TO_LINGER));
810
811     rc = jk_close_socket(sd, l);
812     if (JK_IS_DEBUG_LEVEL(l))
813         jk_log(l, JK_LOG_DEBUG,
814                "Shutdown socket %d [%s] and read %d lingering bytes in %d sec.",
815                sd, sb, rd, (int)difftime(time(NULL), start));
816     errno = save_errno;
817     JK_TRACE_EXIT(l);
818     return rc;
819 }
820
821 /** send a message
822  * @param sd  socket to use
823  * @param b   buffer containing the data
824  * @param len length to send
825  * @param l   logger
826  * @return    negative errno: write returns a fatal -1 (!WIN32)
827  *            negative pseudo errno: send returns SOCKET_ERROR (WIN32)
828  *            JK_SOCKET_EOF: no bytes could be sent
829  *            >0: success, provided number of bytes send
830  * @remark    Always closes socket in case of error
831  * @remark    Cares about errno
832  * @bug       this fails on Unixes if len is too big for the underlying
833  *            protocol
834  */
835 int jk_tcp_socket_sendfull(jk_sock_t sd, const unsigned char *b, int len, jk_logger_t *l)
836 {
837     int sent = 0;
838     int wr;
839
840     JK_TRACE_ENTER(l);
841
842     errno = 0;
843     while (sent < len) {
844         do {
845 #if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
846             wr = send(sd, (const char*)(b + sent),
847                       len - sent, 0);
848             if (JK_IS_SOCKET_ERROR(wr))
849                 JK_GET_SOCKET_ERRNO();
850 #else
851             wr = write(sd, b + sent, len - sent);
852 #endif
853         } while (JK_IS_SOCKET_ERROR(wr) && (errno == EINTR || errno == EAGAIN));
854
855         if (JK_IS_SOCKET_ERROR(wr)) {
856             int err;
857             jk_shutdown_socket(sd, l);
858             err = (errno > 0) ? -errno : errno;
859             JK_TRACE_EXIT(l);
860             return err;
861         }
862         else if (wr == 0) {
863             jk_shutdown_socket(sd, l);
864             JK_TRACE_EXIT(l);
865             return JK_SOCKET_EOF;
866         }
867         sent += wr;
868     }
869
870     JK_TRACE_EXIT(l);
871     return sent;
872 }
873
874 /** receive a message
875  * @param sd  socket to use
876  * @param b   buffer to store the data
877  * @param len length to receive
878  * @param l   logger
879  * @return    negative errno: read returns a fatal -1 (!WIN32)
880  *            negative pseudo errno: recv returns SOCKET_ERROR (WIN32)
881  *            JK_SOCKET_EOF: no bytes could be read
882  *            >0: success, requested number of bytes received
883  * @remark    Always closes socket in case of error
884  * @remark    Cares about errno
885  */
886 int jk_tcp_socket_recvfull(jk_sock_t sd, unsigned char *b, int len, jk_logger_t *l)
887 {
888     int rdlen = 0;
889     int rd;
890
891     JK_TRACE_ENTER(l);
892
893     errno = 0;
894     while (rdlen < len) {
895         do {
896 #if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
897             rd = recv(sd, (char *)b + rdlen,
898                       len - rdlen, 0);
899             if (JK_IS_SOCKET_ERROR(rd))
900                 JK_GET_SOCKET_ERRNO();
901 #else
902             rd = read(sd, (char *)b + rdlen, len - rdlen);
903 #endif
904         } while (JK_IS_SOCKET_ERROR(rd) && errno == EINTR);
905
906         if (JK_IS_SOCKET_ERROR(rd)) {
907             int err = (errno > 0) ? -errno : errno;
908             jk_shutdown_socket(sd, l);
909             JK_TRACE_EXIT(l);
910             return (err == 0) ? JK_SOCKET_EOF : err;
911         }
912         else if (rd == 0) {
913             jk_shutdown_socket(sd, l);
914             JK_TRACE_EXIT(l);
915             return JK_SOCKET_EOF;
916         }
917         rdlen += rd;
918     }
919
920     JK_TRACE_EXIT(l);
921     return rdlen;
922 }
923
924 /**
925  * dump a sockaddr_in in A.B.C.D:P in ASCII buffer
926  *
927  */
928 char *jk_dump_hinfo(struct sockaddr_in *saddr, char *buf)
929 {
930     unsigned long laddr = (unsigned long)htonl(saddr->sin_addr.s_addr);
931     unsigned short lport = (unsigned short)htons(saddr->sin_port);
932
933     sprintf(buf, "%d.%d.%d.%d:%d",
934             (int)(laddr >> 24), (int)((laddr >> 16) & 0xff),
935             (int)((laddr >> 8) & 0xff), (int)(laddr & 0xff), (int)lport);
936
937     return buf;
938 }
939
940 char *jk_dump_sinfo(jk_sock_t sd, char *buf)
941 {
942     struct sockaddr_in rsaddr;
943     struct sockaddr_in lsaddr;
944     socklen_t          salen;
945
946     salen = sizeof(struct sockaddr);
947     if (getsockname(sd, (struct sockaddr *)&lsaddr, &salen) == 0) {
948         salen = sizeof(struct sockaddr);
949         if (getpeername(sd, (struct sockaddr *)&rsaddr, &salen) == 0) {
950             unsigned long  laddr = (unsigned  long)htonl(lsaddr.sin_addr.s_addr);
951             unsigned short lport = (unsigned short)htons(lsaddr.sin_port);
952             unsigned long  raddr = (unsigned  long)htonl(rsaddr.sin_addr.s_addr);
953             unsigned short rport = (unsigned short)htons(rsaddr.sin_port);
954             sprintf(buf, "%d.%d.%d.%d:%d -> %d.%d.%d.%d:%d",
955                     (int)(laddr >> 24), (int)((laddr >> 16) & 0xff),
956                     (int)((laddr >> 8) & 0xff), (int)(laddr & 0xff), (int)lport,
957                     (int)(raddr >> 24), (int)((raddr >> 16) & 0xff),
958                     (int)((raddr >> 8) & 0xff), (int)(raddr & 0xff), (int)rport);
959             return buf;
960         }
961     }
962     sprintf(buf, "error=%d", errno);
963     return buf;
964 }
965
966 /** Wait for input event on socket until timeout
967  * @param sd      socket to use
968  * @param timeout wait timeout in milliseconds
969  * @param l       logger
970  * @return        JK_FALSE: Timeout expired without something to read
971  *                JK_FALSE: Error during waiting
972  *                JK_TRUE: success
973  * @remark        Does not close socket in case of error
974  *                to allow for iterative waiting
975  * @remark        Cares about errno
976  */
977 #ifdef HAVE_POLL
978 int jk_is_input_event(jk_sock_t sd, int timeout, jk_logger_t *l)
979 {
980     struct pollfd fds;
981     int rc;
982     int save_errno;
983     char buf[64];
984
985     JK_TRACE_ENTER(l);
986
987     errno = 0;
988     fds.fd = sd;
989     fds.events = POLLIN;
990     fds.revents = 0;
991
992     do {
993         rc = poll(&fds, 1, timeout);
994     } while (rc < 0 && errno == EINTR);
995
996     if (rc == 0) {
997         if (JK_IS_DEBUG_LEVEL(l)) {
998             jk_log(l, JK_LOG_DEBUG,
999                    "timeout during poll on socket %d [%s] (timeout=%d)",
1000                    sd, jk_dump_sinfo(sd, buf), timeout);
1001         }
1002         /* Timeout. Set the errno to timeout */
1003         errno = ETIMEDOUT;
1004         JK_TRACE_EXIT(l);
1005         return JK_FALSE;
1006     }
1007     else if (rc < 0) {
1008         save_errno = errno;
1009         if (JK_IS_DEBUG_LEVEL(l)) {
1010             jk_log(l, JK_LOG_DEBUG,
1011                    "error during poll on socket %d [%s] (errno=%d)",
1012                    sd, jk_dump_sinfo(sd, buf), errno);
1013         }
1014         errno = save_errno;
1015         JK_TRACE_EXIT(l);
1016         return JK_FALSE;
1017     }
1018     if ((fds.revents & (POLLERR | POLLHUP))) {
1019         save_errno = fds.revents & (POLLERR | POLLHUP);
1020         if (JK_IS_DEBUG_LEVEL(l)) {
1021             jk_log(l, JK_LOG_DEBUG,
1022                    "error event during poll on socket %d [%s] (event=%d)",
1023                    sd, jk_dump_sinfo(sd, buf), save_errno);
1024         }
1025         errno = save_errno;
1026         JK_TRACE_EXIT(l);
1027         return JK_FALSE;
1028     }
1029     errno = 0;
1030     JK_TRACE_EXIT(l);
1031     return JK_TRUE;
1032 }
1033 #else
1034 int jk_is_input_event(jk_sock_t sd, int timeout, jk_logger_t *l)
1035 {
1036     fd_set rset;
1037     struct timeval tv;
1038     int rc;
1039     int save_errno;
1040     char buf[64];
1041
1042     JK_TRACE_ENTER(l);
1043
1044     errno = 0;
1045     FD_ZERO(&rset);
1046     FD_SET(sd, &rset);
1047     tv.tv_sec = timeout / 1000;
1048     tv.tv_usec = (timeout % 1000) * 1000;
1049
1050     do {
1051         rc = select((int)sd + 1, &rset, NULL, NULL, &tv);
1052     } while (rc < 0 && errno == EINTR);
1053
1054     if (rc == 0) {
1055         if (JK_IS_DEBUG_LEVEL(l)) {
1056             jk_log(l, JK_LOG_DEBUG,
1057                    "timeout during select on socket %d [%s] (timeout=%d)",
1058                    sd, jk_dump_sinfo(sd, buf), timeout);
1059         }
1060         /* Timeout. Set the errno to timeout */
1061 #if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
1062         errno = WSAETIMEDOUT - WSABASEERR;
1063 #else
1064         errno = ETIMEDOUT;
1065 #endif
1066         JK_TRACE_EXIT(l);
1067         return JK_FALSE;
1068     }
1069     else if (rc < 0) {
1070         save_errno = errno;
1071         if (JK_IS_DEBUG_LEVEL(l)) {
1072             jk_log(l, JK_LOG_DEBUG,
1073                    "error during select on socket %d [%s] (errno=%d)",
1074                    sd, jk_dump_sinfo(sd, buf), errno);
1075         }
1076         errno = save_errno;
1077         JK_TRACE_EXIT(l);
1078         return JK_FALSE;
1079     }
1080     errno = 0;
1081     JK_TRACE_EXIT(l);
1082     return JK_TRUE;
1083 }
1084 #endif
1085
1086 /** Test if a socket is still connected
1087  * @param sd   socket to use
1088  * @param l    logger
1089  * @return     JK_FALSE: failure
1090  *             JK_TRUE: success
1091  * @remark     Always closes socket in case of error
1092  * @remark     Cares about errno
1093  */
1094 #ifdef HAVE_POLL
1095 int jk_is_socket_connected(jk_sock_t sd, jk_logger_t *l)
1096 {
1097     struct pollfd fds;
1098     int rc;
1099
1100     JK_TRACE_ENTER(l);
1101
1102     errno = 0;
1103     fds.fd = sd;
1104     fds.events = POLLIN;
1105
1106     do {
1107         rc = poll(&fds, 1, 0);
1108     } while (rc < 0 && errno == EINTR);
1109
1110     if (rc == 0) {
1111         /* If we get a timeout, then we are still connected */
1112         JK_TRACE_EXIT(l);
1113         return JK_TRUE;
1114     }
1115     else if (rc == 1 && fds.revents == POLLIN) {
1116         char buf;
1117         do {
1118             rc = (int)recvfrom(sd, &buf, 1, MSG_PEEK, NULL, NULL);
1119         } while (rc < 0 && errno == EINTR);
1120         if (rc == 1) {
1121             /* There is at least one byte to read. */
1122             JK_TRACE_EXIT(l);
1123             return JK_TRUE;
1124         }
1125     }
1126     jk_shutdown_socket(sd, l);
1127
1128     JK_TRACE_EXIT(l);
1129     return JK_FALSE;
1130 }
1131
1132 #else
1133 int jk_is_socket_connected(jk_sock_t sd, jk_logger_t *l)
1134 {
1135     fd_set fd;
1136     struct timeval tv;
1137     int rc;
1138
1139     JK_TRACE_ENTER(l);
1140
1141     errno = 0;
1142     FD_ZERO(&fd);
1143     FD_SET(sd, &fd);
1144
1145     /* Initially test the socket without any blocking.
1146      */
1147     tv.tv_sec  = 0;
1148     tv.tv_usec = 0;
1149
1150     do {
1151         rc = select((int)sd + 1, &fd, NULL, NULL, &tv);
1152         JK_GET_SOCKET_ERRNO();
1153         /* Wait one microsecond on next select, if EINTR */
1154         tv.tv_sec  = 0;
1155         tv.tv_usec = 1;
1156     } while (JK_IS_SOCKET_ERROR(rc) && errno == EINTR);
1157
1158     errno = 0;
1159     if (rc == 0) {
1160         /* If we get a timeout, then we are still connected */
1161         JK_TRACE_EXIT(l);
1162         return JK_TRUE;
1163     }
1164     else if (rc == 1) {
1165 #if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__))
1166         u_long nr;
1167         rc = ioctlsocket(sd, FIONREAD, &nr);
1168         if (rc == 0) {
1169             if (WSAGetLastError() == 0)
1170                 errno = 0;
1171             else
1172                 JK_GET_SOCKET_ERRNO();
1173         }
1174 #else
1175         int nr;
1176         rc = ioctl(sd, FIONREAD, (void*)&nr);
1177 #endif
1178         if (rc == 0 && nr != 0) {
1179             JK_TRACE_EXIT(l);
1180             return JK_TRUE;
1181         }
1182         JK_GET_SOCKET_ERRNO();
1183     }
1184     jk_shutdown_socket(sd, l);
1185
1186     JK_TRACE_EXIT(l);
1187     return JK_FALSE;
1188 }
1189 #endif
1190