/* * Command line: opannotate /usr/freeswitch/lib/libapr-1.so.0.2.7 --source=/usr/src/freeswitch.trunk/libs/apr-1.2.7/ * * Interpretation of command line: * Output annotated source file with samples * Output all files * * CPU: AMD64 processors, speed 1991.58 MHz (estimated) * Counted CPU_CLK_UNHALTED events (Cycles outside of halt state) with a unit mask of 0x00 (No unit mask) count 100000 */ /* * Total samples for file : "network_io/unix/sendrecv.c" * * 29835 51.9574 */ :/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as : * applicable. : * : * Licensed 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. : */ : :#include "apr_arch_networkio.h" :#include "apr_support.h" : :#if APR_HAS_SENDFILE :/* This file is needed to allow us access to the apr_file_t internals. */ :#include "apr_arch_file_io.h" :#endif /* APR_HAS_SENDFILE */ : :/* osreldate.h is only needed on FreeBSD for sendfile detection */ :#if defined(__FreeBSD__) :#include :#endif : :apr_status_t apr_socket_send(apr_socket_t *sock, const char *buf, : apr_size_t *len) :{ : apr_ssize_t rv; : : if (sock->options & APR_INCOMPLETE_WRITE) { : sock->options &= ~APR_INCOMPLETE_WRITE; : goto do_select; : } : : do { : rv = write(sock->socketdes, buf, (*len)); : } while (rv == -1 && errno == EINTR); : : while (rv == -1 && (errno == EAGAIN || errno == EWOULDBLOCK) : && (sock->timeout > 0)) { : apr_status_t arv; :do_select: : arv = apr_wait_for_io_or_timeout(NULL, sock, 0); : if (arv != APR_SUCCESS) { : *len = 0; : return arv; : } : else { : do { : rv = write(sock->socketdes, buf, (*len)); : } while (rv == -1 && errno == EINTR); : } : } : if (rv == -1) { : *len = 0; : return errno; : } : if ((sock->timeout > 0) && (rv < *len)) { : sock->options |= APR_INCOMPLETE_WRITE; : } : (*len) = rv; : return APR_SUCCESS; :} : :apr_status_t apr_socket_recv(apr_socket_t *sock, char *buf, apr_size_t *len) :{ : apr_ssize_t rv; : apr_status_t arv; : : if (sock->options & APR_INCOMPLETE_READ) { : sock->options &= ~APR_INCOMPLETE_READ; : goto do_select; : } : : do { : rv = read(sock->socketdes, buf, (*len)); : } while (rv == -1 && errno == EINTR); : : while ((rv == -1) && (errno == EAGAIN || errno == EWOULDBLOCK) : && (sock->timeout > 0)) { :do_select: : arv = apr_wait_for_io_or_timeout(NULL, sock, 1); : if (arv != APR_SUCCESS) { : *len = 0; : return arv; : } : else { : do { : rv = read(sock->socketdes, buf, (*len)); : } while (rv == -1 && errno == EINTR); : } : } : if (rv == -1) { : (*len) = 0; : return errno; : } : if ((sock->timeout > 0) && (rv < *len)) { : sock->options |= APR_INCOMPLETE_READ; : } : (*len) = rv; : if (rv == 0) { : return APR_EOF; : } : return APR_SUCCESS; :} : :apr_status_t apr_socket_sendto(apr_socket_t *sock, apr_sockaddr_t *where, : apr_int32_t flags, const char *buf, : apr_size_t *len) 138 0.2403 :{ /* apr_socket_sendto total: 13883 24.1771 */ : apr_ssize_t rv; : : do { 1183 2.0602 : rv = sendto(sock->socketdes, buf, (*len), flags, : (const struct sockaddr*)&where->sa, : where->salen); 12266 21.3612 : } while (rv == -1 && errno == EINTR); : : while ((rv == -1) && (errno == EAGAIN || errno == EWOULDBLOCK) : && (sock->timeout > 0)) { : apr_status_t arv = apr_wait_for_io_or_timeout(NULL, sock, 0); : if (arv != APR_SUCCESS) { : *len = 0; : return arv; : } else { : do { : rv = sendto(sock->socketdes, buf, (*len), flags, : (const struct sockaddr*)&where->sa, : where->salen); : } while (rv == -1 && errno == EINTR); : } : } : if (rv == -1) { : *len = 0; : return errno; : } 39 0.0679 : *len = rv; : return APR_SUCCESS; 257 0.4476 :} : :apr_status_t apr_socket_recvfrom(apr_sockaddr_t *from, apr_socket_t *sock, : apr_int32_t flags, char *buf, : apr_size_t *len) 6329 11.0219 :{ /* apr_socket_recvfrom total: 15952 27.7803 */ : apr_ssize_t rv; : : do { 207 0.3605 : rv = recvfrom(sock->socketdes, buf, (*len), flags, : (struct sockaddr*)&from->sa, &from->salen); 8877 15.4592 : } while (rv == -1 && errno == EINTR); : 79 0.1376 : while ((rv == -1) && (errno == EAGAIN || errno == EWOULDBLOCK) : && (sock->timeout > 0)) { : apr_status_t arv = apr_wait_for_io_or_timeout(NULL, sock, 1); : if (arv != APR_SUCCESS) { : *len = 0; : return arv; : } else { : do { : rv = recvfrom(sock->socketdes, buf, (*len), flags, : (struct sockaddr*)&from->sa, &from->salen); : } while (rv == -1 && errno == EINTR); : } : } : if (rv == -1) { 33 0.0575 : (*len) = 0; : return errno; : } : : (*len) = rv; : if (rv == 0 && sock->type == SOCK_STREAM) { : return APR_EOF; : } : : return APR_SUCCESS; 427 0.7436 :} : :#ifdef HAVE_WRITEV :apr_status_t apr_socket_sendv(apr_socket_t * sock, const struct iovec *vec, : apr_int32_t nvec, apr_size_t *len) :{ : apr_ssize_t rv; : apr_size_t requested_len = 0; : apr_int32_t i; : : for (i = 0; i < nvec; i++) { : requested_len += vec[i].iov_len; : } : : if (sock->options & APR_INCOMPLETE_WRITE) { : sock->options &= ~APR_INCOMPLETE_WRITE; : goto do_select; : } : : do { : rv = writev(sock->socketdes, vec, nvec); : } while (rv == -1 && errno == EINTR); : : while ((rv == -1) && (errno == EAGAIN || errno == EWOULDBLOCK) : && (sock->timeout > 0)) { : apr_status_t arv; :do_select: : arv = apr_wait_for_io_or_timeout(NULL, sock, 0); : if (arv != APR_SUCCESS) { : *len = 0; : return arv; : } : else { : do { : rv = writev(sock->socketdes, vec, nvec); : } while (rv == -1 && errno == EINTR); : } : } : if (rv == -1) { : *len = 0; : return errno; : } : if ((sock->timeout > 0) && (rv < requested_len)) { : sock->options |= APR_INCOMPLETE_WRITE; : } : (*len) = rv; : return APR_SUCCESS; :} :#endif : :#if APR_HAS_SENDFILE : :/* TODO: Verify that all platforms handle the fd the same way, : * i.e. that they don't move the file pointer. : */ :/* TODO: what should flags be? int_32? */ : :/* Define a structure to pass in when we have a NULL header value */ :static apr_hdtr_t no_hdtr; : :#if defined(__linux__) && defined(HAVE_WRITEV) : :apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file, : apr_hdtr_t *hdtr, apr_off_t *offset, : apr_size_t *len, apr_int32_t flags) :{ : int rv, nbytes = 0, total_hdrbytes, i; : apr_status_t arv; : :#if APR_HAS_LARGE_FILES && defined(HAVE_SENDFILE64) : apr_off_t off = *offset; :#define sendfile sendfile64 : :#elif APR_HAS_LARGE_FILES && SIZEOF_OFF_T == 4 : /* 64-bit apr_off_t but no sendfile64(): fail if trying to send : * past the 2Gb limit. */ : off_t off; : : if ((apr_int64_t)*offset + *len > INT_MAX) { : return EINVAL; : } : : off = *offset; : :#else : off_t off = *offset; :#endif : : if (!hdtr) { : hdtr = &no_hdtr; : } : : /* Ignore flags for now. */ : flags = 0; : : if (hdtr->numheaders > 0) { : apr_size_t hdrbytes; : : /* cork before writing headers */ : rv = apr_socket_opt_set(sock, APR_TCP_NOPUSH, 1); : if (rv != APR_SUCCESS) { : return rv; : } : : /* Now write the headers */ : arv = apr_socket_sendv(sock, hdtr->headers, hdtr->numheaders, : &hdrbytes); : if (arv != APR_SUCCESS) { : *len = 0; : return errno; : } : nbytes += hdrbytes; : : /* If this was a partial write and we aren't doing timeouts, : * return now with the partial byte count; this is a non-blocking : * socket. : */ : total_hdrbytes = 0; : for (i = 0; i < hdtr->numheaders; i++) { : total_hdrbytes += hdtr->headers[i].iov_len; : } : if (hdrbytes < total_hdrbytes) { : *len = hdrbytes; : return apr_socket_opt_set(sock, APR_TCP_NOPUSH, 0); : } : } : : if (sock->options & APR_INCOMPLETE_WRITE) { : sock->options &= ~APR_INCOMPLETE_WRITE; : goto do_select; : } : : do { : rv = sendfile(sock->socketdes, /* socket */ : file->filedes, /* open file descriptor of the file to be sent */ : &off, /* where in the file to start */ : *len); /* number of bytes to send */ : } while (rv == -1 && errno == EINTR); : : while ((rv == -1) && (errno == EAGAIN || errno == EWOULDBLOCK) : && (sock->timeout > 0)) { :do_select: : arv = apr_wait_for_io_or_timeout(NULL, sock, 0); : if (arv != APR_SUCCESS) { : *len = 0; : return arv; : } : else { : do { : rv = sendfile(sock->socketdes, /* socket */ : file->filedes, /* open file descriptor of the file to be sent */ : &off, /* where in the file to start */ : *len); /* number of bytes to send */ : } while (rv == -1 && errno == EINTR); : } : } : : if (rv == -1) { : *len = nbytes; : rv = errno; : apr_socket_opt_set(sock, APR_TCP_NOPUSH, 0); : return rv; : } : : nbytes += rv; : : if (rv < *len) { : *len = nbytes; : arv = apr_socket_opt_set(sock, APR_TCP_NOPUSH, 0); : if (rv > 0) { : : /* If this was a partial write, return now with the : * partial byte count; this is a non-blocking socket. : */ : : if (sock->timeout > 0) { : sock->options |= APR_INCOMPLETE_WRITE; : } : return arv; : } : else { : /* If the file got smaller mid-request, eventually the offset : * becomes equal to the new file size and the kernel returns 0. : * Make this an error so the caller knows to log something and : * exit. : */ : return APR_EOF; : } : } : : /* Now write the footers */ : if (hdtr->numtrailers > 0) { : apr_size_t trbytes; : arv = apr_socket_sendv(sock, hdtr->trailers, hdtr->numtrailers, : &trbytes); : nbytes += trbytes; : if (arv != APR_SUCCESS) { : *len = nbytes; : rv = errno; : apr_socket_opt_set(sock, APR_TCP_NOPUSH, 0); : return rv; : } : } : : apr_socket_opt_set(sock, APR_TCP_NOPUSH, 0); : : (*len) = nbytes; : return rv < 0 ? errno : APR_SUCCESS; :} : :#elif defined(__FreeBSD__) || defined(__DragonFly__) : :/* Release 3.1 or greater */ :apr_status_t apr_socket_sendfile(apr_socket_t * sock, apr_file_t * file, : apr_hdtr_t * hdtr, apr_off_t * offset, : apr_size_t * len, apr_int32_t flags) :{ : off_t nbytes = 0; : int rv, i; : struct sf_hdtr headerstruct; : apr_size_t bytes_to_send = *len; : : /* Ignore flags for now. */ : flags = 0; : : if (!hdtr) { : hdtr = &no_hdtr; : } : :#if defined(__FreeBSD_version) && __FreeBSD_version < 460001 : else if (hdtr->numheaders) { : : /* On early versions of FreeBSD sendfile, the number of bytes to send : * must include the length of the headers. Don't look at the man page : * for this :( Instead, look at the the logic in : * src/sys/kern/uipc_syscalls::sendfile(). : * : * This was fixed in the middle of 4.6-STABLE : */ : for (i = 0; i < hdtr->numheaders; i++) { : bytes_to_send += hdtr->headers[i].iov_len; : } : } :#endif : : headerstruct.headers = hdtr->headers; : headerstruct.hdr_cnt = hdtr->numheaders; : headerstruct.trailers = hdtr->trailers; : headerstruct.trl_cnt = hdtr->numtrailers; : : /* FreeBSD can send the headers/footers as part of the system call */ : do { : if (sock->options & APR_INCOMPLETE_WRITE) { : apr_status_t arv; : sock->options &= ~APR_INCOMPLETE_WRITE; : arv = apr_wait_for_io_or_timeout(NULL, sock, 0); : if (arv != APR_SUCCESS) { : *len = 0; : return arv; : } : } : if (bytes_to_send) { : /* We won't dare call sendfile() if we don't have : * header or file bytes to send because bytes_to_send == 0 : * means send the whole file. : */ : rv = sendfile(file->filedes, /* file to be sent */ : sock->socketdes, /* socket */ : *offset, /* where in the file to start */ : bytes_to_send, /* number of bytes to send */ : &headerstruct, /* Headers/footers */ : &nbytes, /* number of bytes written */ : flags); /* undefined, set to 0 */ : : if (rv == -1) { : if (errno == EAGAIN) { : if (sock->timeout > 0) { : sock->options |= APR_INCOMPLETE_WRITE; : } : /* FreeBSD's sendfile can return -1/EAGAIN even if it : * sent bytes. Sanitize the result so we get normal EAGAIN : * semantics w.r.t. bytes sent. : */ : if (nbytes) { : /* normal exit for a big file & non-blocking io */ : (*len) = nbytes; : return APR_SUCCESS; : } : } : } : else { /* rv == 0 (or the kernel is broken) */ : if (nbytes == 0) { : /* Most likely the file got smaller after the stat. : * Return an error so the caller can do the Right Thing. : */ : (*len) = nbytes; : return APR_EOF; : } : } : } : else { : /* just trailer bytes... use writev() : */ : rv = writev(sock->socketdes, : hdtr->trailers, : hdtr->numtrailers); : if (rv > 0) { : nbytes = rv; : rv = 0; : } : else { : nbytes = 0; : } : } : if ((rv == -1) && (errno == EAGAIN) : && (sock->timeout > 0)) { : apr_status_t arv = apr_wait_for_io_or_timeout(NULL, sock, 0); : if (arv != APR_SUCCESS) { : *len = 0; : return arv; : } : } : } while (rv == -1 && (errno == EINTR || errno == EAGAIN)); : : (*len) = nbytes; : if (rv == -1) { : return errno; : } : return APR_SUCCESS; :} : :#elif defined(__hpux) || defined(__hpux__) : :/* HP cc in ANSI mode defines __hpux; gcc defines __hpux__ */ : :/* HP-UX Version 10.30 or greater : * (no worries, because we only get here if autoconfiguration found sendfile) : */ : :/* ssize_t sendfile(int s, int fd, off_t offset, size_t nbytes, : * const struct iovec *hdtrl, int flags); : * : * nbytes is the number of bytes to send just from the file; as with FreeBSD, : * if nbytes == 0, the rest of the file (from offset) is sent : */ : :apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file, : apr_hdtr_t *hdtr, apr_off_t *offset, : apr_size_t *len, apr_int32_t flags) :{ : int i; : apr_ssize_t rc; : apr_size_t nbytes = *len, headerlen, trailerlen; : struct iovec hdtrarray[2]; : char *headerbuf, *trailerbuf; : :#if APR_HAS_LARGE_FILES && defined(HAVE_SENDFILE64) : /* later HP-UXes have a sendfile64() */ :#define sendfile sendfile64 : apr_off_t off = *offset; : :#elif APR_HAS_LARGE_FILES && SIZEOF_OFF_T == 4 : /* HP-UX 11.00 doesn't have a sendfile64(): fail if trying to send : * past the 2Gb limit */ : off_t off; : : if ((apr_int64_t)*offset + *len > INT_MAX) { : return EINVAL; : } : off = *offset; :#else : apr_off_t off = *offset; :#endif : : if (!hdtr) { : hdtr = &no_hdtr; : } : : /* Ignore flags for now. */ : flags = 0; : : /* HP-UX can only send one header iovec and one footer iovec; try to : * only allocate storage to combine input iovecs when we really have to : */ : : switch(hdtr->numheaders) { : case 0: : hdtrarray[0].iov_base = NULL; : hdtrarray[0].iov_len = 0; : break; : case 1: : hdtrarray[0] = hdtr->headers[0]; : break; : default: : headerlen = 0; : for (i = 0; i < hdtr->numheaders; i++) { : headerlen += hdtr->headers[i].iov_len; : } : : /* XXX: BUHHH? wow, what a memory leak! */ : headerbuf = hdtrarray[0].iov_base = apr_palloc(sock->pool, headerlen); : hdtrarray[0].iov_len = headerlen; : : for (i = 0; i < hdtr->numheaders; i++) { : memcpy(headerbuf, hdtr->headers[i].iov_base, : hdtr->headers[i].iov_len); : headerbuf += hdtr->headers[i].iov_len; : } : } : : switch(hdtr->numtrailers) { : case 0: : hdtrarray[1].iov_base = NULL; : hdtrarray[1].iov_len = 0; : break; : case 1: : hdtrarray[1] = hdtr->trailers[0]; : break; : default: : trailerlen = 0; : for (i = 0; i < hdtr->numtrailers; i++) { : trailerlen += hdtr->trailers[i].iov_len; : } : : /* XXX: BUHHH? wow, what a memory leak! */ : trailerbuf = hdtrarray[1].iov_base = apr_palloc(sock->pool, trailerlen); : hdtrarray[1].iov_len = trailerlen; : : for (i = 0; i < hdtr->numtrailers; i++) { : memcpy(trailerbuf, hdtr->trailers[i].iov_base, : hdtr->trailers[i].iov_len); : trailerbuf += hdtr->trailers[i].iov_len; : } : } : : do { : if (nbytes) { /* any bytes to send from the file? */ : rc = sendfile(sock->socketdes, /* socket */ : file->filedes, /* file descriptor to send */ : off, /* where in the file to start */ : nbytes, /* number of bytes to send from file */ : hdtrarray, /* Headers/footers */ : flags); /* undefined, set to 0 */ : } : else { /* we can't call sendfile() with no bytes to send from the file */ : rc = writev(sock->socketdes, hdtrarray, 2); : } : } while (rc == -1 && errno == EINTR); : : while ((rc == -1) && (errno == EAGAIN || errno == EWOULDBLOCK) : && (sock->timeout > 0)) { : apr_status_t arv = apr_wait_for_io_or_timeout(NULL, sock, 0); : : if (arv != APR_SUCCESS) { : *len = 0; : return arv; : } : else { : do { : if (nbytes) { : rc = sendfile(sock->socketdes, /* socket */ : file->filedes, /* file descriptor to send */ : off, /* where in the file to start */ : nbytes, /* number of bytes to send from file */ : hdtrarray, /* Headers/footers */ : flags); /* undefined, set to 0 */ : } : else { /* we can't call sendfile() with no bytes to send from the file */ : rc = writev(sock->socketdes, hdtrarray, 2); : } : } while (rc == -1 && errno == EINTR); : } : } : : if (rc == -1) { : *len = 0; : return errno; : } : : /* Set len to the number of bytes written */ : *len = rc; : return APR_SUCCESS; :} :#elif defined(_AIX) || defined(__MVS__) :/* AIX and OS/390 have the same send_file() interface. : * : * subtle differences: : * AIX doesn't update the file ptr but OS/390 does : * : * availability (correctly determined by autoconf): : * : * AIX - version 4.3.2 with APAR IX85388, or version 4.3.3 and above : * OS/390 - V2R7 and above : */ :apr_status_t apr_socket_sendfile(apr_socket_t * sock, apr_file_t * file, : apr_hdtr_t * hdtr, apr_off_t * offset, : apr_size_t * len, apr_int32_t flags) :{ : int i, ptr, rv = 0; : void * hbuf=NULL, * tbuf=NULL; : apr_status_t arv; : struct sf_parms parms; : : if (!hdtr) { : hdtr = &no_hdtr; : } : : /* Ignore flags for now. */ : flags = 0; : : /* word to the wise: by default, AIX stores files sent by send_file() : * in the network buffer cache... there are supposedly scenarios : * where the most recent copy of the file won't be sent, but I can't : * recreate the potential problem, perhaps because of the way we : * use send_file()... if you suspect such a problem, try turning : * on the SF_SYNC_CACHE flag : */ : : /* AIX can also send the headers/footers as part of the system call */ : parms.header_length = 0; : if (hdtr && hdtr->numheaders) { : if (hdtr->numheaders == 1) { : parms.header_data = hdtr->headers[0].iov_base; : parms.header_length = hdtr->headers[0].iov_len; : } : else { : for (i = 0; i < hdtr->numheaders; i++) { : parms.header_length += hdtr->headers[i].iov_len; : } :#if 0 : /* Keepalives make apr_palloc a bad idea */ : hbuf = malloc(parms.header_length); :#else : /* but headers are small, so maybe we can hold on to the : * memory for the life of the socket... : */ : hbuf = apr_palloc(sock->pool, parms.header_length); :#endif : ptr = 0; : for (i = 0; i < hdtr->numheaders; i++) { : memcpy((char *)hbuf + ptr, hdtr->headers[i].iov_base, : hdtr->headers[i].iov_len); : ptr += hdtr->headers[i].iov_len; : } : parms.header_data = hbuf; : } : } : else parms.header_data = NULL; : parms.trailer_length = 0; : if (hdtr && hdtr->numtrailers) { : if (hdtr->numtrailers == 1) { : parms.trailer_data = hdtr->trailers[0].iov_base; : parms.trailer_length = hdtr->trailers[0].iov_len; : } : else { : for (i = 0; i < hdtr->numtrailers; i++) { : parms.trailer_length += hdtr->trailers[i].iov_len; : } :#if 0 : /* Keepalives make apr_palloc a bad idea */ : tbuf = malloc(parms.trailer_length); :#else : tbuf = apr_palloc(sock->pool, parms.trailer_length); :#endif : ptr = 0; : for (i = 0; i < hdtr->numtrailers; i++) { : memcpy((char *)tbuf + ptr, hdtr->trailers[i].iov_base, : hdtr->trailers[i].iov_len); : ptr += hdtr->trailers[i].iov_len; : } : parms.trailer_data = tbuf; : } : } : else { : parms.trailer_data = NULL; : } : : /* Whew! Headers and trailers set up. Now for the file data */ : : parms.file_descriptor = file->filedes; : parms.file_offset = *offset; : parms.file_bytes = *len; : : /* O.K. All set up now. Let's go to town */ : : if (sock->options & APR_INCOMPLETE_WRITE) { : sock->options &= ~APR_INCOMPLETE_WRITE; : goto do_select; : } : : do { : rv = send_file(&(sock->socketdes), /* socket */ : &(parms), /* all data */ : flags); /* flags */ : } while (rv == -1 && errno == EINTR); : : while ((rv == -1) && (errno == EAGAIN || errno == EWOULDBLOCK) : && (sock->timeout > 0)) { :do_select: : arv = apr_wait_for_io_or_timeout(NULL, sock, 0); : if (arv != APR_SUCCESS) { : *len = 0; : return arv; : } : else { : do { : rv = send_file(&(sock->socketdes), /* socket */ : &(parms), /* all data */ : flags); /* flags */ : } while (rv == -1 && errno == EINTR); : } : } : : (*len) = parms.bytes_sent; : :#if 0 : /* Clean up after ourselves */ : if(hbuf) free(hbuf); : if(tbuf) free(tbuf); :#endif : : if (rv == -1) { : return errno; : } : : if ((sock->timeout > 0) : && (parms.bytes_sent : < (parms.file_bytes + parms.header_length + parms.trailer_length))) { : sock->options |= APR_INCOMPLETE_WRITE; : } : : return APR_SUCCESS; :} :#elif defined(__osf__) && defined (__alpha) :/* Tru64's sendfile implementation doesn't work, and we need to make sure that : * we don't use it until it is fixed. If it is used as it is now, it will : * hang the machine and the only way to fix it is a reboot. : */ :#elif defined(HAVE_SENDFILEV) :/* Solaris 8's sendfilev() interface : * : * SFV_FD_SELF refers to our memory space. : * : * Required Sparc patches (or newer): : * 111297-01, 108528-09, 109472-06, 109234-03, 108995-02, 111295-01, 109025-03, : * 108991-13 : * Required x86 patches (or newer): : * 111298-01, 108529-09, 109473-06, 109235-04, 108996-02, 111296-01, 109026-04, : * 108992-13 : */ : :#if APR_HAS_LARGE_FILES && defined(HAVE_SENDFILEV64) :#define sendfilevec_t sendfilevec64_t :#define sendfilev sendfilev64 :#endif : :apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file, : apr_hdtr_t *hdtr, apr_off_t *offset, : apr_size_t *len, apr_int32_t flags) :{ : apr_status_t rv, arv; : apr_size_t nbytes; : sendfilevec_t *sfv; : int vecs, curvec, i, repeat; : apr_size_t requested_len = 0; : : if (!hdtr) { : hdtr = &no_hdtr; : } : : /* Ignore flags for now. */ : flags = 0; : : /* Calculate how much space we need. */ : vecs = hdtr->numheaders + hdtr->numtrailers + 1; : sfv = apr_palloc(sock->pool, sizeof(sendfilevec_t) * vecs); : : curvec = 0; : : /* Add the headers */ : for (i = 0; i < hdtr->numheaders; i++, curvec++) { : sfv[curvec].sfv_fd = SFV_FD_SELF; : sfv[curvec].sfv_flag = 0; : sfv[curvec].sfv_off = (apr_off_t)hdtr->headers[i].iov_base; : sfv[curvec].sfv_len = hdtr->headers[i].iov_len; : requested_len += sfv[curvec].sfv_len; : } : : /* If the len is 0, we skip the file. */ : if (*len) : { : sfv[curvec].sfv_fd = file->filedes; : sfv[curvec].sfv_flag = 0; : sfv[curvec].sfv_off = *offset; : sfv[curvec].sfv_len = *len; : requested_len += sfv[curvec].sfv_len; : : curvec++; : } : else { : vecs--; : } : : /* Add the footers */ : for (i = 0; i < hdtr->numtrailers; i++, curvec++) { : sfv[curvec].sfv_fd = SFV_FD_SELF; : sfv[curvec].sfv_flag = 0; : sfv[curvec].sfv_off = (apr_off_t)hdtr->trailers[i].iov_base; : sfv[curvec].sfv_len = hdtr->trailers[i].iov_len; : requested_len += sfv[curvec].sfv_len; : } : : /* If the last write couldn't send all the requested data, : * wait for the socket to become writable before proceeding : */ : if (sock->options & APR_INCOMPLETE_WRITE) { : sock->options &= ~APR_INCOMPLETE_WRITE; : arv = apr_wait_for_io_or_timeout(NULL, sock, 0); : if (arv != APR_SUCCESS) { : *len = 0; : return arv; : } : } : : /* Actually do the sendfilev : * : * Solaris may return -1/EAGAIN even if it sent bytes on a non-block sock. : * : * If no bytes were originally sent (nbytes == 0) and we are on a TIMEOUT : * socket (which as far as the OS is concerned is a non-blocking socket), : * we want to retry after waiting for the other side to read the data (as : * determined by poll). Once it is clear to send, we want to retry : * sending the sendfilevec_t once more. : */ : arv = 0; : do { : /* Clear out the repeat */ : repeat = 0; : : /* socket, vecs, number of vecs, bytes written */ : rv = sendfilev(sock->socketdes, sfv, vecs, &nbytes); : : if (rv == -1 && errno == EAGAIN) { : if (nbytes) { : rv = 0; : } : else if (!arv && (sock->timeout > 0)) { : apr_status_t t = apr_wait_for_io_or_timeout(NULL, sock, 0); : : if (t != APR_SUCCESS) { : *len = 0; : return t; : } : : arv = 1; : repeat = 1; : } : } : } while ((rv == -1 && errno == EINTR) || repeat); : : if (rv == -1) { : *len = 0; : return errno; : } : : /* Update how much we sent */ : *len = nbytes; : if ((sock->timeout > 0) && (*len < requested_len)) { : sock->options |= APR_INCOMPLETE_WRITE; : } : return APR_SUCCESS; :} :#else :#error APR has detected sendfile on your system, but nobody has written a :#error version of it for APR yet. To get past this, either write :#error apr_socket_sendfile or change APR_HAS_SENDFILE in apr.h to 0. :#endif /* __linux__, __FreeBSD__, __DragonFly__, __HPUX__, _AIX, __MVS__, : Tru64/OSF1 */ : :#endif /* APR_HAS_SENDFILE */ /* * Total samples for file : "locks/unix/thread_mutex.c" * * 16898 29.4277 */ :/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as : * applicable. : * : * Licensed 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. : */ : :#include "apr_arch_thread_mutex.h" :#define APR_WANT_MEMFUNC :#include "apr_want.h" : :#if APR_HAS_THREADS : :static apr_status_t thread_mutex_cleanup(void *data) :{ : apr_thread_mutex_t *mutex = data; : apr_status_t rv; : 3 0.0052 : rv = pthread_mutex_destroy(&mutex->mutex); /* thread_mutex_cleanup total: 3 0.0052 */ :#ifdef PTHREAD_SETS_ERRNO : if (rv) { : rv = errno; : } :#endif : return rv; :} : :APR_DECLARE(apr_status_t) apr_thread_mutex_create(apr_thread_mutex_t **mutex, : unsigned int flags, : apr_pool_t *pool) 2 0.0035 :{ /* apr_thread_mutex_create total: 6 0.0104 */ : apr_thread_mutex_t *new_mutex; : apr_status_t rv; : :#ifndef HAVE_PTHREAD_MUTEX_RECURSIVE : if (flags & APR_THREAD_MUTEX_NESTED) { : return APR_ENOTIMPL; : } :#endif : : new_mutex = apr_pcalloc(pool, sizeof(apr_thread_mutex_t)); : new_mutex->pool = pool; : :#ifdef HAVE_PTHREAD_MUTEX_RECURSIVE : if (flags & APR_THREAD_MUTEX_NESTED) { : pthread_mutexattr_t mattr; : : rv = pthread_mutexattr_init(&mattr); : if (rv) return rv; : 2 0.0035 : rv = pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE); : if (rv) { : pthread_mutexattr_destroy(&mattr); : return rv; : } : : rv = pthread_mutex_init(&new_mutex->mutex, &mattr); : : pthread_mutexattr_destroy(&mattr); : } else :#endif : rv = pthread_mutex_init(&new_mutex->mutex, NULL); : 2 0.0035 : if (rv) { :#ifdef PTHREAD_SETS_ERRNO : rv = errno; :#endif : return rv; : } : : apr_pool_cleanup_register(new_mutex->pool, : new_mutex, thread_mutex_cleanup, : apr_pool_cleanup_null); : : *mutex = new_mutex; : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_thread_mutex_lock(apr_thread_mutex_t *mutex) :{ : apr_status_t rv; : 4567 7.9534 : rv = pthread_mutex_lock(&mutex->mutex); /* apr_thread_mutex_lock total: 4567 7.9534 */ :#ifdef PTHREAD_SETS_ERRNO : if (rv) { : rv = errno; : } :#endif : : return rv; :} : :APR_DECLARE(apr_status_t) apr_thread_mutex_trylock(apr_thread_mutex_t *mutex) :{ /* apr_thread_mutex_trylock total: 1 0.0017 */ : apr_status_t rv; : 1 0.0017 : rv = pthread_mutex_trylock(&mutex->mutex); : if (rv) { :#ifdef PTHREAD_SETS_ERRNO : rv = errno; :#endif : return (rv == EBUSY) ? APR_EBUSY : rv; : } : : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_thread_mutex_unlock(apr_thread_mutex_t *mutex) :{ : apr_status_t status; : 12321 21.4569 : status = pthread_mutex_unlock(&mutex->mutex); /* apr_thread_mutex_unlock total: 12321 21.4569 */ :#ifdef PTHREAD_SETS_ERRNO : if (status) { : status = errno; : } :#endif : : return status; :} : :APR_DECLARE(apr_status_t) apr_thread_mutex_destroy(apr_thread_mutex_t *mutex) :{ : return apr_pool_cleanup_run(mutex->pool, mutex, thread_mutex_cleanup); :} : :APR_POOL_IMPLEMENT_ACCESSOR(thread_mutex) : :#endif /* APR_HAS_THREADS */ /* * Total samples for file : "time/unix/time.c" * * 8299 14.4526 */ :/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as : * applicable. : * : * Licensed 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. : */ : :#include "apr_portable.h" :#include "apr_time.h" :#include "apr_lib.h" :#include "apr_private.h" :#include "apr_strings.h" : :/* private APR headers */ :#include "apr_arch_internal_time.h" : :/* System Headers required for time library */ :#if APR_HAVE_SYS_TIME_H :#include :#endif :#if APR_HAVE_UNISTD_H :#include :#endif :#ifdef HAVE_TIME_H :#include :#endif :/* End System Headers */ : :#if !defined(HAVE_STRUCT_TM_TM_GMTOFF) && !defined(HAVE_STRUCT_TM___TM_GMTOFF) :static apr_int32_t server_gmt_offset; :#define NO_GMTOFF_IN_STRUCT_TM :#endif : :static apr_int32_t get_offset(struct tm *tm) :{ :#if defined(HAVE_STRUCT_TM_TM_GMTOFF) : return tm->tm_gmtoff; :#elif defined(HAVE_STRUCT_TM___TM_GMTOFF) : return tm->__tm_gmtoff; :#else :#ifdef NETWARE : /* Need to adjust the global variable each time otherwise : the web server would have to be restarted when daylight : savings changes. : */ : if (daylightOnOff) { : return server_gmt_offset + daylightOffset; : } :#else : if (tm->tm_isdst) : return server_gmt_offset + 3600; :#endif : return server_gmt_offset; :#endif :} : :APR_DECLARE(apr_status_t) apr_time_ansi_put(apr_time_t *result, : time_t input) :{ : *result = (apr_time_t)input * APR_USEC_PER_SEC; : return APR_SUCCESS; :} : :/* NB NB NB NB This returns GMT!!!!!!!!!! */ :APR_DECLARE(apr_time_t) apr_time_now(void) 1648 2.8700 :{ /* apr_time_now total: 4300 7.4884 */ : struct timeval tv; 2652 4.6184 : gettimeofday(&tv, NULL); : return tv.tv_sec * APR_USEC_PER_SEC + tv.tv_usec; :} : :static void explode_time(apr_time_exp_t *xt, apr_time_t t, : apr_int32_t offset, int use_localtime) 5 0.0087 :{ : struct tm tm; 1 0.0017 : time_t tt = (t / APR_USEC_PER_SEC) + offset; /* explode_time total: 12 0.0209 */ : xt->tm_usec = t % APR_USEC_PER_SEC; : :#if APR_HAS_THREADS && defined (_POSIX_THREAD_SAFE_FUNCTIONS) : if (use_localtime) : localtime_r(&tt, &tm); : else : gmtime_r(&tt, &tm); :#else : if (use_localtime) : tm = *localtime(&tt); : else : tm = *gmtime(&tt); :#endif : 3 0.0052 : xt->tm_sec = tm.tm_sec; : xt->tm_min = tm.tm_min; : xt->tm_hour = tm.tm_hour; : xt->tm_mday = tm.tm_mday; : xt->tm_mon = tm.tm_mon; : xt->tm_year = tm.tm_year; 1 0.0017 : xt->tm_wday = tm.tm_wday; : xt->tm_yday = tm.tm_yday; : xt->tm_isdst = tm.tm_isdst; 2 0.0035 : xt->tm_gmtoff = get_offset(&tm); :} : :APR_DECLARE(apr_status_t) apr_time_exp_tz(apr_time_exp_t *result, : apr_time_t input, apr_int32_t offs) :{ : explode_time(result, input, offs, 0); : result->tm_gmtoff = offs; : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_time_exp_gmt(apr_time_exp_t *result, : apr_time_t input) :{ 2 0.0035 : return apr_time_exp_tz(result, input, 0); /* apr_time_exp_gmt total: 2 0.0035 */ :} : :APR_DECLARE(apr_status_t) apr_time_exp_lt(apr_time_exp_t *result, : apr_time_t input) 5 0.0087 :{ /* apr_time_exp_lt total: 12 0.0209 */ :#if defined(__EMX__) : /* EMX gcc (OS/2) has a timezone global we can use */ : return apr_time_exp_tz(result, input, -timezone); :#else 6 0.0104 : explode_time(result, input, 0, 1); : return APR_SUCCESS; :#endif /* __EMX__ */ 1 0.0017 :} : :APR_DECLARE(apr_status_t) apr_time_exp_get(apr_time_t *t, apr_time_exp_t *xt) :{ : apr_time_t year = xt->tm_year; : apr_time_t days; : static const int dayoffset[12] = : {306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275}; : : /* shift new year to 1st March in order to make leap year calc easy */ : : if (xt->tm_mon < 2) : year--; : : /* Find number of days since 1st March 1900 (in the Gregorian calendar). */ : : days = year * 365 + year / 4 - year / 100 + (year / 100 + 3) / 4; : days += dayoffset[xt->tm_mon] + xt->tm_mday - 1; : days -= 25508; /* 1 jan 1970 is 25508 days since 1 mar 1900 */ : days = ((days * 24 + xt->tm_hour) * 60 + xt->tm_min) * 60 + xt->tm_sec; : : if (days < 0) { : return APR_EBADDATE; : } : *t = days * APR_USEC_PER_SEC + xt->tm_usec; : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_time_exp_gmt_get(apr_time_t *t, : apr_time_exp_t *xt) :{ : apr_status_t status = apr_time_exp_get(t, xt); : if (status == APR_SUCCESS) : *t -= (apr_time_t) xt->tm_gmtoff * APR_USEC_PER_SEC; : return status; :} : :APR_DECLARE(apr_status_t) apr_os_imp_time_get(apr_os_imp_time_t **ostime, : apr_time_t *aprtime) :{ : (*ostime)->tv_usec = *aprtime % APR_USEC_PER_SEC; : (*ostime)->tv_sec = *aprtime / APR_USEC_PER_SEC; : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_os_exp_time_get(apr_os_exp_time_t **ostime, : apr_time_exp_t *aprtime) :{ : (*ostime)->tm_sec = aprtime->tm_sec; : (*ostime)->tm_min = aprtime->tm_min; : (*ostime)->tm_hour = aprtime->tm_hour; : (*ostime)->tm_mday = aprtime->tm_mday; : (*ostime)->tm_mon = aprtime->tm_mon; : (*ostime)->tm_year = aprtime->tm_year; : (*ostime)->tm_wday = aprtime->tm_wday; : (*ostime)->tm_yday = aprtime->tm_yday; : (*ostime)->tm_isdst = aprtime->tm_isdst; : :#if defined(HAVE_STRUCT_TM_TM_GMTOFF) : (*ostime)->tm_gmtoff = aprtime->tm_gmtoff; :#elif defined(HAVE_STRUCT_TM___TM_GMTOFF) : (*ostime)->__tm_gmtoff = aprtime->tm_gmtoff; :#endif : : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_os_imp_time_put(apr_time_t *aprtime, : apr_os_imp_time_t **ostime, : apr_pool_t *cont) :{ : *aprtime = (*ostime)->tv_sec * APR_USEC_PER_SEC + (*ostime)->tv_usec; : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_os_exp_time_put(apr_time_exp_t *aprtime, : apr_os_exp_time_t **ostime, : apr_pool_t *cont) :{ : aprtime->tm_sec = (*ostime)->tm_sec; : aprtime->tm_min = (*ostime)->tm_min; : aprtime->tm_hour = (*ostime)->tm_hour; : aprtime->tm_mday = (*ostime)->tm_mday; : aprtime->tm_mon = (*ostime)->tm_mon; : aprtime->tm_year = (*ostime)->tm_year; : aprtime->tm_wday = (*ostime)->tm_wday; : aprtime->tm_yday = (*ostime)->tm_yday; : aprtime->tm_isdst = (*ostime)->tm_isdst; : :#if defined(HAVE_STRUCT_TM_TM_GMTOFF) : aprtime->tm_gmtoff = (*ostime)->tm_gmtoff; :#elif defined(HAVE_STRUCT_TM___TM_GMTOFF) : aprtime->tm_gmtoff = (*ostime)->__tm_gmtoff; :#endif : : return APR_SUCCESS; :} : :APR_DECLARE(void) apr_sleep(apr_interval_time_t t) :{ :#ifdef OS2 : DosSleep(t/1000); :#elif defined(BEOS) : snooze(t); :#elif defined(NETWARE) : delay(t/1000); :#else : struct timeval tv; 3335 5.8079 : tv.tv_usec = t % APR_USEC_PER_SEC; /* apr_sleep total: 3973 6.9190 */ 36 0.0627 : tv.tv_sec = t / APR_USEC_PER_SEC; 8 0.0139 : select(0, NULL, NULL, NULL, &tv); :#endif 594 1.0344 :} : :#ifdef OS2 :APR_DECLARE(apr_status_t) apr_os2_time_to_apr_time(apr_time_t *result, : FDATE os2date, : FTIME os2time) :{ : struct tm tmpdate; : : memset(&tmpdate, 0, sizeof(tmpdate)); : tmpdate.tm_hour = os2time.hours; : tmpdate.tm_min = os2time.minutes; : tmpdate.tm_sec = os2time.twosecs * 2; : : tmpdate.tm_mday = os2date.day; : tmpdate.tm_mon = os2date.month - 1; : tmpdate.tm_year = os2date.year + 80; : tmpdate.tm_isdst = -1; : : *result = mktime(&tmpdate) * APR_USEC_PER_SEC; : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_apr_time_to_os2_time(FDATE *os2date, : FTIME *os2time, : apr_time_t aprtime) :{ : time_t ansitime = aprtime / APR_USEC_PER_SEC; : struct tm *lt; : lt = localtime(&ansitime); : os2time->hours = lt->tm_hour; : os2time->minutes = lt->tm_min; : os2time->twosecs = lt->tm_sec / 2; : : os2date->day = lt->tm_mday; : os2date->month = lt->tm_mon + 1; : os2date->year = lt->tm_year - 80; : return APR_SUCCESS; :} :#endif : :#ifdef NETWARE :APR_DECLARE(void) apr_netware_setup_time(void) :{ : tzset(); : server_gmt_offset = -TZONE; :} :#else :APR_DECLARE(void) apr_unix_setup_time(void) :{ :#ifdef NO_GMTOFF_IN_STRUCT_TM : /* Precompute the offset from GMT on systems where it's not : in struct tm. : : Note: This offset is normalized to be independent of daylight : savings time; if the calculation happens to be done in a : time/place where a daylight savings adjustment is in effect, : the returned offset has the same value that it would have : in the same location if daylight savings were not in effect. : The reason for this is that the returned offset can be : applied to a past or future timestamp in explode_time(), : so the DST adjustment obtained from the current time won't : necessarily be applicable. : : mktime() is the inverse of localtime(); so, presumably, : passing in a struct tm made by gmtime() let's us calculate : the true GMT offset. However, there's a catch: if daylight : savings is in effect, gmtime()will set the tm_isdst field : and confuse mktime() into returning a time that's offset : by one hour. In that case, we must adjust the calculated GMT : offset. : : */ : : struct timeval now; : time_t t1, t2; : struct tm t; : : gettimeofday(&now, NULL); : t1 = now.tv_sec; : t2 = 0; : :#if APR_HAS_THREADS && defined(_POSIX_THREAD_SAFE_FUNCTIONS) : gmtime_r(&t1, &t); :#else : t = *gmtime(&t1); :#endif : t.tm_isdst = 0; /* we know this GMT time isn't daylight-savings */ : t2 = mktime(&t); : server_gmt_offset = (apr_int32_t) difftime(t1, t2); :#endif /* NO_GMTOFF_IN_STRUCT_TM */ :} : :#endif : :/* A noop on all known Unix implementations */ :APR_DECLARE(void) apr_time_clock_hires(apr_pool_t *p) :{ : return; :} : : /* * Total samples for file : "strings/apr_snprintf.c" * * 452 0.7872 */ :/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as : * applicable. : * : * Licensed 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. : */ : :#include "apr.h" :#include "apr_private.h" : :#include "apr_lib.h" :#include "apr_strings.h" :#include "apr_network_io.h" :#include "apr_portable.h" :#include :#if APR_HAVE_CTYPE_H :#include :#endif :#if APR_HAVE_NETINET_IN_H :#include :#endif :#if APR_HAVE_SYS_SOCKET_H :#include :#endif :#if APR_HAVE_ARPA_INET_H :#include :#endif :#if APR_HAVE_LIMITS_H :#include :#endif :#if APR_HAVE_STRING_H :#include :#endif : :typedef enum { : NO = 0, YES = 1 :} boolean_e; : :#ifndef FALSE :#define FALSE 0 :#endif :#ifndef TRUE :#define TRUE 1 :#endif :#define NUL '\0' :#define WIDE_INT long : :typedef WIDE_INT wide_int; :typedef unsigned WIDE_INT u_wide_int; :typedef apr_int64_t widest_int; :#ifdef __TANDEM :/* Although Tandem supports "long long" there is no unsigned variant. */ :typedef unsigned long u_widest_int; :#else :typedef apr_uint64_t u_widest_int; :#endif :typedef int bool_int; : :#define S_NULL "(null)" :#define S_NULL_LEN 6 : :#define FLOAT_DIGITS 6 :#define EXPONENT_LENGTH 10 : :/* : * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions : * : * NOTICE: this is a magic number; do not decrease it : */ :#define NUM_BUF_SIZE 512 : :/* : * cvt.c - IEEE floating point formatting routines for FreeBSD : * from GNU libc-4.6.27. Modified to be thread safe. : */ : :/* : * apr_ecvt converts to decimal : * the number of digits is specified by ndigit : * decpt is set to the position of the decimal point : * sign is set to 0 for positive, 1 for negative : */ : :#define NDIG 80 : :/* buf must have at least NDIG bytes */ :static char *apr_cvt(double arg, int ndigits, int *decpt, int *sign, : int eflag, char *buf) :{ : register int r2; : double fi, fj; : register char *p, *p1; : : if (ndigits >= NDIG - 1) : ndigits = NDIG - 2; : r2 = 0; : *sign = 0; : p = &buf[0]; : if (arg < 0) { : *sign = 1; : arg = -arg; : } : arg = modf(arg, &fi); : p1 = &buf[NDIG]; : /* : * Do integer part : */ : if (fi != 0) { : p1 = &buf[NDIG]; : while (p1 > &buf[0] && fi != 0) { : fj = modf(fi / 10, &fi); : *--p1 = (int) ((fj + .03) * 10) + '0'; : r2++; : } : while (p1 < &buf[NDIG]) : *p++ = *p1++; : } : else if (arg > 0) { : while ((fj = arg * 10) < 1) { : arg = fj; : r2--; : } : } : p1 = &buf[ndigits]; : if (eflag == 0) : p1 += r2; : if (p1 < &buf[0]) { : *decpt = -ndigits; : buf[0] = '\0'; : return (buf); : } : *decpt = r2; : while (p <= p1 && p < &buf[NDIG]) { : arg *= 10; : arg = modf(arg, &fj); : *p++ = (int) fj + '0'; : } : if (p1 >= &buf[NDIG]) { : buf[NDIG - 1] = '\0'; : return (buf); : } : p = p1; : *p1 += 5; : while (*p1 > '9') { : *p1 = '0'; : if (p1 > buf) : ++ * --p1; : else { : *p1 = '1'; : (*decpt)++; : if (eflag == 0) { : if (p > buf) : *p = '0'; : p++; : } : } : } : *p = '\0'; : return (buf); :} : :static char *apr_ecvt(double arg, int ndigits, int *decpt, int *sign, char *buf) :{ : return (apr_cvt(arg, ndigits, decpt, sign, 1, buf)); :} : :static char *apr_fcvt(double arg, int ndigits, int *decpt, int *sign, char *buf) :{ : return (apr_cvt(arg, ndigits, decpt, sign, 0, buf)); :} : :/* : * apr_gcvt - Floating output conversion to : * minimal length string : */ : :static char *apr_gcvt(double number, int ndigit, char *buf, boolean_e altform) :{ : int sign, decpt; : register char *p1, *p2; : register int i; : char buf1[NDIG]; : : p1 = apr_ecvt(number, ndigit, &decpt, &sign, buf1); : p2 = buf; : if (sign) : *p2++ = '-'; : for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--) : ndigit--; : if ((decpt >= 0 && decpt - ndigit > 4) : || (decpt < 0 && decpt < -3)) { /* use E-style */ : decpt--; : *p2++ = *p1++; : *p2++ = '.'; : for (i = 1; i < ndigit; i++) : *p2++ = *p1++; : *p2++ = 'e'; : if (decpt < 0) { : decpt = -decpt; : *p2++ = '-'; : } : else : *p2++ = '+'; : if (decpt / 100 > 0) : *p2++ = decpt / 100 + '0'; : if (decpt / 10 > 0) : *p2++ = (decpt % 100) / 10 + '0'; : *p2++ = decpt % 10 + '0'; : } : else { : if (decpt <= 0) { : if (*p1 != '0') : *p2++ = '.'; : while (decpt < 0) { : decpt++; : *p2++ = '0'; : } : } : for (i = 1; i <= ndigit; i++) { : *p2++ = *p1++; : if (i == decpt) : *p2++ = '.'; : } : if (ndigit < decpt) { : while (ndigit++ < decpt) : *p2++ = '0'; : *p2++ = '.'; : } : } : if (p2[-1] == '.' && !altform) : p2--; : *p2 = '\0'; : return (buf); :} : :/* : * The INS_CHAR macro inserts a character in the buffer and writes : * the buffer back to disk if necessary : * It uses the char pointers sp and bep: : * sp points to the next available character in the buffer : * bep points to the end-of-buffer+1 : * While using this macro, note that the nextb pointer is NOT updated. : * : * NOTE: Evaluation of the c argument should not have any side-effects : */ :#define INS_CHAR(c, sp, bep, cc) \ :{ \ : if (sp) { \ : if (sp >= bep) { \ : vbuff->curpos = sp; \ : if (flush_func(vbuff)) \ : return -1; \ : sp = vbuff->curpos; \ : bep = vbuff->endpos; \ : } \ : *sp++ = (c); \ : } \ : cc++; \ :} : :#define NUM(c) (c - '0') : :#define STR_TO_DEC(str, num) \ : num = NUM(*str++); \ : while (apr_isdigit(*str)) \ : { \ : num *= 10 ; \ : num += NUM(*str++); \ : } : :/* : * This macro does zero padding so that the precision : * requirement is satisfied. The padding is done by : * adding '0's to the left of the string that is going : * to be printed. We don't allow precision to be large : * enough that we continue past the start of s. : * : * NOTE: this makes use of the magic info that s is : * always based on num_buf with a size of NUM_BUF_SIZE. : */ :#define FIX_PRECISION(adjust, precision, s, s_len) \ : if (adjust) { \ : apr_size_t p = (precision + 1 < NUM_BUF_SIZE) \ : ? precision : NUM_BUF_SIZE - 1; \ : while (s_len < p) \ : { \ : *--s = '0'; \ : s_len++; \ : } \ : } : :/* : * Macro that does padding. The padding is done by printing : * the character ch. : */ :#define PAD(width, len, ch) \ :do \ :{ \ : INS_CHAR(ch, sp, bep, cc); \ : width--; \ :} \ :while (width > len) : :/* : * Prefix the character ch to the string str : * Increase length : * Set the has_prefix flag : */ :#define PREFIX(str, length, ch) \ : *--str = ch; \ : length++; \ : has_prefix=YES; : : :/* : * Convert num to its decimal format. : * Return value: : * - a pointer to a string containing the number (no sign) : * - len contains the length of the string : * - is_negative is set to TRUE or FALSE depending on the sign : * of the number (always set to FALSE if is_unsigned is TRUE) : * : * The caller provides a buffer for the string: that is the buf_end argument : * which is a pointer to the END of the buffer + 1 (i.e. if the buffer : * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) : * : * Note: we have 2 versions. One is used when we need to use quads : * (conv_10_quad), the other when we don't (conv_10). We're assuming the : * latter is faster. : */ :static char *conv_10(register wide_int num, register bool_int is_unsigned, : register bool_int *is_negative, char *buf_end, : register apr_size_t *len) 2 0.0035 :{ : register char *p = buf_end; : register u_wide_int magnitude; : 1 0.0017 : if (is_unsigned) { /* conv_10 total: 15 0.0261 */ : magnitude = (u_wide_int) num; : *is_negative = FALSE; : } : else { : *is_negative = (num < 0); : : /* : * On a 2's complement machine, negating the most negative integer : * results in a number that cannot be represented as a signed integer. : * Here is what we do to obtain the number's magnitude: : * a. add 1 to the number : * b. negate it (becomes positive) : * c. convert it to unsigned : * d. add 1 : */ : if (*is_negative) { : wide_int t = num + 1; : 4 0.0070 : magnitude = ((u_wide_int) -t) + 1; : } : else 1 0.0017 : magnitude = (u_wide_int) num; : } : : /* : * We use a do-while loop so that we write at least 1 digit : */ : do { 1 0.0017 : register u_wide_int new_magnitude = magnitude / 10; : 5 0.0087 : *--p = (char) (magnitude - new_magnitude * 10 + '0'); : magnitude = new_magnitude; : } : while (magnitude); : 1 0.0017 : *len = buf_end - p; : return (p); :} : :static char *conv_10_quad(widest_int num, register bool_int is_unsigned, : register bool_int *is_negative, char *buf_end, : register apr_size_t *len) :{ : register char *p = buf_end; : u_widest_int magnitude; : : /* : * We see if we can use the faster non-quad version by checking the : * number against the largest long value it can be. If <=, we : * punt to the quicker version. : */ : if ((num <= ULONG_MAX && is_unsigned) : || (num <= LONG_MAX && num >= LONG_MIN && !is_unsigned)) : return(conv_10( (wide_int)num, is_unsigned, is_negative, : buf_end, len)); : : if (is_unsigned) { : magnitude = (u_widest_int) num; : *is_negative = FALSE; : } : else { : *is_negative = (num < 0); : : /* : * On a 2's complement machine, negating the most negative integer : * results in a number that cannot be represented as a signed integer. : * Here is what we do to obtain the number's magnitude: : * a. add 1 to the number : * b. negate it (becomes positive) : * c. convert it to unsigned : * d. add 1 : */ : if (*is_negative) { : widest_int t = num + 1; : : magnitude = ((u_widest_int) -t) + 1; : } : else : magnitude = (u_widest_int) num; : } : : /* : * We use a do-while loop so that we write at least 1 digit : */ : do { : u_widest_int new_magnitude = magnitude / 10; : : *--p = (char) (magnitude - new_magnitude * 10 + '0'); : magnitude = new_magnitude; : } : while (magnitude); : : *len = buf_end - p; : return (p); :} : : : :static char *conv_in_addr(struct in_addr *ia, char *buf_end, apr_size_t *len) :{ : unsigned addr = ntohl(ia->s_addr); : char *p = buf_end; : bool_int is_negative; : apr_size_t sub_len; : : p = conv_10((addr & 0x000000FF) , TRUE, &is_negative, p, &sub_len); : *--p = '.'; : p = conv_10((addr & 0x0000FF00) >> 8, TRUE, &is_negative, p, &sub_len); : *--p = '.'; : p = conv_10((addr & 0x00FF0000) >> 16, TRUE, &is_negative, p, &sub_len); : *--p = '.'; : p = conv_10((addr & 0xFF000000) >> 24, TRUE, &is_negative, p, &sub_len); : : *len = buf_end - p; : return (p); :} : : : :static char *conv_apr_sockaddr(apr_sockaddr_t *sa, char *buf_end, apr_size_t *len) :{ : char *p = buf_end; : bool_int is_negative; : apr_size_t sub_len; : char *ipaddr_str; : : p = conv_10(sa->port, TRUE, &is_negative, p, &sub_len); : *--p = ':'; : apr_sockaddr_ip_get(&ipaddr_str, sa); : sub_len = strlen(ipaddr_str); :#if APR_HAVE_IPV6 : if (sa->family == APR_INET6 && : !IN6_IS_ADDR_V4MAPPED(&sa->sa.sin6.sin6_addr)) { : *(p - 1) = ']'; : p -= sub_len + 2; : *p = '['; : memcpy(p + 1, ipaddr_str, sub_len); : } : else :#endif : { : p -= sub_len; : memcpy(p, ipaddr_str, sub_len); : } : : *len = buf_end - p; : return (p); :} : : : :#if APR_HAS_THREADS :static char *conv_os_thread_t(apr_os_thread_t *tid, char *buf_end, apr_size_t *len) :{ : union { : apr_os_thread_t tid; : apr_uint64_t alignme; : } u; : int is_negative; : : u.tid = *tid; : switch(sizeof(u.tid)) { : case sizeof(apr_int32_t): : return conv_10(*(apr_uint32_t *)&u.tid, TRUE, &is_negative, buf_end, len); : case sizeof(apr_int64_t): : return conv_10_quad(*(apr_uint64_t *)&u.tid, TRUE, &is_negative, buf_end, len); : default: : /* not implemented; stick 0 in the buffer */ : return conv_10(0, TRUE, &is_negative, buf_end, len); : } :} :#endif : : : :/* : * Convert a floating point number to a string formats 'f', 'e' or 'E'. : * The result is placed in buf, and len denotes the length of the string : * The sign is returned in the is_negative argument (and is not placed : * in buf). : */ :static char *conv_fp(register char format, register double num, : boolean_e add_dp, int precision, bool_int *is_negative, : char *buf, apr_size_t *len) :{ : register char *s = buf; : register char *p; : int decimal_point; : char buf1[NDIG]; : : if (format == 'f') : p = apr_fcvt(num, precision, &decimal_point, is_negative, buf1); : else /* either e or E format */ : p = apr_ecvt(num, precision + 1, &decimal_point, is_negative, buf1); : : /* : * Check for Infinity and NaN : */ : if (apr_isalpha(*p)) { : *len = strlen(p); : memcpy(buf, p, *len + 1); : *is_negative = FALSE; : return (buf); : } : : if (format == 'f') { : if (decimal_point <= 0) { : *s++ = '0'; : if (precision > 0) { : *s++ = '.'; : while (decimal_point++ < 0) : *s++ = '0'; : } : else if (add_dp) : *s++ = '.'; : } : else { : while (decimal_point-- > 0) : *s++ = *p++; : if (precision > 0 || add_dp) : *s++ = '.'; : } : } : else { : *s++ = *p++; : if (precision > 0 || add_dp) : *s++ = '.'; : } : : /* : * copy the rest of p, the NUL is NOT copied : */ : while (*p) : *s++ = *p++; : : if (format != 'f') { : char temp[EXPONENT_LENGTH]; /* for exponent conversion */ : apr_size_t t_len; : bool_int exponent_is_negative; : : *s++ = format; /* either e or E */ : decimal_point--; : if (decimal_point != 0) { : p = conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative, : &temp[EXPONENT_LENGTH], &t_len); : *s++ = exponent_is_negative ? '-' : '+'; : : /* : * Make sure the exponent has at least 2 digits : */ : if (t_len == 1) : *s++ = '0'; : while (t_len--) : *s++ = *p++; : } : else { : *s++ = '+'; : *s++ = '0'; : *s++ = '0'; : } : } : : *len = s - buf; : return (buf); :} : : :/* : * Convert num to a base X number where X is a power of 2. nbits determines X. : * For example, if nbits is 3, we do base 8 conversion : * Return value: : * a pointer to a string containing the number : * : * The caller provides a buffer for the string: that is the buf_end argument : * which is a pointer to the END of the buffer + 1 (i.e. if the buffer : * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) : * : * As with conv_10, we have a faster version which is used when : * the number isn't quad size. : */ :static char *conv_p2(register u_wide_int num, register int nbits, : char format, char *buf_end, register apr_size_t *len) :{ : register int mask = (1 << nbits) - 1; : register char *p = buf_end; : static const char low_digits[] = "0123456789abcdef"; : static const char upper_digits[] = "0123456789ABCDEF"; : register const char *digits = (format == 'X') ? upper_digits : low_digits; : : do { : *--p = digits[num & mask]; : num >>= nbits; : } : while (num); : : *len = buf_end - p; : return (p); :} : :static char *conv_p2_quad(u_widest_int num, register int nbits, : char format, char *buf_end, register apr_size_t *len) :{ : register int mask = (1 << nbits) - 1; : register char *p = buf_end; : static const char low_digits[] = "0123456789abcdef"; : static const char upper_digits[] = "0123456789ABCDEF"; : register const char *digits = (format == 'X') ? upper_digits : low_digits; : : if (num <= ULONG_MAX) : return(conv_p2((u_wide_int)num, nbits, format, buf_end, len)); : : do { : *--p = digits[num & mask]; : num >>= nbits; : } : while (num); : : *len = buf_end - p; : return (p); :} : :#if APR_HAS_THREADS :static char *conv_os_thread_t_hex(apr_os_thread_t *tid, char *buf_end, apr_size_t *len) :{ : union { : apr_os_thread_t tid; : apr_uint64_t alignme; : } u; : int is_negative; : : u.tid = *tid; : switch(sizeof(u.tid)) { : case sizeof(apr_int32_t): : return conv_p2(*(apr_uint32_t *)&u.tid, 4, 'x', buf_end, len); : case sizeof(apr_int64_t): : return conv_p2_quad(*(apr_uint64_t *)&u.tid, 4, 'x', buf_end, len); : default: : /* not implemented; stick 0 in the buffer */ : return conv_10(0, TRUE, &is_negative, buf_end, len); : } :} :#endif : :/* : * Do format conversion placing the output in buffer : */ :APR_DECLARE(int) apr_vformatter(int (*flush_func)(apr_vformatter_buff_t *), : apr_vformatter_buff_t *vbuff, const char *fmt, va_list ap) 14 0.0244 :{ /* apr_vformatter total: 364 0.6339 */ : register char *sp; : register char *bep; : register int cc = 0; : register apr_size_t i; : : register char *s = NULL; : char *q; : apr_size_t s_len; : : register apr_size_t min_width = 0; : apr_size_t precision = 0; : enum { : LEFT, RIGHT : } adjust; : char pad_char; : char prefix_char; : : double fp_num; : widest_int i_quad = (widest_int) 0; : u_widest_int ui_quad; : wide_int i_num = (wide_int) 0; : u_wide_int ui_num; : : char num_buf[NUM_BUF_SIZE]; : char char_buf[2]; /* for printing %% and % */ : : enum var_type_enum { : IS_QUAD, IS_LONG, IS_SHORT, IS_INT : }; : enum var_type_enum var_type = IS_INT; : : /* : * Flag variables : */ : boolean_e alternate_form; : boolean_e print_sign; : boolean_e print_blank; : boolean_e adjust_precision; : boolean_e adjust_width; : bool_int is_negative; : 8 0.0139 : sp = vbuff->curpos; 10 0.0174 : bep = vbuff->endpos; : 19 0.0331 : while (*fmt) { 45 0.0784 : if (*fmt != '%') { 43 0.0749 : INS_CHAR(*fmt, sp, bep, cc); : } : else { : /* : * Default variable settings : */ : boolean_e print_something = YES; : adjust = RIGHT; : alternate_form = print_sign = print_blank = NO; : pad_char = ' '; : prefix_char = NUL; : : fmt++; : : /* : * Try to avoid checking for flags, width or precision : */ 23 0.0401 : if (!apr_islower(*fmt)) { : /* : * Recognize flags: -, #, BLANK, + : */ : for (;; fmt++) { : if (*fmt == '-') : adjust = LEFT; : else if (*fmt == '+') : print_sign = YES; : else if (*fmt == '#') : alternate_form = YES; : else if (*fmt == ' ') : print_blank = YES; : else if (*fmt == '0') : pad_char = '0'; : else : break; : } : : /* : * Check if a width was specified : */ : if (apr_isdigit(*fmt)) { : STR_TO_DEC(fmt, min_width); : adjust_width = YES; : } : else if (*fmt == '*') { : int v = va_arg(ap, int); : fmt++; : adjust_width = YES; : if (v < 0) { : adjust = LEFT; : min_width = (apr_size_t)(-v); : } : else : min_width = (apr_size_t)v; : } : else : adjust_width = NO; : : /* : * Check if a precision was specified : */ : if (*fmt == '.') { : adjust_precision = YES; : fmt++; : if (apr_isdigit(*fmt)) { : STR_TO_DEC(fmt, precision); : } : else if (*fmt == '*') { : int v = va_arg(ap, int); : fmt++; : precision = (v < 0) ? 0 : (apr_size_t)v; : } : else : precision = 0; : } : else : adjust_precision = NO; : } : else : adjust_precision = adjust_width = NO; : : /* : * Modifier check. Note that if APR_INT64_T_FMT is "d", : * the first if condition is never true. : */ 3 0.0052 : if ((sizeof(APR_INT64_T_FMT) == 4 && : fmt[0] == APR_INT64_T_FMT[0] && : fmt[1] == APR_INT64_T_FMT[1]) || : (sizeof(APR_INT64_T_FMT) == 3 && : fmt[0] == APR_INT64_T_FMT[0]) || : (sizeof(APR_INT64_T_FMT) > 4 && : strncmp(fmt, APR_INT64_T_FMT, : sizeof(APR_INT64_T_FMT) - 2) == 0)) { : /* Need to account for trailing 'd' and null in sizeof() */ : var_type = IS_QUAD; : fmt += (sizeof(APR_INT64_T_FMT) - 2); : } 1 0.0017 : else if (*fmt == 'q') { : var_type = IS_QUAD; : fmt++; : } : else if (*fmt == 'l') { : var_type = IS_LONG; : fmt++; : } 4 0.0070 : else if (*fmt == 'h') { : var_type = IS_SHORT; : fmt++; : } : else { : var_type = IS_INT; : } : : /* : * Argument extraction and printing. : * First we determine the argument type. : * Then, we convert the argument to a string. : * On exit from the switch, s points to the string that : * must be printed, s_len has the length of the string : * The precision requirements, if any, are reflected in s_len. : * : * NOTE: pad_char may be set to '0' because of the 0 flag. : * It is reset to ' ' by non-numeric formats : */ 5 0.0087 : switch (*fmt) { : case 'u': 1 0.0017 : if (var_type == IS_QUAD) { : i_quad = va_arg(ap, u_widest_int); : s = conv_10_quad(i_quad, 1, &is_negative, : &num_buf[NUM_BUF_SIZE], &s_len); : } : else { 2 0.0035 : if (var_type == IS_LONG) : i_num = (wide_int) va_arg(ap, u_wide_int); : else if (var_type == IS_SHORT) : i_num = (wide_int) (unsigned short) va_arg(ap, unsigned int); : else 1 0.0017 : i_num = (wide_int) va_arg(ap, unsigned int); 2 0.0035 : s = conv_10(i_num, 1, &is_negative, : &num_buf[NUM_BUF_SIZE], &s_len); : } : FIX_PRECISION(adjust_precision, precision, s, s_len); : break; : : case 'd': : case 'i': 12 0.0209 : if (var_type == IS_QUAD) { : i_quad = va_arg(ap, widest_int); : s = conv_10_quad(i_quad, 0, &is_negative, : &num_buf[NUM_BUF_SIZE], &s_len); : } : else { 1 0.0017 : if (var_type == IS_LONG) : i_num = (wide_int) va_arg(ap, wide_int); 1 0.0017 : else if (var_type == IS_SHORT) : i_num = (wide_int) (short) va_arg(ap, int); : else 1 0.0017 : i_num = (wide_int) va_arg(ap, int); 1 0.0017 : s = conv_10(i_num, 0, &is_negative, : &num_buf[NUM_BUF_SIZE], &s_len); : } : FIX_PRECISION(adjust_precision, precision, s, s_len); : 2 0.0035 : if (is_negative) : prefix_char = '-'; : else if (print_sign) : prefix_char = '+'; : else if (print_blank) : prefix_char = ' '; : break; : : : case 'o': : if (var_type == IS_QUAD) { : ui_quad = va_arg(ap, u_widest_int); : s = conv_p2_quad(ui_quad, 3, *fmt, : &num_buf[NUM_BUF_SIZE], &s_len); : } : else { : if (var_type == IS_LONG) : ui_num = (u_wide_int) va_arg(ap, u_wide_int); : else if (var_type == IS_SHORT) : ui_num = (u_wide_int) (unsigned short) va_arg(ap, unsigned int); : else : ui_num = (u_wide_int) va_arg(ap, unsigned int); : s = conv_p2(ui_num, 3, *fmt, : &num_buf[NUM_BUF_SIZE], &s_len); : } : FIX_PRECISION(adjust_precision, precision, s, s_len); : if (alternate_form && *s != '0') { : *--s = '0'; : s_len++; : } : break; : : : case 'x': : case 'X': : if (var_type == IS_QUAD) { : ui_quad = va_arg(ap, u_widest_int); : s = conv_p2_quad(ui_quad, 4, *fmt, : &num_buf[NUM_BUF_SIZE], &s_len); : } : else { : if (var_type == IS_LONG) : ui_num = (u_wide_int) va_arg(ap, u_wide_int); : else if (var_type == IS_SHORT) : ui_num = (u_wide_int) (unsigned short) va_arg(ap, unsigned int); : else : ui_num = (u_wide_int) va_arg(ap, unsigned int); : s = conv_p2(ui_num, 4, *fmt, : &num_buf[NUM_BUF_SIZE], &s_len); : } : FIX_PRECISION(adjust_precision, precision, s, s_len); : if (alternate_form && i_num != 0) { : *--s = *fmt; /* 'x' or 'X' */ : *--s = '0'; : s_len += 2; : } : break; : : : case 's': 17 0.0296 : s = va_arg(ap, char *); 2 0.0035 : if (s != NULL) { : if (!adjust_precision) { 19 0.0331 : s_len = strlen(s); : } : else { : /* From the C library standard in section 7.9.6.1: : * ...if the precision is specified, no more then : * that many characters are written. If the : * precision is not specified or is greater : * than the size of the array, the array shall : * contain a null character. : * : * My reading is is precision is specified and : * is less then or equal to the size of the : * array, no null character is required. So : * we can't do a strlen. : * : * This figures out the length of the string : * up to the precision. Once it's long enough : * for the specified precision, we don't care : * anymore. : * : * NOTE: you must do the length comparison : * before the check for the null character. : * Otherwise, you'll check one beyond the : * last valid character. : */ : const char *walk; : : for (walk = s, s_len = 0; : (s_len < precision) && (*walk != '\0'); : ++walk, ++s_len); : } : } : else { : s = S_NULL; : s_len = S_NULL_LEN; : } : pad_char = ' '; : break; : : : case 'f': : case 'e': : case 'E': : fp_num = va_arg(ap, double); : /* : * We use &num_buf[ 1 ], so that we have room for the sign : */ : s = NULL; :#ifdef HAVE_ISNAN : if (isnan(fp_num)) { : s = "nan"; : s_len = 3; : } :#endif :#ifdef HAVE_ISINF : if (!s && isinf(fp_num)) { : s = "inf"; : s_len = 3; : } :#endif : if (!s) { : s = conv_fp(*fmt, fp_num, alternate_form, : (adjust_precision == NO) ? FLOAT_DIGITS : precision, : &is_negative, &num_buf[1], &s_len); : if (is_negative) : prefix_char = '-'; : else if (print_sign) : prefix_char = '+'; : else if (print_blank) : prefix_char = ' '; : } : break; : : : case 'g': : case 'G': : if (adjust_precision == NO) : precision = FLOAT_DIGITS; : else if (precision == 0) : precision = 1; : /* : * * We use &num_buf[ 1 ], so that we have room for the sign : */ : s = apr_gcvt(va_arg(ap, double), precision, &num_buf[1], : alternate_form); : if (*s == '-') : prefix_char = *s++; : else if (print_sign) : prefix_char = '+'; : else if (print_blank) : prefix_char = ' '; : : s_len = strlen(s); : : if (alternate_form && (q = strchr(s, '.')) == NULL) { : s[s_len++] = '.'; : s[s_len] = '\0'; /* delimit for following strchr() */ : } : if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL) : *q = 'E'; : break; : : : case 'c': 3 0.0052 : char_buf[0] = (char) (va_arg(ap, int)); : s = &char_buf[0]; : s_len = 1; : pad_char = ' '; : break; : : : case '%': : char_buf[0] = '%'; : s = &char_buf[0]; 3 0.0052 : s_len = 1; : pad_char = ' '; : break; : : : case 'n': : if (var_type == IS_QUAD) : *(va_arg(ap, widest_int *)) = cc; : else if (var_type == IS_LONG) : *(va_arg(ap, long *)) = cc; : else if (var_type == IS_SHORT) : *(va_arg(ap, short *)) = cc; : else : *(va_arg(ap, int *)) = cc; : print_something = NO; : break; : : /* : * This is where we extend the printf format, with a second : * type specifier : */ : case 'p': : switch(*++fmt) { : /* : * If the pointer size is equal to or smaller than the size : * of the largest unsigned int, we convert the pointer to a : * hex number, otherwise we print "%p" to indicate that we : * don't handle "%p". : */ : case 'p': :#ifdef APR_VOID_P_IS_QUAD : if (sizeof(void *) <= sizeof(u_widest_int)) { : ui_quad = (u_widest_int) va_arg(ap, void *); : s = conv_p2_quad(ui_quad, 4, 'x', : &num_buf[NUM_BUF_SIZE], &s_len); : } :#else : if (sizeof(void *) <= sizeof(u_wide_int)) { : ui_num = (u_wide_int) va_arg(ap, void *); : s = conv_p2(ui_num, 4, 'x', : &num_buf[NUM_BUF_SIZE], &s_len); : } :#endif : else { : s = "%p"; : s_len = 2; : prefix_char = NUL; : } : pad_char = ' '; : break; : : /* print an apr_sockaddr_t as a.b.c.d:port */ : case 'I': : { : apr_sockaddr_t *sa; : : sa = va_arg(ap, apr_sockaddr_t *); : if (sa != NULL) { : s = conv_apr_sockaddr(sa, &num_buf[NUM_BUF_SIZE], &s_len); : if (adjust_precision && precision < s_len) : s_len = precision; : } : else { : s = S_NULL; : s_len = S_NULL_LEN; : } : pad_char = ' '; : } : break; : : /* print a struct in_addr as a.b.c.d */ : case 'A': : { : struct in_addr *ia; : : ia = va_arg(ap, struct in_addr *); : if (ia != NULL) { : s = conv_in_addr(ia, &num_buf[NUM_BUF_SIZE], &s_len); : if (adjust_precision && precision < s_len) : s_len = precision; : } : else { : s = S_NULL; : s_len = S_NULL_LEN; : } : pad_char = ' '; : } : break; : : case 'T': :#if APR_HAS_THREADS : { : apr_os_thread_t *tid; : : tid = va_arg(ap, apr_os_thread_t *); : if (tid != NULL) { : s = conv_os_thread_t(tid, &num_buf[NUM_BUF_SIZE], &s_len); : if (adjust_precision && precision < s_len) : s_len = precision; : } : else { : s = S_NULL; : s_len = S_NULL_LEN; : } : pad_char = ' '; : } :#else : char_buf[0] = '0'; : s = &char_buf[0]; : s_len = 1; : pad_char = ' '; :#endif : break; : : case 't': :#if APR_HAS_THREADS : { : apr_os_thread_t *tid; : : tid = va_arg(ap, apr_os_thread_t *); : if (tid != NULL) { : s = conv_os_thread_t_hex(tid, &num_buf[NUM_BUF_SIZE], &s_len); : if (adjust_precision && precision < s_len) : s_len = precision; : } : else { : s = S_NULL; : s_len = S_NULL_LEN; : } : pad_char = ' '; : } :#else : char_buf[0] = '0'; : s = &char_buf[0]; : s_len = 1; : pad_char = ' '; :#endif : break; : : case NUL: : /* if %p ends the string, oh well ignore it */ : continue; : : default: : s = "bogus %p"; : s_len = 8; : prefix_char = NUL; : (void)va_arg(ap, void *); /* skip the bogus argument on the stack */ : break; : } : break; : : case NUL: : /* : * The last character of the format string was %. : * We ignore it. : */ : continue; : : : /* : * The default case is for unrecognized %'s. : * We print % to help the user identify what : * option is not understood. : * This is also useful in case the user wants to pass : * the output of format_converter to another function : * that understands some other % (like syslog). : * Note that we can't point s inside fmt because the : * unknown could be preceded by width etc. : */ : default: : char_buf[0] = '%'; : char_buf[1] = *fmt; : s = char_buf; : s_len = 2; : pad_char = ' '; : break; : } : : if (prefix_char != NUL && s != S_NULL && s != char_buf) { : *--s = prefix_char; 1 0.0017 : s_len++; : } : 5 0.0087 : if (adjust_width && adjust == RIGHT && min_width > s_len) { : if (pad_char == '0' && prefix_char != NUL) { : INS_CHAR(*s, sp, bep, cc); : s++; : s_len--; : min_width--; : } : PAD(min_width, s_len, pad_char); : } : : /* : * Print the string s. : */ 10 0.0174 : if (print_something == YES) { 19 0.0331 : for (i = s_len; i != 0; i--) { 30 0.0522 : INS_CHAR(*s, sp, bep, cc); : s++; : } : } : 20 0.0348 : if (adjust_width && adjust == LEFT && min_width > s_len) : PAD(min_width, s_len, pad_char); : } 20 0.0348 : fmt++; : } : vbuff->curpos = sp; : : return cc; 16 0.0279 :} : : :static int snprintf_flush(apr_vformatter_buff_t *vbuff) :{ : /* if the buffer fills we have to abort immediately, there is no way : * to "flush" an apr_snprintf... there's nowhere to flush it to. : */ : return -1; :} : : :APR_DECLARE_NONSTD(int) apr_snprintf(char *buf, apr_size_t len, : const char *format, ...) 30 0.0522 :{ /* apr_snprintf total: 57 0.0993 */ : int cc; : va_list ap; : apr_vformatter_buff_t vbuff; : : if (len == 0) { : /* NOTE: This is a special case; we just want to return the number : * of chars that would be written (minus \0) if the buffer : * size was infinite. We leverage the fact that INS_CHAR : * just does actual inserts iff the buffer pointer is non-NULL. : * In this case, we don't care what buf is; it can be NULL, since : * we don't touch it at all. : */ : vbuff.curpos = NULL; : vbuff.endpos = NULL; : } else { : /* save one byte for nul terminator */ 5 0.0087 : vbuff.curpos = buf; 3 0.0052 : vbuff.endpos = buf + len - 1; : } 5 0.0087 : va_start(ap, format); 13 0.0226 : cc = apr_vformatter(snprintf_flush, &vbuff, format, ap); : va_end(ap); : if (len != 0) { : *vbuff.curpos = '\0'; : } 1 0.0017 : return (cc == -1) ? (int)len : cc; :} : : :APR_DECLARE(int) apr_vsnprintf(char *buf, apr_size_t len, const char *format, : va_list ap) 6 0.0104 :{ /* apr_vsnprintf total: 16 0.0279 */ : int cc; : apr_vformatter_buff_t vbuff; : : if (len == 0) { : /* See above note */ : vbuff.curpos = NULL; : vbuff.endpos = NULL; : } else { : /* save one byte for nul terminator */ 4 0.0070 : vbuff.curpos = buf; : vbuff.endpos = buf + len - 1; : } 4 0.0070 : cc = apr_vformatter(snprintf_flush, &vbuff, format, ap); : if (len != 0) { : *vbuff.curpos = '\0'; : } 1 0.0017 : return (cc == -1) ? (int)len : cc; 1 0.0017 :} /* * Total samples for file : "tables/apr_hash.c" * * 233 0.4058 */ :/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as : * applicable. : * : * Licensed 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. : */ : :#include "apr_private.h" : :#include "apr_general.h" :#include "apr_pools.h" : :#include "apr_hash.h" : :#if APR_HAVE_STDLIB_H :#include :#endif :#if APR_HAVE_STRING_H :#include :#endif : :#if APR_POOL_DEBUG && APR_HAVE_STDIO_H :#include :#endif : :/* : * The internal form of a hash table. : * : * The table is an array indexed by the hash of the key; collisions : * are resolved by hanging a linked list of hash entries off each : * element of the array. Although this is a really simple design it : * isn't too bad given that pools have a low allocation overhead. : */ : :typedef struct apr_hash_entry_t apr_hash_entry_t; : :struct apr_hash_entry_t { : apr_hash_entry_t *next; : unsigned int hash; : const void *key; : apr_ssize_t klen; : const void *val; :}; : :/* : * Data structure for iterating through a hash table. : * : * We keep a pointer to the next hash entry here to allow the current : * hash entry to be freed or otherwise mangled between calls to : * apr_hash_next(). : */ :struct apr_hash_index_t { : apr_hash_t *ht; : apr_hash_entry_t *this, *next; : unsigned int index; :}; : :/* : * The size of the array is always a power of two. We use the maximum : * index rather than the size so that we can use bitwise-AND for : * modular arithmetic. : * The count of hash entries may be greater depending on the chosen : * collision rate. : */ :struct apr_hash_t { : apr_pool_t *pool; : apr_hash_entry_t **array; : apr_hash_index_t iterator; /* For apr_hash_first(NULL, ...) */ : unsigned int count, max; : apr_hashfunc_t hash_func; : apr_hash_entry_t *free; /* List of recycled entries */ :}; : :#define INITIAL_MAX 15 /* tunable == 2^n - 1 */ : : :/* : * Hash creation functions. : */ : :static apr_hash_entry_t **alloc_array(apr_hash_t *ht, unsigned int max) 1 0.0017 :{ : return apr_pcalloc(ht->pool, sizeof(*ht->array) * (max + 1)); /* alloc_array total: 1 0.0017 */ :} : :APR_DECLARE(apr_hash_t *) apr_hash_make(apr_pool_t *pool) 2 0.0035 :{ /* apr_hash_make total: 2 0.0035 */ : apr_hash_t *ht; : ht = apr_palloc(pool, sizeof(apr_hash_t)); : ht->pool = pool; : ht->free = NULL; : ht->count = 0; : ht->max = INITIAL_MAX; : ht->array = alloc_array(ht, ht->max); : ht->hash_func = apr_hashfunc_default; : return ht; :} : :APR_DECLARE(apr_hash_t *) apr_hash_make_custom(apr_pool_t *pool, : apr_hashfunc_t hash_func) :{ : apr_hash_t *ht = apr_hash_make(pool); : ht->hash_func = hash_func; : return ht; :} : : :/* : * Hash iteration functions. : */ : :APR_DECLARE(apr_hash_index_t *) apr_hash_next(apr_hash_index_t *hi) :{ 1 0.0017 : hi->this = hi->next; /* apr_hash_next total: 19 0.0331 */ 9 0.0157 : while (!hi->this) { 1 0.0017 : if (hi->index > hi->ht->max) : return NULL; : 2 0.0035 : hi->this = hi->ht->array[hi->index++]; : } 2 0.0035 : hi->next = hi->this->next; 4 0.0070 : return hi; :} : :APR_DECLARE(apr_hash_index_t *) apr_hash_first(apr_pool_t *p, apr_hash_t *ht) 1 0.0017 :{ : apr_hash_index_t *hi; : if (p) /* apr_hash_first total: 3 0.0052 */ : hi = apr_palloc(p, sizeof(*hi)); : else : hi = &ht->iterator; : 1 0.0017 : hi->ht = ht; : hi->index = 0; : hi->this = NULL; 1 0.0017 : hi->next = NULL; : return apr_hash_next(hi); :} : :APR_DECLARE(void) apr_hash_this(apr_hash_index_t *hi, : const void **key, : apr_ssize_t *klen, : void **val) :{ 8 0.0139 : if (key) *key = hi->this->key; /* apr_hash_this total: 8 0.0139 */ : if (klen) *klen = hi->this->klen; : if (val) *val = (void *)hi->this->val; :} : : :/* : * Expanding a hash table : */ : :static void expand_array(apr_hash_t *ht) :{ : apr_hash_index_t *hi; : apr_hash_entry_t **new_array; : unsigned int new_max; : : new_max = ht->max * 2 + 1; : new_array = alloc_array(ht, new_max); : for (hi = apr_hash_first(NULL, ht); hi; hi = apr_hash_next(hi)) { : unsigned int i = hi->this->hash & new_max; : hi->this->next = new_array[i]; : new_array[i] = hi->this; : } : ht->array = new_array; : ht->max = new_max; :} : :APR_DECLARE_NONSTD(unsigned int) apr_hashfunc_default(const char *char_key, : apr_ssize_t *klen) :{ : unsigned int hash = 0; : const unsigned char *key = (const unsigned char *)char_key; : const unsigned char *p; : apr_ssize_t i; : : /* : * This is the popular `times 33' hash algorithm which is used by : * perl and also appears in Berkeley DB. This is one of the best : * known hash functions for strings because it is both computed : * very fast and distributes very well. : * : * The originator may be Dan Bernstein but the code in Berkeley DB : * cites Chris Torek as the source. The best citation I have found : * is "Chris Torek, Hash function for text in C, Usenet message : * <27038@mimsy.umd.edu> in comp.lang.c , October, 1990." in Rich : * Salz's USENIX 1992 paper about INN which can be found at : * . : * : * The magic of number 33, i.e. why it works better than many other : * constants, prime or not, has never been adequately explained by : * anyone. So I try an explanation: if one experimentally tests all : * multipliers between 1 and 256 (as I did while writing a low-level : * data structure library some time ago) one detects that even : * numbers are not useable at all. The remaining 128 odd numbers : * (except for the number 1) work more or less all equally well. : * They all distribute in an acceptable way and this way fill a hash : * table with an average percent of approx. 86%. : * : * If one compares the chi^2 values of the variants (see : * Bob Jenkins ``Hashing Frequently Asked Questions'' at : * http://burtleburtle.net/bob/hash/hashfaq.html for a description : * of chi^2), the number 33 not even has the best value. But the : * number 33 and a few other equally good numbers like 17, 31, 63, : * 127 and 129 have nevertheless a great advantage to the remaining : * numbers in the large set of possible multipliers: their multiply : * operation can be replaced by a faster operation based on just one : * shift plus either a single addition or subtraction operation. And : * because a hash function has to both distribute good _and_ has to : * be very fast to compute, those few numbers should be preferred. : * : * -- Ralf S. Engelschall : */ : 31 0.0540 : if (*klen == APR_HASH_KEY_STRING) { /* apr_hashfunc_default total: 122 0.2125 */ 41 0.0714 : for (p = key; *p; p++) { 49 0.0853 : hash = hash * 33 + *p; : } : *klen = p - key; : } : else { : for (p = key, i = *klen; i; i--, p++) { : hash = hash * 33 + *p; : } : } : : return hash; 1 0.0017 :} : : :/* : * This is where we keep the details of the hash function and control : * the maximum collision rate. : * : * If val is non-NULL it creates and initializes a new hash entry if : * there isn't already one there; it returns an updatable pointer so : * that hash entries can be removed. : */ : :static apr_hash_entry_t **find_entry(apr_hash_t *ht, : const void *key, : apr_ssize_t klen, : const void *val) 24 0.0418 :{ /* find_entry total: 63 0.1097 */ : apr_hash_entry_t **hep, *he; : unsigned int hash; : : hash = ht->hash_func(key, &klen); : : /* scan linked list */ : for (hep = &ht->array[hash & ht->max], he = *hep; 1 0.0017 : he; hep = &he->next, he = *hep) { 31 0.0540 : if (he->hash == hash : && he->klen == klen : && memcmp(he->key, key, klen) == 0) : break; : } 1 0.0017 : if (he || !val) : return hep; : : /* add a new entry for non-NULL values */ : if ((he = ht->free) != NULL) : ht->free = he->next; : else : he = apr_palloc(ht->pool, sizeof(*he)); : he->next = NULL; : he->hash = hash; : he->key = key; : he->klen = klen; : he->val = val; : *hep = he; : ht->count++; : return hep; 6 0.0104 :} : :APR_DECLARE(apr_hash_t *) apr_hash_copy(apr_pool_t *pool, : const apr_hash_t *orig) :{ : apr_hash_t *ht; : apr_hash_entry_t *new_vals; : unsigned int i, j; : : ht = apr_palloc(pool, sizeof(apr_hash_t) + : sizeof(*ht->array) * (orig->max + 1) + : sizeof(apr_hash_entry_t) * orig->count); : ht->pool = pool; : ht->free = NULL; : ht->count = orig->count; : ht->max = orig->max; : ht->hash_func = orig->hash_func; : ht->array = (apr_hash_entry_t **)((char *)ht + sizeof(apr_hash_t)); : : new_vals = (apr_hash_entry_t *)((char *)(ht) + sizeof(apr_hash_t) + : sizeof(*ht->array) * (orig->max + 1)); : j = 0; : for (i = 0; i <= ht->max; i++) { : apr_hash_entry_t **new_entry = &(ht->array[i]); : apr_hash_entry_t *orig_entry = orig->array[i]; : while (orig_entry) { : *new_entry = &new_vals[j++]; : (*new_entry)->hash = orig_entry->hash; : (*new_entry)->key = orig_entry->key; : (*new_entry)->klen = orig_entry->klen; : (*new_entry)->val = orig_entry->val; : new_entry = &((*new_entry)->next); : orig_entry = orig_entry->next; : } : *new_entry = NULL; : } : return ht; :} : :APR_DECLARE(void *) apr_hash_get(apr_hash_t *ht, : const void *key, : apr_ssize_t klen) 2 0.0035 :{ /* apr_hash_get total: 7 0.0122 */ : apr_hash_entry_t *he; 5 0.0087 : he = *find_entry(ht, key, klen, NULL); : if (he) : return (void *)he->val; : else : return NULL; :} : :APR_DECLARE(void) apr_hash_set(apr_hash_t *ht, : const void *key, : apr_ssize_t klen, : const void *val) 1 0.0017 :{ /* apr_hash_set total: 4 0.0070 */ : apr_hash_entry_t **hep; : hep = find_entry(ht, key, klen, val); : if (*hep) { 1 0.0017 : if (!val) { : /* delete entry */ : apr_hash_entry_t *old = *hep; : *hep = (*hep)->next; : old->next = ht->free; : ht->free = old; 2 0.0035 : --ht->count; : } : else { : /* replace entry */ : (*hep)->val = val; : /* check that the collision rate isn't too high */ : if (ht->count > ht->max) { : expand_array(ht); : } : } : } : /* else key not present and val==NULL */ :} : :APR_DECLARE(unsigned int) apr_hash_count(apr_hash_t *ht) :{ : return ht->count; :} : :APR_DECLARE(apr_hash_t*) apr_hash_overlay(apr_pool_t *p, : const apr_hash_t *overlay, : const apr_hash_t *base) :{ : return apr_hash_merge(p, overlay, base, NULL, NULL); :} : :APR_DECLARE(apr_hash_t *) apr_hash_merge(apr_pool_t *p, : const apr_hash_t *overlay, : const apr_hash_t *base, : void * (*merger)(apr_pool_t *p, : const void *key, : apr_ssize_t klen, : const void *h1_val, : const void *h2_val, : const void *data), : const void *data) :{ : apr_hash_t *res; : apr_hash_entry_t *new_vals = NULL; : apr_hash_entry_t *iter; : apr_hash_entry_t *ent; : unsigned int i,j,k; : :#if APR_POOL_DEBUG : /* we don't copy keys and values, so it's necessary that : * overlay->a.pool and base->a.pool have a life span at least : * as long as p : */ : if (!apr_pool_is_ancestor(overlay->pool, p)) { : fprintf(stderr, : "apr_hash_merge: overlay's pool is not an ancestor of p\n"); : abort(); : } : if (!apr_pool_is_ancestor(base->pool, p)) { : fprintf(stderr, : "apr_hash_merge: base's pool is not an ancestor of p\n"); : abort(); : } :#endif : : res = apr_palloc(p, sizeof(apr_hash_t)); : res->pool = p; : res->free = NULL; : res->hash_func = base->hash_func; : res->count = base->count; : res->max = (overlay->max > base->max) ? overlay->max : base->max; : if (base->count + overlay->count > res->max) { : res->max = res->max * 2 + 1; : } : res->array = alloc_array(res, res->max); : if (base->count + overlay->count) { : new_vals = apr_palloc(p, sizeof(apr_hash_entry_t) * : (base->count + overlay->count)); : } : j = 0; : for (k = 0; k <= base->max; k++) { : for (iter = base->array[k]; iter; iter = iter->next) { : i = iter->hash & res->max; : new_vals[j].klen = iter->klen; : new_vals[j].key = iter->key; : new_vals[j].val = iter->val; : new_vals[j].hash = iter->hash; : new_vals[j].next = res->array[i]; : res->array[i] = &new_vals[j]; : j++; : } : } : : for (k = 0; k <= overlay->max; k++) { : for (iter = overlay->array[k]; iter; iter = iter->next) { : i = iter->hash & res->max; : for (ent = res->array[i]; ent; ent = ent->next) { : if ((ent->klen == iter->klen) && : (memcmp(ent->key, iter->key, iter->klen) == 0)) { : if (merger) { : ent->val = (*merger)(p, iter->key, iter->klen, : iter->val, ent->val, data); : } : else { : ent->val = iter->val; : } : break; : } : } : if (!ent) { : new_vals[j].klen = iter->klen; : new_vals[j].key = iter->key; : new_vals[j].val = iter->val; : new_vals[j].hash = iter->hash; : new_vals[j].next = res->array[i]; : res->array[i] = &new_vals[j]; : res->count++; : j++; : } : } : } : return res; :} : 4 0.0070 :APR_POOL_IMPLEMENT_ACCESSOR(hash) /* apr_hash_pool_get total: 4 0.0070 */ /* * Total samples for file : "memory/unix/apr_pools.c" * * 74 0.1289 */ :/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as : * applicable. : * : * Licensed 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. : */ : :#include "apr.h" :#include "apr_private.h" : :#include "apr_atomic.h" :#include "apr_portable.h" /* for get_os_proc */ :#include "apr_strings.h" :#include "apr_general.h" :#include "apr_pools.h" :#include "apr_allocator.h" :#include "apr_lib.h" :#include "apr_thread_mutex.h" :#include "apr_hash.h" :#include "apr_time.h" :#define APR_WANT_MEMFUNC :#include "apr_want.h" :#include "apr_env.h" : :#if APR_HAVE_STDLIB_H :#include /* for malloc, free and abort */ :#endif : :#if APR_HAVE_UNISTD_H :#include /* for getpid */ :#endif : : :/* : * Magic numbers : */ : :#define MIN_ALLOC 8192 :#define MAX_INDEX 20 : :#define BOUNDARY_INDEX 12 :#define BOUNDARY_SIZE (1 << BOUNDARY_INDEX) : :/* : * Timing constants for killing subprocesses : * There is a total 3-second delay between sending a SIGINT : * and sending of the final SIGKILL. : * TIMEOUT_INTERVAL should be set to TIMEOUT_USECS / 64 : * for the exponetial timeout alogrithm. : */ :#define TIMEOUT_USECS 3000000 :#define TIMEOUT_INTERVAL 46875 : :/* : * Allocator : */ : :struct apr_allocator_t { : apr_uint32_t max_index; : apr_uint32_t max_free_index; : apr_uint32_t current_free_index; :#if APR_HAS_THREADS : apr_thread_mutex_t *mutex; :#endif /* APR_HAS_THREADS */ : apr_pool_t *owner; : apr_memnode_t *free[MAX_INDEX]; :}; : :#define SIZEOF_ALLOCATOR_T APR_ALIGN_DEFAULT(sizeof(apr_allocator_t)) : : :/* : * Allocator : */ : :APR_DECLARE(apr_status_t) apr_allocator_create(apr_allocator_t **allocator) :{ : apr_allocator_t *new_allocator; : : *allocator = NULL; : : if ((new_allocator = malloc(SIZEOF_ALLOCATOR_T)) == NULL) : return APR_ENOMEM; : : memset(new_allocator, 0, SIZEOF_ALLOCATOR_T); : new_allocator->max_free_index = APR_ALLOCATOR_MAX_FREE_UNLIMITED; : : *allocator = new_allocator; : : return APR_SUCCESS; :} : :APR_DECLARE(void) apr_allocator_destroy(apr_allocator_t *allocator) :{ /* apr_allocator_destroy total: 2 0.0035 */ : apr_uint32_t index; : apr_memnode_t *node, **ref; : : for (index = 0; index < MAX_INDEX; index++) { : ref = &allocator->free[index]; 1 0.0017 : while ((node = *ref) != NULL) { : *ref = node->next; 1 0.0017 : free(node); : } : } : : free(allocator); :} : :#if APR_HAS_THREADS :APR_DECLARE(void) apr_allocator_mutex_set(apr_allocator_t *allocator, : apr_thread_mutex_t *mutex) :{ : allocator->mutex = mutex; :} : :APR_DECLARE(apr_thread_mutex_t *) apr_allocator_mutex_get( : apr_allocator_t *allocator) 1 0.0017 :{ /* apr_allocator_mutex_get total: 3 0.0052 */ : return allocator->mutex; 2 0.0035 :} :#endif /* APR_HAS_THREADS */ : :APR_DECLARE(void) apr_allocator_owner_set(apr_allocator_t *allocator, : apr_pool_t *pool) :{ : allocator->owner = pool; :} : :APR_DECLARE(apr_pool_t *) apr_allocator_owner_get(apr_allocator_t *allocator) 1 0.0017 :{ /* apr_allocator_owner_get total: 3 0.0052 */ : return allocator->owner; 2 0.0035 :} : :APR_DECLARE(void) apr_allocator_max_free_set(apr_allocator_t *allocator, : apr_size_t in_size) :{ : apr_uint32_t max_free_index; : apr_uint32_t size = (APR_UINT32_TRUNC_CAST)in_size; : :#if APR_HAS_THREADS : apr_thread_mutex_t *mutex; : : mutex = apr_allocator_mutex_get(allocator); : if (mutex != NULL) : apr_thread_mutex_lock(mutex); :#endif /* APR_HAS_THREADS */ : : max_free_index = APR_ALIGN(size, BOUNDARY_SIZE) >> BOUNDARY_INDEX; : allocator->current_free_index += max_free_index; : allocator->current_free_index -= allocator->max_free_index; : allocator->max_free_index = max_free_index; : if (allocator->current_free_index > max_free_index) : allocator->current_free_index = max_free_index; : :#if APR_HAS_THREADS : if (mutex != NULL) : apr_thread_mutex_unlock(mutex); :#endif :} : :static APR_INLINE :apr_memnode_t *allocator_alloc(apr_allocator_t *allocator, apr_size_t size) :{ : apr_memnode_t *node, **ref; : apr_uint32_t max_index; : apr_size_t i, index; : : /* Round up the block size to the next boundary, but always : * allocate at least a certain size (MIN_ALLOC). : */ : size = APR_ALIGN(size + APR_MEMNODE_T_SIZE, BOUNDARY_SIZE); 2 0.0035 : if (size < MIN_ALLOC) : size = MIN_ALLOC; : : /* Find the index for this node size by : * dividing its size by the boundary size : */ : index = (size >> BOUNDARY_INDEX) - 1; : : if (index > APR_UINT32_MAX) { : return NULL; : } : : /* First see if there are any nodes in the area we know : * our node will fit into. : */ 1 0.0017 : if (index <= allocator->max_index) { :#if APR_HAS_THREADS : if (allocator->mutex) : apr_thread_mutex_lock(allocator->mutex); :#endif /* APR_HAS_THREADS */ : : /* Walk the free list to see if there are : * any nodes on it of the requested size : * : * NOTE: an optimization would be to check : * allocator->free[index] first and if no : * node is present, directly use : * allocator->free[max_index]. This seems : * like overkill though and could cause : * memory waste. : */ : max_index = allocator->max_index; : ref = &allocator->free[index]; : i = index; : while (*ref == NULL && i < max_index) { : ref++; : i++; : } : : if ((node = *ref) != NULL) { : /* If we have found a node and it doesn't have any : * nodes waiting in line behind it _and_ we are on : * the highest available index, find the new highest : * available index : */ : if ((*ref = node->next) == NULL && i >= max_index) { : do { : ref--; : max_index--; : } : while (*ref == NULL && max_index > 0); : : allocator->max_index = max_index; : } : : allocator->current_free_index += node->index; : if (allocator->current_free_index > allocator->max_free_index) : allocator->current_free_index = allocator->max_free_index; : :#if APR_HAS_THREADS : if (allocator->mutex) : apr_thread_mutex_unlock(allocator->mutex); :#endif /* APR_HAS_THREADS */ : : node->next = NULL; : node->first_avail = (char *)node + APR_MEMNODE_T_SIZE; : : return node; : } : :#if APR_HAS_THREADS : if (allocator->mutex) : apr_thread_mutex_unlock(allocator->mutex); :#endif /* APR_HAS_THREADS */ : } : : /* If we found nothing, seek the sink (at index 0), if : * it is not empty. : */ 1 0.0017 : else if (allocator->free[0]) { :#if APR_HAS_THREADS : if (allocator->mutex) : apr_thread_mutex_lock(allocator->mutex); :#endif /* APR_HAS_THREADS */ : : /* Walk the free list to see if there are : * any nodes on it of the requested size : */ : ref = &allocator->free[0]; : while ((node = *ref) != NULL && index > node->index) : ref = &node->next; : : if (node) { : *ref = node->next; : : allocator->current_free_index += node->index; : if (allocator->current_free_index > allocator->max_free_index) : allocator->current_free_index = allocator->max_free_index; : :#if APR_HAS_THREADS : if (allocator->mutex) : apr_thread_mutex_unlock(allocator->mutex); :#endif /* APR_HAS_THREADS */ : : node->next = NULL; : node->first_avail = (char *)node + APR_MEMNODE_T_SIZE; : : return node; : } : :#if APR_HAS_THREADS : if (allocator->mutex) : apr_thread_mutex_unlock(allocator->mutex); :#endif /* APR_HAS_THREADS */ : } : : /* If we haven't got a suitable node, malloc a new one : * and initialize it. : */ 7 0.0122 : if ((node = malloc(size)) == NULL) : return NULL; : : node->next = NULL; 2 0.0035 : node->index = (APR_UINT32_TRUNC_CAST)index; : node->first_avail = (char *)node + APR_MEMNODE_T_SIZE; : node->endp = (char *)node + size; : : return node; :} : :static APR_INLINE :void allocator_free(apr_allocator_t *allocator, apr_memnode_t *node) :{ : apr_memnode_t *next, *freelist = NULL; : apr_uint32_t index, max_index; : apr_uint32_t max_free_index, current_free_index; : :#if APR_HAS_THREADS : if (allocator->mutex) : apr_thread_mutex_lock(allocator->mutex); :#endif /* APR_HAS_THREADS */ : : max_index = allocator->max_index; : max_free_index = allocator->max_free_index; : current_free_index = allocator->current_free_index; : : /* Walk the list of submitted nodes and free them one by one, : * shoving them in the right 'size' buckets as we go. : */ : do { : next = node->next; : index = node->index; : : if (max_free_index != APR_ALLOCATOR_MAX_FREE_UNLIMITED : && index > current_free_index) { : node->next = freelist; : freelist = node; : } : else if (index < MAX_INDEX) { : /* Add the node to the appropiate 'size' bucket. Adjust : * the max_index when appropiate. : */ : if ((node->next = allocator->free[index]) == NULL : && index > max_index) { : max_index = index; : } : allocator->free[index] = node; : current_free_index -= index; : } : else { : /* This node is too large to keep in a specific size bucket, : * just add it to the sink (at index 0). : */ : node->next = allocator->free[0]; : allocator->free[0] = node; : current_free_index -= index; : } : } while ((node = next) != NULL); : : allocator->max_index = max_index; : allocator->current_free_index = current_free_index; : :#if APR_HAS_THREADS : if (allocator->mutex) : apr_thread_mutex_unlock(allocator->mutex); :#endif /* APR_HAS_THREADS */ : : while (freelist != NULL) { : node = freelist; : freelist = node->next; : free(node); : } :} : :APR_DECLARE(apr_memnode_t *) apr_allocator_alloc(apr_allocator_t *allocator, : apr_size_t size) :{ : return allocator_alloc(allocator, size); :} : :APR_DECLARE(void) apr_allocator_free(apr_allocator_t *allocator, : apr_memnode_t *node) :{ : allocator_free(allocator, node); :} : : : :/* : * Debug level : */ : :#define APR_POOL_DEBUG_GENERAL 0x01 :#define APR_POOL_DEBUG_VERBOSE 0x02 :#define APR_POOL_DEBUG_LIFETIME 0x04 :#define APR_POOL_DEBUG_OWNER 0x08 :#define APR_POOL_DEBUG_VERBOSE_ALLOC 0x10 : :#define APR_POOL_DEBUG_VERBOSE_ALL (APR_POOL_DEBUG_VERBOSE \ : | APR_POOL_DEBUG_VERBOSE_ALLOC) : : :/* : * Structures : */ : :typedef struct cleanup_t cleanup_t; : :/** A list of processes */ :struct process_chain { : /** The process ID */ : apr_proc_t *proc; : apr_kill_conditions_e kill_how; : /** The next process in the list */ : struct process_chain *next; :}; : : :#if APR_POOL_DEBUG : :typedef struct debug_node_t debug_node_t; : :struct debug_node_t { : debug_node_t *next; : apr_uint32_t index; : void *beginp[64]; : void *endp[64]; :}; : :#define SIZEOF_DEBUG_NODE_T APR_ALIGN_DEFAULT(sizeof(debug_node_t)) : :#endif /* APR_POOL_DEBUG */ : :/* The ref field in the apr_pool_t struct holds a : * pointer to the pointer referencing this pool. : * It is used for parent, child, sibling management. : * Look at apr_pool_create_ex() and apr_pool_destroy() : * to see how it is used. : */ :struct apr_pool_t { : apr_pool_t *parent; : apr_pool_t *child; : apr_pool_t *sibling; : apr_pool_t **ref; : cleanup_t *cleanups; : cleanup_t *free_cleanups; : apr_allocator_t *allocator; : struct process_chain *subprocesses; : apr_abortfunc_t abort_fn; : apr_hash_t *user_data; : const char *tag; : :#if !APR_POOL_DEBUG : apr_memnode_t *active; : apr_memnode_t *self; /* The node containing the pool itself */ : char *self_first_avail; : :#else /* APR_POOL_DEBUG */ : apr_pool_t *joined; /* the caller has guaranteed that this pool : * will survive as long as ->joined */ : debug_node_t *nodes; : const char *file_line; : apr_uint32_t creation_flags; : unsigned int stat_alloc; : unsigned int stat_total_alloc; : unsigned int stat_clear; :#if APR_HAS_THREADS : apr_os_thread_t owner; : apr_thread_mutex_t *mutex; :#endif /* APR_HAS_THREADS */ :#endif /* APR_POOL_DEBUG */ :#ifdef NETWARE : apr_os_proc_t owner_proc; :#endif /* defined(NETWARE) */ :}; : :#define SIZEOF_POOL_T APR_ALIGN_DEFAULT(sizeof(apr_pool_t)) : : :/* : * Variables : */ : :static apr_byte_t apr_pools_initialized = 0; :static apr_pool_t *global_pool = NULL; : :#if !APR_POOL_DEBUG :static apr_allocator_t *global_allocator = NULL; :#endif /* !APR_POOL_DEBUG */ : :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) :static apr_file_t *file_stderr = NULL; :#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ : :/* : * Local functions : */ : :static void run_cleanups(cleanup_t **c); :static void run_child_cleanups(cleanup_t **c); :static void free_proc_chain(struct process_chain *procs); : :#if APR_POOL_DEBUG :static void pool_destroy_debug(apr_pool_t *pool, const char *file_line); :#endif : :#if !APR_POOL_DEBUG :/* : * Initialization : */ : :APR_DECLARE(apr_status_t) apr_pool_initialize(void) :{ : apr_status_t rv; : : if (apr_pools_initialized++) : return APR_SUCCESS; : : if ((rv = apr_allocator_create(&global_allocator)) != APR_SUCCESS) { : apr_pools_initialized = 0; : return rv; : } : : if ((rv = apr_pool_create_ex(&global_pool, NULL, NULL, : global_allocator)) != APR_SUCCESS) { : apr_allocator_destroy(global_allocator); : global_allocator = NULL; : apr_pools_initialized = 0; : return rv; : } : : apr_pool_tag(global_pool, "apr_global_pool"); : : /* This has to happen here because mutexes might be backed by : * atomics. It used to be snug and safe in apr_initialize(). : */ : if ((rv = apr_atomic_init(global_pool)) != APR_SUCCESS) { : return rv; : } : :#if APR_HAS_THREADS : { : apr_thread_mutex_t *mutex; : : if ((rv = apr_thread_mutex_create(&mutex, : APR_THREAD_MUTEX_DEFAULT, : global_pool)) != APR_SUCCESS) { : return rv; : } : : apr_allocator_mutex_set(global_allocator, mutex); : } :#endif /* APR_HAS_THREADS */ : : apr_allocator_owner_set(global_allocator, global_pool); : : return APR_SUCCESS; :} : :APR_DECLARE(void) apr_pool_terminate(void) :{ : if (!apr_pools_initialized) : return; : : if (--apr_pools_initialized) : return; : : apr_pool_destroy(global_pool); /* This will also destroy the mutex */ : global_pool = NULL; : : global_allocator = NULL; :} : : :/* Node list management helper macros; list_insert() inserts 'node' : * before 'point'. */ :#define list_insert(node, point) do { \ : node->ref = point->ref; \ : *node->ref = node; \ : node->next = point; \ : point->ref = &node->next; \ :} while (0) : :/* list_remove() removes 'node' from its list. */ :#define list_remove(node) do { \ : *node->ref = node->next; \ : node->next->ref = node->ref; \ :} while (0) : :/* : * Memory allocation : */ : :APR_DECLARE(void *) apr_palloc(apr_pool_t *pool, apr_size_t size) 15 0.0261 :{ /* apr_palloc total: 32 0.0557 */ : apr_memnode_t *active, *node; : void *mem; : apr_size_t free_index; : : size = APR_ALIGN_DEFAULT(size); : active = pool->active; : : /* If the active node has enough bytes left, use it. */ : if (size < (apr_size_t)(active->endp - active->first_avail)) { 1 0.0017 : mem = active->first_avail; : active->first_avail += size; : : return mem; : } : : node = active->next; 2 0.0035 : if (size < (apr_size_t)(node->endp - node->first_avail)) { 1 0.0017 : list_remove(node); : } : else { 2 0.0035 : if ((node = allocator_alloc(pool->allocator, size)) == NULL) { : if (pool->abort_fn) : pool->abort_fn(APR_ENOMEM); : : return NULL; : } : } : : node->free_index = 0; : : mem = node->first_avail; : node->first_avail += size; : : list_insert(node, active); : : pool->active = node; : 1 0.0017 : free_index = (APR_ALIGN(active->endp - active->first_avail + 1, : BOUNDARY_SIZE) - BOUNDARY_SIZE) >> BOUNDARY_INDEX; : : active->free_index = (APR_UINT32_TRUNC_CAST)free_index; 3 0.0052 : node = active->next; : if (free_index >= node->free_index) : return mem; : : do { : node = node->next; : } : while (free_index < node->free_index); : : list_remove(active); : list_insert(active, node); : : return mem; 3 0.0052 :} : :/* Provide an implementation of apr_pcalloc for backward compatibility : * with code built before apr_pcalloc was a macro : */ : :#ifdef apr_pcalloc :#undef apr_pcalloc :#endif : :APR_DECLARE(void *) apr_pcalloc(apr_pool_t *pool, apr_size_t size); :APR_DECLARE(void *) apr_pcalloc(apr_pool_t *pool, apr_size_t size) :{ : void *mem; : : size = APR_ALIGN_DEFAULT(size); : if ((mem = apr_palloc(pool, size)) != NULL) { : memset(mem, 0, size); : } : : return mem; :} : : :/* : * Pool creation/destruction : */ : :APR_DECLARE(void) apr_pool_clear(apr_pool_t *pool) :{ : apr_memnode_t *active; : : /* Destroy the subpools. The subpools will detach themselves from : * this pool thus this loop is safe and easy. : */ : while (pool->child) : apr_pool_destroy(pool->child); : : /* Run cleanups */ : run_cleanups(&pool->cleanups); : pool->cleanups = NULL; : pool->free_cleanups = NULL; : : /* Free subprocesses */ : free_proc_chain(pool->subprocesses); : pool->subprocesses = NULL; : : /* Clear the user data. */ : pool->user_data = NULL; : : /* Find the node attached to the pool structure, reset it, make : * it the active node and free the rest of the nodes. : */ : active = pool->active = pool->self; : active->first_avail = pool->self_first_avail; : : if (active->next == active) : return; : : *active->ref = NULL; : allocator_free(pool->allocator, active->next); : active->next = active; : active->ref = &active->next; :} : :APR_DECLARE(void) apr_pool_destroy(apr_pool_t *pool) 1 0.0017 :{ /* apr_pool_destroy total: 1 0.0017 */ : apr_memnode_t *active; : apr_allocator_t *allocator; : : /* Destroy the subpools. The subpools will detach themselve from : * this pool thus this loop is safe and easy. : */ : while (pool->child) : apr_pool_destroy(pool->child); : : /* Run cleanups */ : run_cleanups(&pool->cleanups); : : /* Free subprocesses */ : free_proc_chain(pool->subprocesses); : : /* Remove the pool from the parents child list */ : if (pool->parent) { :#if APR_HAS_THREADS : apr_thread_mutex_t *mutex; : : if ((mutex = apr_allocator_mutex_get(pool->parent->allocator)) != NULL) : apr_thread_mutex_lock(mutex); :#endif /* APR_HAS_THREADS */ : : if ((*pool->ref = pool->sibling) != NULL) : pool->sibling->ref = pool->ref; : :#if APR_HAS_THREADS : if (mutex) : apr_thread_mutex_unlock(mutex); :#endif /* APR_HAS_THREADS */ : } : : /* Find the block attached to the pool structure. Save a copy of the : * allocator pointer, because the pool struct soon will be no more. : */ : allocator = pool->allocator; : active = pool->self; : *active->ref = NULL; : :#if APR_HAS_THREADS : if (apr_allocator_owner_get(allocator) == pool) { : /* Make sure to remove the lock, since it is highly likely to : * be invalid now. : */ : apr_allocator_mutex_set(allocator, NULL); : } :#endif /* APR_HAS_THREADS */ : : /* Free all the nodes in the pool (including the node holding the : * pool struct), by giving them back to the allocator. : */ : allocator_free(allocator, active); : : /* If this pool happens to be the owner of the allocator, free : * everything in the allocator (that includes the pool struct : * and the allocator). Don't worry about destroying the optional mutex : * in the allocator, it will have been destroyed by the cleanup function. : */ : if (apr_allocator_owner_get(allocator) == pool) { : apr_allocator_destroy(allocator); : } :} : :APR_DECLARE(apr_status_t) apr_pool_create_ex(apr_pool_t **newpool, : apr_pool_t *parent, : apr_abortfunc_t abort_fn, : apr_allocator_t *allocator) 6 0.0104 :{ /* apr_pool_create_ex total: 22 0.0383 */ : apr_pool_t *pool; : apr_memnode_t *node; : : *newpool = NULL; : : if (!parent) : parent = global_pool; : : if (!abort_fn && parent) : abort_fn = parent->abort_fn; : : if (allocator == NULL) 2 0.0035 : allocator = parent->allocator; : : if ((node = allocator_alloc(allocator, : MIN_ALLOC - APR_MEMNODE_T_SIZE)) == NULL) { : if (abort_fn) : abort_fn(APR_ENOMEM); : : return APR_ENOMEM; : } : : node->next = node; : node->ref = &node->next; : : pool = (apr_pool_t *)node->first_avail; : node->first_avail = pool->self_first_avail = (char *)pool + SIZEOF_POOL_T; : : pool->allocator = allocator; : pool->active = pool->self = node; : pool->abort_fn = abort_fn; : pool->child = NULL; : pool->cleanups = NULL; 1 0.0017 : pool->free_cleanups = NULL; : pool->subprocesses = NULL; : pool->user_data = NULL; : pool->tag = NULL; : :#ifdef NETWARE : pool->owner_proc = (apr_os_proc_t)getnlmhandle(); :#endif /* defined(NETWARE) */ : 4 0.0070 : if ((pool->parent = parent) != NULL) { :#if APR_HAS_THREADS : apr_thread_mutex_t *mutex; : : if ((mutex = apr_allocator_mutex_get(parent->allocator)) != NULL) : apr_thread_mutex_lock(mutex); :#endif /* APR_HAS_THREADS */ : : if ((pool->sibling = parent->child) != NULL) : pool->sibling->ref = &pool->sibling; : : parent->child = pool; : pool->ref = &parent->child; : :#if APR_HAS_THREADS : if (mutex) : apr_thread_mutex_unlock(mutex); :#endif /* APR_HAS_THREADS */ : } : else { : pool->sibling = NULL; : pool->ref = NULL; : } : : *newpool = pool; : : return APR_SUCCESS; :} : : :/* : * "Print" functions : */ : :/* : * apr_psprintf is implemented by writing directly into the current : * block of the pool, starting right at first_avail. If there's : * insufficient room, then a new block is allocated and the earlier : * output is copied over. The new block isn't linked into the pool : * until all the output is done. : * : * Note that this is completely safe because nothing else can : * allocate in this apr_pool_t while apr_psprintf is running. alarms are : * blocked, and the only thing outside of apr_pools.c that's invoked : * is apr_vformatter -- which was purposefully written to be : * self-contained with no callouts. : */ : :struct psprintf_data { : apr_vformatter_buff_t vbuff; : apr_memnode_t *node; : apr_pool_t *pool; : apr_byte_t got_a_new_node; : apr_memnode_t *free; :}; : :#define APR_PSPRINTF_MIN_STRINGSIZE 32 : :static int psprintf_flush(apr_vformatter_buff_t *vbuff) :{ : struct psprintf_data *ps = (struct psprintf_data *)vbuff; : apr_memnode_t *node, *active; : apr_size_t cur_len, size; : char *strp; : apr_pool_t *pool; : apr_size_t free_index; : : pool = ps->pool; : active = ps->node; : strp = ps->vbuff.curpos; : cur_len = strp - active->first_avail; : size = cur_len << 1; : : /* Make sure that we don't try to use a block that has less : * than APR_PSPRINTF_MIN_STRINGSIZE bytes left in it. This : * also catches the case where size == 0, which would result : * in reusing a block that can't even hold the NUL byte. : */ : if (size < APR_PSPRINTF_MIN_STRINGSIZE) : size = APR_PSPRINTF_MIN_STRINGSIZE; : : node = active->next; : if (!ps->got_a_new_node : && size < (apr_size_t)(node->endp - node->first_avail)) { : : list_remove(node); : list_insert(node, active); : : node->free_index = 0; : : pool->active = node; : : free_index = (APR_ALIGN(active->endp - active->first_avail + 1, : BOUNDARY_SIZE) - BOUNDARY_SIZE) >> BOUNDARY_INDEX; : : active->free_index = (APR_UINT32_TRUNC_CAST)free_index; : node = active->next; : if (free_index < node->free_index) { : do { : node = node->next; : } : while (free_index < node->free_index); : : list_remove(active); : list_insert(active, node); : } : : node = pool->active; : } : else { : if ((node = allocator_alloc(pool->allocator, size)) == NULL) : return -1; : : if (ps->got_a_new_node) { : active->next = ps->free; : ps->free = active; : } : : ps->got_a_new_node = 1; : } : : memcpy(node->first_avail, active->first_avail, cur_len); : : ps->node = node; : ps->vbuff.curpos = node->first_avail + cur_len; : ps->vbuff.endpos = node->endp - 1; /* Save a byte for NUL terminator */ : : return 0; :} : :APR_DECLARE(char *) apr_pvsprintf(apr_pool_t *pool, const char *fmt, va_list ap) :{ : struct psprintf_data ps; : char *strp; : apr_size_t size; : apr_memnode_t *active, *node; : apr_size_t free_index; : : ps.node = active = pool->active; : ps.pool = pool; : ps.vbuff.curpos = ps.node->first_avail; : : /* Save a byte for the NUL terminator */ : ps.vbuff.endpos = ps.node->endp - 1; : ps.got_a_new_node = 0; : ps.free = NULL; : : /* Make sure that the first node passed to apr_vformatter has at least : * room to hold the NUL terminator. : */ : if (ps.node->first_avail == ps.node->endp) { : if (psprintf_flush(&ps.vbuff) == -1) { : if (pool->abort_fn) { : pool->abort_fn(APR_ENOMEM); : } : : return NULL; : } : } : : if (apr_vformatter(psprintf_flush, &ps.vbuff, fmt, ap) == -1) { : if (pool->abort_fn) : pool->abort_fn(APR_ENOMEM); : : return NULL; : } : : strp = ps.vbuff.curpos; : *strp++ = '\0'; : : size = strp - ps.node->first_avail; : size = APR_ALIGN_DEFAULT(size); : strp = ps.node->first_avail; : ps.node->first_avail += size; : : if (ps.free) : allocator_free(pool->allocator, ps.free); : : /* : * Link the node in if it's a new one : */ : if (!ps.got_a_new_node) : return strp; : : active = pool->active; : node = ps.node; : : node->free_index = 0; : : list_insert(node, active); : : pool->active = node; : : free_index = (APR_ALIGN(active->endp - active->first_avail + 1, : BOUNDARY_SIZE) - BOUNDARY_SIZE) >> BOUNDARY_INDEX; : : active->free_index = (APR_UINT32_TRUNC_CAST)free_index; : node = active->next; : : if (free_index >= node->free_index) : return strp; : : do { : node = node->next; : } : while (free_index < node->free_index); : : list_remove(active); : list_insert(active, node); : : return strp; :} : : :#else /* APR_POOL_DEBUG */ :/* : * Debug helper functions : */ : : :/* : * Walk the pool tree rooted at pool, depth first. When fn returns : * anything other than 0, abort the traversal and return the value : * returned by fn. : */ :static int apr_pool_walk_tree(apr_pool_t *pool, : int (*fn)(apr_pool_t *pool, void *data), : void *data) :{ : int rv; : apr_pool_t *child; : : rv = fn(pool, data); : if (rv) : return rv; : :#if APR_HAS_THREADS : if (pool->mutex) { : apr_thread_mutex_lock(pool->mutex); : } :#endif /* APR_HAS_THREADS */ : : child = pool->child; : while (child) { : rv = apr_pool_walk_tree(child, fn, data); : if (rv) : break; : : child = child->sibling; : } : :#if APR_HAS_THREADS : if (pool->mutex) { : apr_thread_mutex_unlock(pool->mutex); : } :#endif /* APR_HAS_THREADS */ : : return rv; :} : :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) :static void apr_pool_log_event(apr_pool_t *pool, const char *event, : const char *file_line, int deref) :{ : if (file_stderr) { : if (deref) { : apr_file_printf(file_stderr, : "POOL DEBUG: " : "[%lu" :#if APR_HAS_THREADS : "/%lu" :#endif /* APR_HAS_THREADS */ : "] " : "%7s " : "(%10lu/%10lu/%10lu) " : "0x%08X \"%s\" " : "<%s> " : "(%u/%u/%u) " : "\n", : (unsigned long)getpid(), :#if APR_HAS_THREADS : (unsigned long)apr_os_thread_current(), :#endif /* APR_HAS_THREADS */ : event, : (unsigned long)apr_pool_num_bytes(pool, 0), : (unsigned long)apr_pool_num_bytes(pool, 1), : (unsigned long)apr_pool_num_bytes(global_pool, 1), : (unsigned int)pool, pool->tag, : file_line, : pool->stat_alloc, pool->stat_total_alloc, pool->stat_clear); : } : else { : apr_file_printf(file_stderr, : "POOL DEBUG: " : "[%lu" :#if APR_HAS_THREADS : "/%lu" :#endif /* APR_HAS_THREADS */ : "] " : "%7s " : " " : "0x%08X " : "<%s> " : "\n", : (unsigned long)getpid(), :#if APR_HAS_THREADS : (unsigned long)apr_os_thread_current(), :#endif /* APR_HAS_THREADS */ : event, : (unsigned int)pool, : file_line); : } : } :} :#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ : :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME) :static int pool_is_child_of(apr_pool_t *parent, void *data) :{ : apr_pool_t *pool = (apr_pool_t *)data; : : return (pool == parent); :} : :static int apr_pool_is_child_of(apr_pool_t *pool, apr_pool_t *parent) :{ : if (parent == NULL) : return 0; : : return apr_pool_walk_tree(parent, pool_is_child_of, pool); :} :#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME) */ : :static void apr_pool_check_integrity(apr_pool_t *pool) :{ : /* Rule of thumb: use of the global pool is always : * ok, since the only user is apr_pools.c. Unless : * people have searched for the top level parent and : * started to use that... : */ : if (pool == global_pool || global_pool == NULL) : return; : : /* Lifetime : * This basically checks to see if the pool being used is still : * a relative to the global pool. If not it was previously : * destroyed, in which case we abort(). : */ :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME) : if (!apr_pool_is_child_of(pool, global_pool)) { :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) : apr_pool_log_event(pool, "LIFE", : __FILE__ ":apr_pool_integrity check", 0); :#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ : abort(); : } :#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_LIFETIME) */ : :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_OWNER) :#if APR_HAS_THREADS : if (!apr_os_thread_equal(pool->owner, apr_os_thread_current())) { :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) : apr_pool_log_event(pool, "THREAD", : __FILE__ ":apr_pool_integrity check", 0); :#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ : abort(); : } :#endif /* APR_HAS_THREADS */ :#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_OWNER) */ :} : : :/* : * Initialization (debug) : */ : :APR_DECLARE(apr_status_t) apr_pool_initialize(void) :{ : apr_status_t rv; :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) : char *logpath; :#endif : : if (apr_pools_initialized++) : return APR_SUCCESS; : : /* Since the debug code works a bit differently then the : * regular pools code, we ask for a lock here. The regular : * pools code has got this lock embedded in the global : * allocator, a concept unknown to debug mode. : */ : if ((rv = apr_pool_create_ex(&global_pool, NULL, NULL, : NULL)) != APR_SUCCESS) { : return rv; : } : : apr_pool_tag(global_pool, "APR global pool"); : : apr_pools_initialized = 1; : : /* This has to happen here because mutexes might be backed by : * atomics. It used to be snug and safe in apr_initialize(). : */ : if ((rv = apr_atomic_init(global_pool)) != APR_SUCCESS) { : return rv; : } : :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) : rv = apr_env_get(&logpath, "APR_POOL_DEBUG_LOG", global_pool); : : if (rv == APR_SUCCESS) { : apr_file_open(&file_stderr, logpath, APR_APPEND|APR_WRITE|APR_CREATE, : APR_OS_DEFAULT, global_pool); : } : else { : apr_file_open_stderr(&file_stderr, global_pool); : } : : if (file_stderr) { : apr_file_printf(file_stderr, : "POOL DEBUG: [PID" :#if APR_HAS_THREADS : "/TID" :#endif /* APR_HAS_THREADS */ : "] ACTION (SIZE /POOL SIZE /TOTAL SIZE) " : "POOL \"TAG\" <__FILE__:__LINE__> (ALLOCS/TOTAL ALLOCS/CLEARS)\n"); : : apr_pool_log_event(global_pool, "GLOBAL", __FILE__ ":apr_pool_initialize", 0); : } :#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ : : return APR_SUCCESS; :} : :APR_DECLARE(void) apr_pool_terminate(void) :{ : if (!apr_pools_initialized) : return; : : apr_pools_initialized = 0; : : apr_pool_destroy(global_pool); /* This will also destroy the mutex */ : global_pool = NULL; : :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) : file_stderr = NULL; :#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ :} : : :/* : * Memory allocation (debug) : */ : :static void *pool_alloc(apr_pool_t *pool, apr_size_t size) :{ : debug_node_t *node; : void *mem; : : if ((mem = malloc(size)) == NULL) { : if (pool->abort_fn) : pool->abort_fn(APR_ENOMEM); : : return NULL; : } : : node = pool->nodes; : if (node == NULL || node->index == 64) { : if ((node = malloc(SIZEOF_DEBUG_NODE_T)) == NULL) { : if (pool->abort_fn) : pool->abort_fn(APR_ENOMEM); : : return NULL; : } : : memset(node, 0, SIZEOF_DEBUG_NODE_T); : : node->next = pool->nodes; : pool->nodes = node; : node->index = 0; : } : : node->beginp[node->index] = mem; : node->endp[node->index] = (char *)mem + size; : node->index++; : : pool->stat_alloc++; : pool->stat_total_alloc++; : : return mem; :} : :APR_DECLARE(void *) apr_palloc_debug(apr_pool_t *pool, apr_size_t size, : const char *file_line) :{ : void *mem; : : apr_pool_check_integrity(pool); : : mem = pool_alloc(pool, size); : :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC) : apr_pool_log_event(pool, "PALLOC", file_line, 1); :#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC) */ : : return mem; :} : :APR_DECLARE(void *) apr_pcalloc_debug(apr_pool_t *pool, apr_size_t size, : const char *file_line) :{ : void *mem; : : apr_pool_check_integrity(pool); : : mem = pool_alloc(pool, size); : memset(mem, 0, size); : :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC) : apr_pool_log_event(pool, "PCALLOC", file_line, 1); :#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALLOC) */ : : return mem; :} : : :/* : * Pool creation/destruction (debug) : */ : :#define POOL_POISON_BYTE 'A' : :static void pool_clear_debug(apr_pool_t *pool, const char *file_line) :{ : debug_node_t *node; : apr_uint32_t index; : : /* Destroy the subpools. The subpools will detach themselves from : * this pool thus this loop is safe and easy. : */ : while (pool->child) : pool_destroy_debug(pool->child, file_line); : : /* Run cleanups */ : run_cleanups(&pool->cleanups); : pool->free_cleanups = NULL; : pool->cleanups = NULL; : : /* If new child pools showed up, this is a reason to raise a flag */ : if (pool->child) : abort(); : : /* Free subprocesses */ : free_proc_chain(pool->subprocesses); : pool->subprocesses = NULL; : : /* Clear the user data. */ : pool->user_data = NULL; : : /* Free the blocks, scribbling over them first to help highlight : * use-after-free issues. */ : while ((node = pool->nodes) != NULL) { : pool->nodes = node->next; : : for (index = 0; index < node->index; index++) { : memset(node->beginp[index], POOL_POISON_BYTE, : node->endp[index] - node->beginp[index]); : free(node->beginp[index]); : } : : memset(node, POOL_POISON_BYTE, SIZEOF_DEBUG_NODE_T); : free(node); : } : : pool->stat_alloc = 0; : pool->stat_clear++; :} : :APR_DECLARE(void) apr_pool_clear_debug(apr_pool_t *pool, : const char *file_line) :{ :#if APR_HAS_THREADS : apr_thread_mutex_t *mutex = NULL; :#endif : : apr_pool_check_integrity(pool); : :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) : apr_pool_log_event(pool, "CLEAR", file_line, 1); :#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) */ : :#if APR_HAS_THREADS : if (pool->parent != NULL) : mutex = pool->parent->mutex; : : /* Lock the parent mutex before clearing so that if we have our : * own mutex it won't be accessed by apr_pool_walk_tree after : * it has been destroyed. : */ : if (mutex != NULL && mutex != pool->mutex) { : apr_thread_mutex_lock(mutex); : } :#endif : : pool_clear_debug(pool, file_line); : :#if APR_HAS_THREADS : /* If we had our own mutex, it will have been destroyed by : * the registered cleanups. Recreate the mutex. Unlock : * the mutex we obtained above. : */ : if (mutex != pool->mutex) { : (void)apr_thread_mutex_create(&pool->mutex, : APR_THREAD_MUTEX_NESTED, pool); : : if (mutex != NULL) : (void)apr_thread_mutex_unlock(mutex); : } :#endif /* APR_HAS_THREADS */ :} : :static void pool_destroy_debug(apr_pool_t *pool, const char *file_line) :{ : apr_pool_check_integrity(pool); : :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) : apr_pool_log_event(pool, "DESTROY", file_line, 1); :#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) */ : : pool_clear_debug(pool, file_line); : : /* Remove the pool from the parents child list */ : if (pool->parent) { :#if APR_HAS_THREADS : apr_thread_mutex_t *mutex; : : if ((mutex = pool->parent->mutex) != NULL) : apr_thread_mutex_lock(mutex); :#endif /* APR_HAS_THREADS */ : : if ((*pool->ref = pool->sibling) != NULL) : pool->sibling->ref = pool->ref; : :#if APR_HAS_THREADS : if (mutex) : apr_thread_mutex_unlock(mutex); :#endif /* APR_HAS_THREADS */ : } : : if (pool->allocator != NULL : && apr_allocator_owner_get(pool->allocator) == pool) { : apr_allocator_destroy(pool->allocator); : } : : /* Free the pool itself */ : free(pool); :} : :APR_DECLARE(void) apr_pool_destroy_debug(apr_pool_t *pool, : const char *file_line) :{ : if (pool->joined) { : /* Joined pools must not be explicitly destroyed; the caller : * has broken the guarantee. */ :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) : apr_pool_log_event(pool, "LIFE", : __FILE__ ":apr_pool_destroy abort on joined", 0); :#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE_ALL) */ : : abort(); : } : pool_destroy_debug(pool, file_line); :} : :APR_DECLARE(apr_status_t) apr_pool_create_ex_debug(apr_pool_t **newpool, : apr_pool_t *parent, : apr_abortfunc_t abort_fn, : apr_allocator_t *allocator, : const char *file_line) :{ : apr_pool_t *pool; : : *newpool = NULL; : : if (!parent) { : parent = global_pool; : } : else { : apr_pool_check_integrity(parent); : : if (!allocator) : allocator = parent->allocator; : } : : if (!abort_fn && parent) : abort_fn = parent->abort_fn; : : if ((pool = malloc(SIZEOF_POOL_T)) == NULL) { : if (abort_fn) : abort_fn(APR_ENOMEM); : : return APR_ENOMEM; : } : : memset(pool, 0, SIZEOF_POOL_T); : : pool->allocator = allocator; : pool->abort_fn = abort_fn; : pool->tag = file_line; : pool->file_line = file_line; : : if ((pool->parent = parent) != NULL) { :#if APR_HAS_THREADS : if (parent->mutex) : apr_thread_mutex_lock(parent->mutex); :#endif /* APR_HAS_THREADS */ : if ((pool->sibling = parent->child) != NULL) : pool->sibling->ref = &pool->sibling; : : parent->child = pool; : pool->ref = &parent->child; : :#if APR_HAS_THREADS : if (parent->mutex) : apr_thread_mutex_unlock(parent->mutex); :#endif /* APR_HAS_THREADS */ : } : else { : pool->sibling = NULL; : pool->ref = NULL; : } : :#if APR_HAS_THREADS : pool->owner = apr_os_thread_current(); :#endif /* APR_HAS_THREADS */ :#ifdef NETWARE : pool->owner_proc = (apr_os_proc_t)getnlmhandle(); :#endif /* defined(NETWARE) */ : : : if (parent == NULL || parent->allocator != allocator) { :#if APR_HAS_THREADS : apr_status_t rv; : : /* No matter what the creation flags say, always create : * a lock. Without it integrity_check and apr_pool_num_bytes : * blow up (because they traverse pools child lists that : * possibly belong to another thread, in combination with : * the pool having no lock). However, this might actually : * hide problems like creating a child pool of a pool : * belonging to another thread. : */ : if ((rv = apr_thread_mutex_create(&pool->mutex, : APR_THREAD_MUTEX_NESTED, pool)) != APR_SUCCESS) { : free(pool); : return rv; : } :#endif /* APR_HAS_THREADS */ : } : else { :#if APR_HAS_THREADS : if (parent) : pool->mutex = parent->mutex; :#endif /* APR_HAS_THREADS */ : } : : *newpool = pool; : :#if (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) : apr_pool_log_event(pool, "CREATE", file_line, 1); :#endif /* (APR_POOL_DEBUG & APR_POOL_DEBUG_VERBOSE) */ : : return APR_SUCCESS; :} : : :/* : * "Print" functions (debug) : */ : :struct psprintf_data { : apr_vformatter_buff_t vbuff; : char *mem; : apr_size_t size; :}; : :static int psprintf_flush(apr_vformatter_buff_t *vbuff) :{ : struct psprintf_data *ps = (struct psprintf_data *)vbuff; : apr_size_t size; : : size = ps->vbuff.curpos - ps->mem; : : ps->size <<= 1; : if ((ps->mem = realloc(ps->mem, ps->size)) == NULL) : return -1; : : ps->vbuff.curpos = ps->mem + size; : ps->vbuff.endpos = ps->mem + ps->size - 1; : : return 0; :} : :APR_DECLARE(char *) apr_pvsprintf(apr_pool_t *pool, const char *fmt, va_list ap) :{ : struct psprintf_data ps; : debug_node_t *node; : : apr_pool_check_integrity(pool); : : ps.size = 64; : ps.mem = malloc(ps.size); : ps.vbuff.curpos = ps.mem; : : /* Save a byte for the NUL terminator */ : ps.vbuff.endpos = ps.mem + ps.size - 1; : : if (apr_vformatter(psprintf_flush, &ps.vbuff, fmt, ap) == -1) { : if (pool->abort_fn) : pool->abort_fn(APR_ENOMEM); : : return NULL; : } : : *ps.vbuff.curpos++ = '\0'; : : /* : * Link the node in : */ : node = pool->nodes; : if (node == NULL || node->index == 64) { : if ((node = malloc(SIZEOF_DEBUG_NODE_T)) == NULL) { : if (pool->abort_fn) : pool->abort_fn(APR_ENOMEM); : : return NULL; : } : : node->next = pool->nodes; : pool->nodes = node; : node->index = 0; : } : : node->beginp[node->index] = ps.mem; : node->endp[node->index] = ps.mem + ps.size; : node->index++; : : return ps.mem; :} : : :/* : * Debug functions : */ : :APR_DECLARE(void) apr_pool_join(apr_pool_t *p, apr_pool_t *sub) :{ :#if APR_POOL_DEBUG : if (sub->parent != p) { : abort(); : } : sub->joined = p; :#endif :} : :static int pool_find(apr_pool_t *pool, void *data) :{ : void **pmem = (void **)data; : debug_node_t *node; : apr_uint32_t index; : : node = pool->nodes; : : while (node) { : for (index = 0; index < node->index; index++) { : if (node->beginp[index] <= *pmem : && node->endp[index] > *pmem) { : *pmem = pool; : return 1; : } : } : : node = node->next; : } : : return 0; :} : :APR_DECLARE(apr_pool_t *) apr_pool_find(const void *mem) :{ : void *pool = (void *)mem; : : if (apr_pool_walk_tree(global_pool, pool_find, &pool)) : return pool; : : return NULL; :} : :static int pool_num_bytes(apr_pool_t *pool, void *data) :{ : apr_size_t *psize = (apr_size_t *)data; : debug_node_t *node; : apr_uint32_t index; : : node = pool->nodes; : : while (node) { : for (index = 0; index < node->index; index++) { : *psize += (char *)node->endp[index] - (char *)node->beginp[index]; : } : : node = node->next; : } : : return 0; :} : :APR_DECLARE(apr_size_t) apr_pool_num_bytes(apr_pool_t *pool, int recurse) :{ : apr_size_t size = 0; : : if (!recurse) { : pool_num_bytes(pool, &size); : : return size; : } : : apr_pool_walk_tree(pool, pool_num_bytes, &size); : : return size; :} : :APR_DECLARE(void) apr_pool_lock(apr_pool_t *pool, int flag) :{ :} : :#endif /* !APR_POOL_DEBUG */ : :#ifdef NETWARE :void netware_pool_proc_cleanup () :{ : apr_pool_t *pool = global_pool->child; : apr_os_proc_t owner_proc = (apr_os_proc_t)getnlmhandle(); : : while (pool) { : if (pool->owner_proc == owner_proc) { : apr_pool_destroy (pool); : pool = global_pool->child; : } : else { : pool = pool->sibling; : } : } : return; :} :#endif /* defined(NETWARE) */ : : :/* : * "Print" functions (common) : */ : :APR_DECLARE_NONSTD(char *) apr_psprintf(apr_pool_t *p, const char *fmt, ...) :{ : va_list ap; : char *res; : : va_start(ap, fmt); : res = apr_pvsprintf(p, fmt, ap); : va_end(ap); : return res; :} : :/* : * Pool Properties : */ : :APR_DECLARE(void) apr_pool_abort_set(apr_abortfunc_t abort_fn, : apr_pool_t *pool) :{ : pool->abort_fn = abort_fn; :} : :APR_DECLARE(apr_abortfunc_t) apr_pool_abort_get(apr_pool_t *pool) :{ : return pool->abort_fn; :} : :APR_DECLARE(apr_pool_t *) apr_pool_parent_get(apr_pool_t *pool) :{ :#ifdef NETWARE : /* On NetWare, don't return the global_pool, return the application pool : as the top most pool */ : if (pool->parent == global_pool) : return NULL; : else :#endif : return pool->parent; :} : :APR_DECLARE(apr_allocator_t *) apr_pool_allocator_get(apr_pool_t *pool) :{ : return pool->allocator; :} : :/* return TRUE if a is an ancestor of b : * NULL is considered an ancestor of all pools : */ :APR_DECLARE(int) apr_pool_is_ancestor(apr_pool_t *a, apr_pool_t *b) :{ : if (a == NULL) : return 1; : :#if APR_POOL_DEBUG : /* Find the pool with the longest lifetime guaranteed by the : * caller: */ : while (a->joined) { : a = a->joined; : } :#endif : : while (b) { : if (a == b) : return 1; : : b = b->parent; : } : : return 0; :} : :APR_DECLARE(void) apr_pool_tag(apr_pool_t *pool, const char *tag) :{ : pool->tag = tag; :} : : :/* : * User data management : */ : :APR_DECLARE(apr_status_t) apr_pool_userdata_set(const void *data, const char *key, : apr_status_t (*cleanup) (void *), : apr_pool_t *pool) :{ :#if APR_POOL_DEBUG : apr_pool_check_integrity(pool); :#endif /* APR_POOL_DEBUG */ : : if (pool->user_data == NULL) : pool->user_data = apr_hash_make(pool); : : if (apr_hash_get(pool->user_data, key, APR_HASH_KEY_STRING) == NULL) { : char *new_key = apr_pstrdup(pool, key); : apr_hash_set(pool->user_data, new_key, APR_HASH_KEY_STRING, data); : } : else { : apr_hash_set(pool->user_data, key, APR_HASH_KEY_STRING, data); : } : : if (cleanup) : apr_pool_cleanup_register(pool, data, cleanup, cleanup); : : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_pool_userdata_setn(const void *data, : const char *key, : apr_status_t (*cleanup)(void *), : apr_pool_t *pool) :{ :#if APR_POOL_DEBUG : apr_pool_check_integrity(pool); :#endif /* APR_POOL_DEBUG */ : : if (pool->user_data == NULL) : pool->user_data = apr_hash_make(pool); : : apr_hash_set(pool->user_data, key, APR_HASH_KEY_STRING, data); : : if (cleanup) : apr_pool_cleanup_register(pool, data, cleanup, cleanup); : : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_pool_userdata_get(void **data, const char *key, : apr_pool_t *pool) :{ :#if APR_POOL_DEBUG : apr_pool_check_integrity(pool); :#endif /* APR_POOL_DEBUG */ : : if (pool->user_data == NULL) { : *data = NULL; : } : else { : *data = apr_hash_get(pool->user_data, key, APR_HASH_KEY_STRING); : } : : return APR_SUCCESS; :} : : :/* : * Cleanup : */ : :struct cleanup_t { : struct cleanup_t *next; : const void *data; : apr_status_t (*plain_cleanup_fn)(void *data); : apr_status_t (*child_cleanup_fn)(void *data); :}; : :APR_DECLARE(void) apr_pool_cleanup_register(apr_pool_t *p, const void *data, : apr_status_t (*plain_cleanup_fn)(void *data), : apr_status_t (*child_cleanup_fn)(void *data)) 5 0.0087 :{ /* apr_pool_cleanup_register total: 6 0.0104 */ : cleanup_t *c; : :#if APR_POOL_DEBUG : apr_pool_check_integrity(p); :#endif /* APR_POOL_DEBUG */ : : if (p != NULL) { : if (p->free_cleanups) { : /* reuse a cleanup structure */ : c = p->free_cleanups; : p->free_cleanups = c->next; : } else { 1 0.0017 : c = apr_palloc(p, sizeof(cleanup_t)); : } : c->data = data; : c->plain_cleanup_fn = plain_cleanup_fn; : c->child_cleanup_fn = child_cleanup_fn; : c->next = p->cleanups; : p->cleanups = c; : } :} : :APR_DECLARE(void) apr_pool_cleanup_kill(apr_pool_t *p, const void *data, : apr_status_t (*cleanup_fn)(void *)) :{ : cleanup_t *c, **lastp; : :#if APR_POOL_DEBUG : apr_pool_check_integrity(p); :#endif /* APR_POOL_DEBUG */ : 1 0.0017 : if (p == NULL) /* apr_pool_cleanup_kill total: 2 0.0035 */ : return; : : c = p->cleanups; : lastp = &p->cleanups; : while (c) { 1 0.0017 : if (c->data == data && c->plain_cleanup_fn == cleanup_fn) { : *lastp = c->next; : /* move to freelist */ : c->next = p->free_cleanups; : p->free_cleanups = c; : break; : } : : lastp = &c->next; : c = c->next; : } :} : :APR_DECLARE(void) apr_pool_child_cleanup_set(apr_pool_t *p, const void *data, : apr_status_t (*plain_cleanup_fn)(void *), : apr_status_t (*child_cleanup_fn)(void *)) :{ : cleanup_t *c; : :#if APR_POOL_DEBUG : apr_pool_check_integrity(p); :#endif /* APR_POOL_DEBUG */ : : if (p == NULL) : return; : : c = p->cleanups; : while (c) { : if (c->data == data && c->plain_cleanup_fn == plain_cleanup_fn) { : c->child_cleanup_fn = child_cleanup_fn; : break; : } : : c = c->next; : } :} : :APR_DECLARE(apr_status_t) apr_pool_cleanup_run(apr_pool_t *p, void *data, : apr_status_t (*cleanup_fn)(void *)) :{ /* apr_pool_cleanup_run total: 1 0.0017 */ : apr_pool_cleanup_kill(p, data, cleanup_fn); 1 0.0017 : return (*cleanup_fn)(data); :} : :static void run_cleanups(cleanup_t **cref) :{ /* run_cleanups total: 2 0.0035 */ : cleanup_t *c = *cref; : : while (c) { : *cref = c->next; : (*c->plain_cleanup_fn)((void *)c->data); : c = *cref; : } 2 0.0035 :} : :static void run_child_cleanups(cleanup_t **cref) :{ : cleanup_t *c = *cref; : : while (c) { : *cref = c->next; : (*c->child_cleanup_fn)((void *)c->data); : c = *cref; : } :} : :static void cleanup_pool_for_exec(apr_pool_t *p) :{ : run_child_cleanups(&p->cleanups); : : for (p = p->child; p; p = p->sibling) : cleanup_pool_for_exec(p); :} : :APR_DECLARE(void) apr_pool_cleanup_for_exec(void) :{ :#if !defined(WIN32) && !defined(OS2) : /* : * Don't need to do anything on NT or OS/2, because I : * am actually going to spawn the new process - not : * exec it. All handles that are not inheritable, will : * be automajically closed. The only problem is with : * file handles that are open, but there isn't much : * I can do about that (except if the child decides : * to go out and close them : */ : cleanup_pool_for_exec(global_pool); :#endif /* !defined(WIN32) && !defined(OS2) */ :} : :APR_DECLARE_NONSTD(apr_status_t) apr_pool_cleanup_null(void *data) :{ : /* do nothing cleanup routine */ : return APR_SUCCESS; :} : :/* Subprocesses don't use the generic cleanup interface because : * we don't want multiple subprocesses to result in multiple : * three-second pauses; the subprocesses have to be "freed" all : * at once. If other resources are introduced with the same property, : * we might want to fold support for that into the generic interface. : * For now, it's a special case. : */ :APR_DECLARE(void) apr_pool_note_subprocess(apr_pool_t *pool, apr_proc_t *proc, : apr_kill_conditions_e how) :{ : struct process_chain *pc = apr_palloc(pool, sizeof(struct process_chain)); : : pc->proc = proc; : pc->kill_how = how; : pc->next = pool->subprocesses; : pool->subprocesses = pc; :} : :static void free_proc_chain(struct process_chain *procs) :{ : /* Dispose of the subprocesses we've spawned off in the course of : * whatever it was we're cleaning up now. This may involve killing : * some of them off... : */ : struct process_chain *pc; : int need_timeout = 0; : apr_time_t timeout_interval; : : if (!procs) : return; /* No work. Whew! */ : : /* First, check to see if we need to do the SIGTERM, sleep, SIGKILL : * dance with any of the processes we're cleaning up. If we've got : * any kill-on-sight subprocesses, ditch them now as well, so they : * don't waste any more cycles doing whatever it is that they shouldn't : * be doing anymore. : */ : :#ifndef NEED_WAITPID : /* Pick up all defunct processes */ : for (pc = procs; pc; pc = pc->next) { : if (apr_proc_wait(pc->proc, NULL, NULL, APR_NOWAIT) != APR_CHILD_NOTDONE) : pc->kill_how = APR_KILL_NEVER; : } :#endif /* !defined(NEED_WAITPID) */ : : for (pc = procs; pc; pc = pc->next) { :#ifndef WIN32 : if ((pc->kill_how == APR_KILL_AFTER_TIMEOUT) : || (pc->kill_how == APR_KILL_ONLY_ONCE)) { : /* : * Subprocess may be dead already. Only need the timeout if not. : * Note: apr_proc_kill on Windows is TerminateProcess(), which is : * similar to a SIGKILL, so always give the process a timeout : * under Windows before killing it. : */ : if (apr_proc_kill(pc->proc, SIGTERM) == APR_SUCCESS) : need_timeout = 1; : } : else if (pc->kill_how == APR_KILL_ALWAYS) { :#else /* WIN32 knows only one fast, clean method of killing processes today */ : if (pc->kill_how != APR_KILL_NEVER) { : need_timeout = 1; : pc->kill_how = APR_KILL_ALWAYS; :#endif : apr_proc_kill(pc->proc, SIGKILL); : } : } : : /* Sleep only if we have to. The sleep algorithm grows : * by a factor of two on each iteration. TIMEOUT_INTERVAL : * is equal to TIMEOUT_USECS / 64. : */ : if (need_timeout) { : timeout_interval = TIMEOUT_INTERVAL; : apr_sleep(timeout_interval); : : do { : /* check the status of the subprocesses */ : need_timeout = 0; : for (pc = procs; pc; pc = pc->next) { : if (pc->kill_how == APR_KILL_AFTER_TIMEOUT) { : if (apr_proc_wait(pc->proc, NULL, NULL, APR_NOWAIT) : == APR_CHILD_NOTDONE) : need_timeout = 1; /* subprocess is still active */ : else : pc->kill_how = APR_KILL_NEVER; /* subprocess has exited */ : } : } : if (need_timeout) { : if (timeout_interval >= TIMEOUT_USECS) { : break; : } : apr_sleep(timeout_interval); : timeout_interval *= 2; : } : } while (need_timeout); : } : : /* OK, the scripts we just timed out for have had a chance to clean up : * --- now, just get rid of them, and also clean up the system accounting : * goop... : */ : for (pc = procs; pc; pc = pc->next) { : if (pc->kill_how == APR_KILL_AFTER_TIMEOUT) : apr_proc_kill(pc->proc, SIGKILL); : } : : /* Now wait for all the signaled processes to die */ : for (pc = procs; pc; pc = pc->next) { : if (pc->kill_how != APR_KILL_NEVER) : (void)apr_proc_wait(pc->proc, NULL, NULL, APR_WAIT); : } :} : : :/* : * Pool creation/destruction stubs, for people who are running : * mixed release/debug enviroments. : */ : :#if !APR_POOL_DEBUG :APR_DECLARE(void *) apr_palloc_debug(apr_pool_t *pool, apr_size_t size, : const char *file_line) :{ : return apr_palloc(pool, size); :} : :APR_DECLARE(void *) apr_pcalloc_debug(apr_pool_t *pool, apr_size_t size, : const char *file_line) :{ : return apr_pcalloc(pool, size); :} : :APR_DECLARE(void) apr_pool_clear_debug(apr_pool_t *pool, : const char *file_line) :{ : apr_pool_clear(pool); :} : :APR_DECLARE(void) apr_pool_destroy_debug(apr_pool_t *pool, : const char *file_line) :{ : apr_pool_destroy(pool); :} : :APR_DECLARE(apr_status_t) apr_pool_create_ex_debug(apr_pool_t **newpool, : apr_pool_t *parent, : apr_abortfunc_t abort_fn, : apr_allocator_t *allocator, : const char *file_line) :{ : return apr_pool_create_ex(newpool, parent, abort_fn, allocator); :} : :#else /* APR_POOL_DEBUG */ : :#undef apr_palloc :APR_DECLARE(void *) apr_palloc(apr_pool_t *pool, apr_size_t size); : :APR_DECLARE(void *) apr_palloc(apr_pool_t *pool, apr_size_t size) :{ : return apr_palloc_debug(pool, size, "undefined"); :} : :#undef apr_pcalloc :APR_DECLARE(void *) apr_pcalloc(apr_pool_t *pool, apr_size_t size); : :APR_DECLARE(void *) apr_pcalloc(apr_pool_t *pool, apr_size_t size) :{ : return apr_pcalloc_debug(pool, size, "undefined"); :} : :#undef apr_pool_clear :APR_DECLARE(void) apr_pool_clear(apr_pool_t *pool); : :APR_DECLARE(void) apr_pool_clear(apr_pool_t *pool) :{ : apr_pool_clear_debug(pool, "undefined"); :} : :#undef apr_pool_destroy :APR_DECLARE(void) apr_pool_destroy(apr_pool_t *pool); : :APR_DECLARE(void) apr_pool_destroy(apr_pool_t *pool) :{ : apr_pool_destroy_debug(pool, "undefined"); :} : :#undef apr_pool_create_ex :APR_DECLARE(apr_status_t) apr_pool_create_ex(apr_pool_t **newpool, : apr_pool_t *parent, : apr_abortfunc_t abort_fn, : apr_allocator_t *allocator); : :APR_DECLARE(apr_status_t) apr_pool_create_ex(apr_pool_t **newpool, : apr_pool_t *parent, : apr_abortfunc_t abort_fn, : apr_allocator_t *allocator) :{ : return apr_pool_create_ex_debug(newpool, parent, : abort_fn, allocator, : "undefined"); :} : :#endif /* APR_POOL_DEBUG */ /* * Total samples for file : "time/unix/timestr.c" * * 32 0.0557 */ :/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as : * applicable. : * : * Licensed 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. : */ : :#include "apr_portable.h" :#include "apr_time.h" :#include "apr_lib.h" :#include "apr_private.h" :/* System Headers required for time library */ :#if APR_HAVE_SYS_TIME_H :#include :#endif :#ifdef HAVE_TIME_H :#include :#endif :#if APR_HAVE_STRING_H :#include :#endif :/* End System Headers */ : :APR_DECLARE_DATA const char apr_month_snames[12][4] = :{ : "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" :}; :APR_DECLARE_DATA const char apr_day_snames[7][4] = :{ : "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" :}; : :apr_status_t apr_rfc822_date(char *date_str, apr_time_t t) 2 0.0035 :{ /* apr_rfc822_date total: 18 0.0313 */ : apr_time_exp_t xt; : const char *s; : int real_year; : : apr_time_exp_gmt(&xt, t); : : /* example: "Sat, 08 Jan 2000 18:31:41 GMT" */ : /* 12345678901234567890123456789 */ : : s = &apr_day_snames[xt.tm_wday][0]; : *date_str++ = *s++; : *date_str++ = *s++; : *date_str++ = *s++; : *date_str++ = ','; : *date_str++ = ' '; : *date_str++ = xt.tm_mday / 10 + '0'; 2 0.0035 : *date_str++ = xt.tm_mday % 10 + '0'; : *date_str++ = ' '; 2 0.0035 : s = &apr_month_snames[xt.tm_mon][0]; : *date_str++ = *s++; : *date_str++ = *s++; : *date_str++ = *s++; : *date_str++ = ' '; : real_year = 1900 + xt.tm_year; : /* This routine isn't y10k ready. */ : *date_str++ = real_year / 1000 + '0'; 4 0.0070 : *date_str++ = real_year % 1000 / 100 + '0'; 1 0.0017 : *date_str++ = real_year % 100 / 10 + '0'; : *date_str++ = real_year % 10 + '0'; : *date_str++ = ' '; : *date_str++ = xt.tm_hour / 10 + '0'; 3 0.0052 : *date_str++ = xt.tm_hour % 10 + '0'; : *date_str++ = ':'; : *date_str++ = xt.tm_min / 10 + '0'; : *date_str++ = xt.tm_min % 10 + '0'; : *date_str++ = ':'; : *date_str++ = xt.tm_sec / 10 + '0'; : *date_str++ = xt.tm_sec % 10 + '0'; : *date_str++ = ' '; : *date_str++ = 'G'; : *date_str++ = 'M'; : *date_str++ = 'T'; 3 0.0052 : *date_str++ = 0; : return APR_SUCCESS; 1 0.0017 :} : :apr_status_t apr_ctime(char *date_str, apr_time_t t) :{ : apr_time_exp_t xt; : const char *s; : int real_year; : : /* example: "Wed Jun 30 21:49:08 1993" */ : /* 123456789012345678901234 */ : : apr_time_exp_lt(&xt, t); : s = &apr_day_snames[xt.tm_wday][0]; : *date_str++ = *s++; : *date_str++ = *s++; : *date_str++ = *s++; : *date_str++ = ' '; : s = &apr_month_snames[xt.tm_mon][0]; : *date_str++ = *s++; : *date_str++ = *s++; : *date_str++ = *s++; : *date_str++ = ' '; : *date_str++ = xt.tm_mday / 10 + '0'; : *date_str++ = xt.tm_mday % 10 + '0'; : *date_str++ = ' '; : *date_str++ = xt.tm_hour / 10 + '0'; : *date_str++ = xt.tm_hour % 10 + '0'; : *date_str++ = ':'; : *date_str++ = xt.tm_min / 10 + '0'; : *date_str++ = xt.tm_min % 10 + '0'; : *date_str++ = ':'; : *date_str++ = xt.tm_sec / 10 + '0'; : *date_str++ = xt.tm_sec % 10 + '0'; : *date_str++ = ' '; : real_year = 1900 + xt.tm_year; : *date_str++ = real_year / 1000 + '0'; : *date_str++ = real_year % 1000 / 100 + '0'; : *date_str++ = real_year % 100 / 10 + '0'; : *date_str++ = real_year % 10 + '0'; : *date_str++ = 0; : : return APR_SUCCESS; :} : :apr_status_t apr_strftime(char *s, apr_size_t *retsize, apr_size_t max, : const char *format, apr_time_exp_t *xt) 3 0.0052 :{ /* apr_strftime total: 14 0.0244 */ : struct tm tm; 3 0.0052 : memset(&tm, 0, sizeof tm); : tm.tm_sec = xt->tm_sec; 1 0.0017 : tm.tm_min = xt->tm_min; : tm.tm_hour = xt->tm_hour; : tm.tm_mday = xt->tm_mday; : tm.tm_mon = xt->tm_mon; : tm.tm_year = xt->tm_year; : tm.tm_wday = xt->tm_wday; : tm.tm_yday = xt->tm_yday; 1 0.0017 : tm.tm_isdst = xt->tm_isdst; :#if defined(HAVE_STRUCT_TM_TM_GMTOFF) : tm.tm_gmtoff = xt->tm_gmtoff; :#elif defined(HAVE_STRUCT_TM___TM_GMTOFF) : tm.__tm_gmtoff = xt->tm_gmtoff; :#endif : (*retsize) = strftime(s, max, format, &tm); : return APR_SUCCESS; 6 0.0104 :} /* * Total samples for file : "network_io/unix/sockets.c" * * 21 0.0366 */ :/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as : * applicable. : * : * Licensed 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. : */ : :#include "apr_arch_networkio.h" :#include "apr_network_io.h" :#include "apr_strings.h" :#include "apr_support.h" :#include "apr_portable.h" :#include "apr_arch_inherit.h" : :#ifdef BEOS_R5 :#undef close :#define close closesocket :#endif /* BEOS_R5 */ : :static char generic_inaddr_any[16] = {0}; /* big enough for IPv4 or IPv6 */ : :static apr_status_t socket_cleanup(void *sock) :{ /* socket_cleanup total: 2 0.0035 */ : apr_socket_t *thesocket = sock; : 2 0.0035 : apr_socket_shutdown(thesocket, APR_SHUTDOWN_READWRITE); : : if (close(thesocket->socketdes) == 0) { : thesocket->socketdes = -1; : return APR_SUCCESS; : } : else { : return errno; : } :} : :static void set_socket_vars(apr_socket_t *sock, int family, int type, int protocol) 3 0.0052 :{ /* set_socket_vars total: 3 0.0052 */ : sock->type = type; : sock->protocol = protocol; : apr_sockaddr_vars_set(sock->local_addr, family, 0); : apr_sockaddr_vars_set(sock->remote_addr, family, 0); : sock->options = 0; :#if defined(BEOS) && !defined(BEOS_BONE) : /* BeOS pre-BONE has TCP_NODELAY on by default and it can't be : * switched off! : */ : sock->options |= APR_TCP_NODELAY; :#endif :} : :static void alloc_socket(apr_socket_t **new, apr_pool_t *p) 3 0.0052 :{ /* alloc_socket total: 5 0.0087 */ 2 0.0035 : *new = (apr_socket_t *)apr_pcalloc(p, sizeof(apr_socket_t)); : (*new)->pool = p; : (*new)->local_addr = (apr_sockaddr_t *)apr_pcalloc((*new)->pool, : sizeof(apr_sockaddr_t)); : (*new)->local_addr->pool = p; : (*new)->remote_addr = (apr_sockaddr_t *)apr_pcalloc((*new)->pool, : sizeof(apr_sockaddr_t)); : (*new)->remote_addr->pool = p; : (*new)->remote_addr_unknown = 1; :#ifndef WAITIO_USES_POLL : /* Create a pollset with room for one descriptor. */ : /* ### check return codes */ : (void) apr_pollset_create(&(*new)->pollset, 1, p, 0); :#endif :} : :apr_status_t apr_socket_protocol_get(apr_socket_t *sock, int *protocol) :{ : *protocol = sock->protocol; : return APR_SUCCESS; :} : :apr_status_t apr_socket_create(apr_socket_t **new, int ofamily, int type, : int protocol, apr_pool_t *cont) 2 0.0035 :{ /* apr_socket_create total: 2 0.0035 */ : int family = ofamily; : : if (family == APR_UNSPEC) { :#if APR_HAVE_IPV6 : family = APR_INET6; :#else : family = APR_INET; :#endif : } : : alloc_socket(new, cont); : :#ifndef BEOS_R5 : (*new)->socketdes = socket(family, type, protocol); :#else : /* For some reason BeOS R5 has an unconventional protocol numbering, : * so we need to translate here. */ : switch (protocol) { : case 0: : (*new)->socketdes = socket(family, type, 0); : break; : case APR_PROTO_TCP: : (*new)->socketdes = socket(family, type, IPPROTO_TCP); : break; : case APR_PROTO_UDP: : (*new)->socketdes = socket(family, type, IPPROTO_UDP); : break; : case APR_PROTO_SCTP: : default: : errno = EPROTONOSUPPORT; : (*new)->socketdes = -1; : break; : } :#endif /* BEOS_R5 */ : :#if APR_HAVE_IPV6 : if ((*new)->socketdes < 0 && ofamily == APR_UNSPEC) { : family = APR_INET; : (*new)->socketdes = socket(family, type, protocol); : } :#endif : : if ((*new)->socketdes < 0) { : return errno; : } : set_socket_vars(*new, family, type, protocol); : : (*new)->timeout = -1; : (*new)->inherit = 0; : apr_pool_cleanup_register((*new)->pool, (void *)(*new), socket_cleanup, : socket_cleanup); : : return APR_SUCCESS; :} : :apr_status_t apr_socket_shutdown(apr_socket_t *thesocket, : apr_shutdown_how_e how) :{ /* apr_socket_shutdown total: 2 0.0035 */ 2 0.0035 : return (shutdown(thesocket->socketdes, how) == -1) ? errno : APR_SUCCESS; :} : :apr_status_t apr_socket_close(apr_socket_t *thesocket) :{ : return apr_pool_cleanup_run(thesocket->pool, thesocket, socket_cleanup); :} : :apr_status_t apr_socket_bind(apr_socket_t *sock, apr_sockaddr_t *sa) 6 0.0104 :{ /* apr_socket_bind total: 7 0.0122 */ : if (bind(sock->socketdes, : (struct sockaddr *)&sa->sa, sa->salen) == -1) { : return errno; : } : else { : sock->local_addr = sa; : /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */ : if (sock->local_addr->sa.sin.sin_port == 0) { /* no need for ntohs() when comparing w/ 0 */ : sock->local_port_unknown = 1; /* kernel got us an ephemeral port */ : } : return APR_SUCCESS; : } 1 0.0017 :} : :apr_status_t apr_socket_listen(apr_socket_t *sock, apr_int32_t backlog) :{ : if (listen(sock->socketdes, backlog) == -1) : return errno; : else : return APR_SUCCESS; :} : :apr_status_t apr_socket_accept(apr_socket_t **new, apr_socket_t *sock, : apr_pool_t *connection_context) :{ : alloc_socket(new, connection_context); : set_socket_vars(*new, sock->local_addr->sa.sin.sin_family, SOCK_STREAM, sock->protocol); : :#ifndef HAVE_POLL : (*new)->connected = 1; :#endif : (*new)->timeout = -1; : : (*new)->socketdes = accept(sock->socketdes, : (struct sockaddr *)&(*new)->remote_addr->sa, : &(*new)->remote_addr->salen); : : if ((*new)->socketdes < 0) { : return errno; : } :#ifdef TPF : if ((*new)->socketdes == 0) { : /* 0 is an invalid socket for TPF */ : return APR_EINTR; : } :#endif : : (*new)->remote_addr_unknown = 0; : : *(*new)->local_addr = *sock->local_addr; : : /* The above assignment just overwrote the pool entry. Setting the local_addr : pool for the accepted socket back to what it should be. Otherwise all : allocations for this socket will come from a server pool that is not : freed until the process goes down.*/ : (*new)->local_addr->pool = connection_context; : : /* fix up any pointers which are no longer valid */ : if (sock->local_addr->sa.sin.sin_family == AF_INET) { : (*new)->local_addr->ipaddr_ptr = &(*new)->local_addr->sa.sin.sin_addr; : } :#if APR_HAVE_IPV6 : else if (sock->local_addr->sa.sin.sin_family == AF_INET6) { : (*new)->local_addr->ipaddr_ptr = &(*new)->local_addr->sa.sin6.sin6_addr; : } :#endif : (*new)->remote_addr->port = ntohs((*new)->remote_addr->sa.sin.sin_port); : if (sock->local_port_unknown) { : /* not likely for a listening socket, but theoretically possible :) */ : (*new)->local_port_unknown = 1; : } : :#if APR_TCP_NODELAY_INHERITED : if (apr_is_option_set(sock, APR_TCP_NODELAY) == 1) { : apr_set_option(*new, APR_TCP_NODELAY, 1); : } :#endif /* TCP_NODELAY_INHERITED */ :#if APR_O_NONBLOCK_INHERITED : if (apr_is_option_set(sock, APR_SO_NONBLOCK) == 1) { : apr_set_option(*new, APR_SO_NONBLOCK, 1); : } :#endif /* APR_O_NONBLOCK_INHERITED */ : : if (sock->local_interface_unknown || : !memcmp(sock->local_addr->ipaddr_ptr, : generic_inaddr_any, : sock->local_addr->ipaddr_len)) { : /* If the interface address inside the listening socket's local_addr wasn't : * up-to-date, we don't know local interface of the connected socket either. : * : * If the listening socket was not bound to a specific interface, we : * don't know the local_addr of the connected socket. : */ : (*new)->local_interface_unknown = 1; : } : : (*new)->inherit = 0; : apr_pool_cleanup_register((*new)->pool, (void *)(*new), socket_cleanup, : socket_cleanup); : return APR_SUCCESS; :} : :apr_status_t apr_socket_connect(apr_socket_t *sock, apr_sockaddr_t *sa) :{ : int rc; : : do { : rc = connect(sock->socketdes, : (const struct sockaddr *)&sa->sa.sin, : sa->salen); : } while (rc == -1 && errno == EINTR); : : /* we can see EINPROGRESS the first time connect is called on a non-blocking : * socket; if called again, we can see EALREADY : */ : if ((rc == -1) && (errno == EINPROGRESS || errno == EALREADY) : && (sock->timeout > 0)) { : rc = apr_wait_for_io_or_timeout(NULL, sock, 0); : if (rc != APR_SUCCESS) { : return rc; : } : :#ifdef SO_ERROR : { : int error; : apr_socklen_t len = sizeof(error); : if ((rc = getsockopt(sock->socketdes, SOL_SOCKET, SO_ERROR, : (char *)&error, &len)) < 0) { : return errno; : } : if (error) { : return error; : } : } :#endif /* SO_ERROR */ : } : : if (rc == -1 && errno != EISCONN) { : return errno; : } : : if (memcmp(sa->ipaddr_ptr, generic_inaddr_any, sa->ipaddr_len)) { : /* A real remote address was passed in. If the unspecified : * address was used, the actual remote addr will have to be : * determined using getpeername() if required. */ : /* ### this should probably be a structure copy + fixup as per : * _accept()'s handling of local_addr */ : sock->remote_addr = sa; : sock->remote_addr_unknown = 0; : } : : if (sock->local_addr->port == 0) { : /* connect() got us an ephemeral port */ : sock->local_port_unknown = 1; : } : if (!memcmp(sock->local_addr->ipaddr_ptr, : generic_inaddr_any, : sock->local_addr->ipaddr_len)) { : /* not bound to specific local interface; connect() had to assign : * one for the socket : */ : sock->local_interface_unknown = 1; : } :#ifndef HAVE_POLL : sock->connected=1; :#endif : return APR_SUCCESS; :} : :apr_status_t apr_socket_type_get(apr_socket_t *sock, int *type) :{ : *type = sock->type; : return APR_SUCCESS; :} : :apr_status_t apr_socket_data_get(void **data, const char *key, apr_socket_t *sock) :{ : sock_userdata_t *cur = sock->userdata; : : *data = NULL; : : while (cur) { : if (!strcmp(cur->key, key)) { : *data = cur->data; : break; : } : cur = cur->next; : } : : return APR_SUCCESS; :} : :apr_status_t apr_socket_data_set(apr_socket_t *sock, void *data, const char *key, : apr_status_t (*cleanup) (void *)) :{ : sock_userdata_t *new = apr_palloc(sock->pool, sizeof(sock_userdata_t)); : : new->key = apr_pstrdup(sock->pool, key); : new->data = data; : new->next = sock->userdata; : sock->userdata = new; : : if (cleanup) { : apr_pool_cleanup_register(sock->pool, data, cleanup, cleanup); : } : : return APR_SUCCESS; :} : :apr_status_t apr_os_sock_get(apr_os_sock_t *thesock, apr_socket_t *sock) :{ : *thesock = sock->socketdes; : return APR_SUCCESS; :} : :apr_status_t apr_os_sock_make(apr_socket_t **apr_sock, : apr_os_sock_info_t *os_sock_info, : apr_pool_t *cont) :{ : alloc_socket(apr_sock, cont); : set_socket_vars(*apr_sock, os_sock_info->family, os_sock_info->type, os_sock_info->protocol); : (*apr_sock)->timeout = -1; : (*apr_sock)->socketdes = *os_sock_info->os_sock; : if (os_sock_info->local) { : memcpy(&(*apr_sock)->local_addr->sa.sin, : os_sock_info->local, : (*apr_sock)->local_addr->salen); : /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */ : (*apr_sock)->local_addr->port = ntohs((*apr_sock)->local_addr->sa.sin.sin_port); : } : else { : (*apr_sock)->local_port_unknown = (*apr_sock)->local_interface_unknown = 1; : } : if (os_sock_info->remote) { :#ifndef HAVE_POLL : (*apr_sock)->connected = 1; :#endif : memcpy(&(*apr_sock)->remote_addr->sa.sin, : os_sock_info->remote, : (*apr_sock)->remote_addr->salen); : /* XXX IPv6 - this assumes sin_port and sin6_port at same offset */ : (*apr_sock)->remote_addr->port = ntohs((*apr_sock)->remote_addr->sa.sin.sin_port); : } : else { : (*apr_sock)->remote_addr_unknown = 1; : } : : (*apr_sock)->inherit = 0; : apr_pool_cleanup_register((*apr_sock)->pool, (void *)(*apr_sock), : socket_cleanup, socket_cleanup); : return APR_SUCCESS; :} : :apr_status_t apr_os_sock_put(apr_socket_t **sock, apr_os_sock_t *thesock, : apr_pool_t *cont) :{ : /* XXX Bogus assumption that *sock points at anything legit */ : if ((*sock) == NULL) { : alloc_socket(sock, cont); : /* XXX IPv6 figure out the family here! */ : /* XXX figure out the actual socket type here */ : /* *or* just decide that apr_os_sock_put() has to be told the family and type */ : set_socket_vars(*sock, APR_INET, SOCK_STREAM, 0); : (*sock)->timeout = -1; : } : (*sock)->local_port_unknown = (*sock)->local_interface_unknown = 1; : (*sock)->remote_addr_unknown = 1; : (*sock)->socketdes = *thesock; : return APR_SUCCESS; :} : :APR_POOL_IMPLEMENT_ACCESSOR(socket) : :APR_IMPLEMENT_INHERIT_SET(socket, inherit, pool, socket_cleanup) : :APR_IMPLEMENT_INHERIT_UNSET(socket, inherit, pool, socket_cleanup) /* * Total samples for file : "network_io/unix/sockaddr.c" * * 16 0.0279 */ :/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as : * applicable. : * : * Licensed 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. : */ : :#include "apr_arch_networkio.h" :#include "apr_strings.h" :#include "apr.h" :#include "apr_lib.h" :#include "apr_strings.h" :#include "apr_private.h" : :#if APR_HAVE_STDLIB_H :#include :#endif : :#define APR_WANT_STRFUNC :#include "apr_want.h" : :struct apr_ipsubnet_t { : int family; :#if APR_HAVE_IPV6 : apr_uint32_t sub[4]; /* big enough for IPv4 and IPv6 addresses */ : apr_uint32_t mask[4]; :#else : apr_uint32_t sub[1]; : apr_uint32_t mask[1]; :#endif :}; : :#if !defined(NETWARE) && !defined(WIN32) :#ifdef HAVE_SET_H_ERRNO :#define SET_H_ERRNO(newval) set_h_errno(newval) :#else :#define SET_H_ERRNO(newval) h_errno = (newval) :#endif :#else :#define SET_H_ERRNO(newval) :#endif : :#if APR_HAS_THREADS && !defined(GETHOSTBYNAME_IS_THREAD_SAFE) && \ : defined(HAVE_GETHOSTBYNAME_R) :/* This is the maximum size that may be returned from the reentrant : * gethostbyname_r function. If the system tries to use more, it : * should return ERANGE. : */ :#define GETHOSTBYNAME_BUFLEN 512 :#endif : :#ifdef _WIN32_WCE :/* XXX: BS solution. Need an HAVE_GETSERVBYNAME and actually : * do something here, to provide the obvious proto mappings. : */ :static void *getservbyname(const char *name, const char *proto) :{ : return NULL; :} :#endif : :static apr_status_t get_local_addr(apr_socket_t *sock) :{ : sock->local_addr->salen = sizeof(sock->local_addr->sa); : if (getsockname(sock->socketdes, (struct sockaddr *)&sock->local_addr->sa, : &sock->local_addr->salen) < 0) { : return apr_get_netos_error(); : } : else { : sock->local_port_unknown = sock->local_interface_unknown = 0; : /* XXX assumes sin_port and sin6_port at same offset */ : sock->local_addr->port = ntohs(sock->local_addr->sa.sin.sin_port); : return APR_SUCCESS; : } :} : :static apr_status_t get_remote_addr(apr_socket_t *sock) :{ : sock->remote_addr->salen = sizeof(sock->remote_addr->sa); : if (getpeername(sock->socketdes, (struct sockaddr *)&sock->remote_addr->sa, : &sock->remote_addr->salen) < 0) { : return apr_get_netos_error(); : } : else { : sock->remote_addr_unknown = 0; : /* XXX assumes sin_port and sin6_port at same offset */ : sock->remote_addr->port = ntohs(sock->remote_addr->sa.sin.sin_port); : return APR_SUCCESS; : } :} : :APR_DECLARE(apr_status_t) apr_sockaddr_ip_get(char **addr, : apr_sockaddr_t *sockaddr) :{ : *addr = apr_palloc(sockaddr->pool, sockaddr->addr_str_len); : apr_inet_ntop(sockaddr->family, : sockaddr->ipaddr_ptr, : *addr, : sockaddr->addr_str_len); :#if APR_HAVE_IPV6 : if (sockaddr->family == AF_INET6 && : IN6_IS_ADDR_V4MAPPED((struct in6_addr *)sockaddr->ipaddr_ptr)) { : /* This is an IPv4-mapped IPv6 address; drop the leading : * part of the address string so we're left with the familiar : * IPv4 format. : */ : *addr += strlen("::ffff:"); : } :#endif : return APR_SUCCESS; :} : :void apr_sockaddr_vars_set(apr_sockaddr_t *addr, int family, apr_port_t port) :{ : addr->family = family; : addr->sa.sin.sin_family = family; 2 0.0035 : if (port) { /* apr_sockaddr_vars_set total: 2 0.0035 */ : /* XXX IPv6: assumes sin_port and sin6_port at same offset */ : addr->sa.sin.sin_port = htons(port); : addr->port = port; : } : : if (family == APR_INET) { : addr->salen = sizeof(struct sockaddr_in); : addr->addr_str_len = 16; : addr->ipaddr_ptr = &(addr->sa.sin.sin_addr); : addr->ipaddr_len = sizeof(struct in_addr); : } :#if APR_HAVE_IPV6 : else if (family == APR_INET6) { : addr->salen = sizeof(struct sockaddr_in6); : addr->addr_str_len = 46; : addr->ipaddr_ptr = &(addr->sa.sin6.sin6_addr); : addr->ipaddr_len = sizeof(struct in6_addr); : } :#endif :} : :APR_DECLARE(apr_status_t) apr_socket_addr_get(apr_sockaddr_t **sa, : apr_interface_e which, : apr_socket_t *sock) :{ : if (which == APR_LOCAL) { : if (sock->local_interface_unknown || sock->local_port_unknown) { : apr_status_t rv = get_local_addr(sock); : : if (rv != APR_SUCCESS) { : return rv; : } : } : *sa = sock->local_addr; : } : else if (which == APR_REMOTE) { : if (sock->remote_addr_unknown) { : apr_status_t rv = get_remote_addr(sock); : : if (rv != APR_SUCCESS) { : return rv; : } : } : *sa = sock->remote_addr; : } : else { : *sa = NULL; : return APR_EINVAL; : } : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_parse_addr_port(char **addr, : char **scope_id, : apr_port_t *port, : const char *str, : apr_pool_t *p) :{ : const char *ch, *lastchar; : int big_port; : apr_size_t addrlen; : : *addr = NULL; /* assume not specified */ : *scope_id = NULL; /* assume not specified */ : *port = 0; /* assume not specified */ : : /* First handle the optional port number. That may be all that : * is specified in the string. : */ : ch = lastchar = str + strlen(str) - 1; : while (ch >= str && apr_isdigit(*ch)) { : --ch; : } : : if (ch < str) { /* Entire string is the port. */ : big_port = atoi(str); : if (big_port < 1 || big_port > 65535) { : return APR_EINVAL; : } : *port = big_port; : return APR_SUCCESS; : } : : if (*ch == ':' && ch < lastchar) { /* host and port number specified */ : if (ch == str) { /* string starts with ':' -- bad */ : return APR_EINVAL; : } : big_port = atoi(ch + 1); : if (big_port < 1 || big_port > 65535) { : return APR_EINVAL; : } : *port = big_port; : lastchar = ch - 1; : } : : /* now handle the hostname */ : addrlen = lastchar - str + 1; : :/* XXX we don't really have to require APR_HAVE_IPV6 for this; : * just pass char[] for ipaddr (so we don't depend on struct in6_addr) : * and always define APR_INET6 : */ :#if APR_HAVE_IPV6 : if (*str == '[') { : const char *end_bracket = memchr(str, ']', addrlen); : struct in6_addr ipaddr; : const char *scope_delim; : : if (!end_bracket || end_bracket != lastchar) { : *port = 0; : return APR_EINVAL; : } : : /* handle scope id; this is the only context where it is allowed */ : scope_delim = memchr(str, '%', addrlen); : if (scope_delim) { : if (scope_delim == end_bracket - 1) { /* '%' without scope id */ : *port = 0; : return APR_EINVAL; : } : addrlen = scope_delim - str - 1; : *scope_id = apr_palloc(p, end_bracket - scope_delim); : memcpy(*scope_id, scope_delim + 1, end_bracket - scope_delim - 1); : (*scope_id)[end_bracket - scope_delim - 1] = '\0'; : } : else { : addrlen = addrlen - 2; /* minus 2 for '[' and ']' */ : } : : *addr = apr_palloc(p, addrlen + 1); : memcpy(*addr, : str + 1, : addrlen); : (*addr)[addrlen] = '\0'; : if (apr_inet_pton(AF_INET6, *addr, &ipaddr) != 1) { : *addr = NULL; : *scope_id = NULL; : *port = 0; : return APR_EINVAL; : } : } : else :#endif : { : /* XXX If '%' is not a valid char in a DNS name, we *could* check : * for bogus scope ids first. : */ : *addr = apr_palloc(p, addrlen + 1); : memcpy(*addr, str, addrlen); : (*addr)[addrlen] = '\0'; : } : return APR_SUCCESS; :} : :#if defined(HAVE_GETADDRINFO) : :static apr_status_t call_resolver(apr_sockaddr_t **sa, : const char *hostname, apr_int32_t family, : apr_port_t port, apr_int32_t flags, : apr_pool_t *p) :{ /* call_resolver total: 6 0.0104 */ : struct addrinfo hints, *ai, *ai_list; : apr_sockaddr_t *prev_sa; : int error; : char *servname = NULL; : 1 0.0017 : memset(&hints, 0, sizeof(hints)); : hints.ai_family = family; : hints.ai_socktype = SOCK_STREAM; :#ifdef HAVE_GAI_ADDRCONFIG : if (family == APR_UNSPEC) { : /* By default, only look up addresses using address types for : * which a local interface is configured, i.e. no IPv6 if no : * IPv6 interfaces configured. */ : hints.ai_flags = AI_ADDRCONFIG; : } :#endif : if(hostname == NULL) { :#ifdef AI_PASSIVE : /* If hostname is NULL, assume we are trying to bind to all : * interfaces. */ 2 0.0035 : hints.ai_flags |= AI_PASSIVE; :#endif : /* getaddrinfo according to RFC 2553 must have either hostname : * or servname non-NULL. : */ :#ifdef OSF1 : /* The Tru64 5.0 getaddrinfo() can only resolve services given : * by the name listed in /etc/services; a numeric or unknown : * servname gets an EAI_SERVICE error. So just resolve the : * appropriate anyaddr and fill in the port later. */ : hostname = family == AF_INET6 ? "::" : "0.0.0.0"; : servname = NULL; :#ifdef AI_NUMERICHOST : hints.ai_flags |= AI_NUMERICHOST; :#endif :#else :#ifdef _AIX : /* But current AIX getaddrinfo() doesn't like servname = "0"; : * the "1" won't hurt since we use the port parameter to fill : * in the returned socket addresses later : */ : if (!port) { : servname = "1"; : } : else :#endif /* _AIX */ : servname = apr_itoa(p, port); :#endif /* OSF1 */ : } : error = getaddrinfo(hostname, servname, &hints, &ai_list); :#ifdef HAVE_GAI_ADDRCONFIG : if (error == EAI_BADFLAGS && family == APR_UNSPEC) { : /* Retry with no flags if AI_ADDRCONFIG was rejected. */ : hints.ai_flags = 0; : error = getaddrinfo(hostname, servname, &hints, &ai_list); : } :#endif : if (error) { :#ifndef WIN32 : if (error == EAI_SYSTEM) { : return errno; : } : else :#endif : { : /* issues with representing this with APR's error scheme: : * glibc uses negative values for these numbers, perhaps so : * they don't conflict with h_errno values... Tru64 uses : * positive values which conflict with h_errno values : */ :#if defined(NEGATIVE_EAI) : error = -error; :#endif : return error + APR_OS_START_EAIERR; : } : } : : prev_sa = NULL; : ai = ai_list; 2 0.0035 : while (ai) { /* while more addresses to report */ : apr_sockaddr_t *new_sa; : : /* Ignore anything bogus: getaddrinfo in some old versions of : * glibc will return AF_UNIX entries for APR_UNSPEC+AI_PASSIVE : * lookups. */ 1 0.0017 : if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) { : ai = ai->ai_next; : continue; : } : : new_sa = apr_pcalloc(p, sizeof(apr_sockaddr_t)); : : new_sa->pool = p; : memcpy(&new_sa->sa, ai->ai_addr, ai->ai_addrlen); : apr_sockaddr_vars_set(new_sa, ai->ai_family, port); : : if (!prev_sa) { /* first element in new list */ : if (hostname) { : new_sa->hostname = apr_pstrdup(p, hostname); : } : *sa = new_sa; : } : else { : new_sa->hostname = prev_sa->hostname; : prev_sa->next = new_sa; : } : : prev_sa = new_sa; : ai = ai->ai_next; : } : freeaddrinfo(ai_list); : return APR_SUCCESS; :} : :static apr_status_t find_addresses(apr_sockaddr_t **sa, : const char *hostname, apr_int32_t family, : apr_port_t port, apr_int32_t flags, : apr_pool_t *p) :{ 2 0.0035 : if (flags & APR_IPV4_ADDR_OK) { : apr_status_t error = call_resolver(sa, hostname, AF_INET, port, flags, p); : :#if APR_HAVE_IPV6 : if (error) { : family = AF_INET6; /* try again */ : } : else :#endif : return error; : } :#if APR_HAVE_IPV6 : else if (flags & APR_IPV6_ADDR_OK) { : apr_status_t error = call_resolver(sa, hostname, AF_INET6, port, flags, p); : : if (error) { : family = AF_INET; /* try again */ : } : else { : return APR_SUCCESS; : } : } :#endif : : return call_resolver(sa, hostname, family, port, flags, p); :} : :#else /* end of HAVE_GETADDRINFO code */ : :static apr_status_t find_addresses(apr_sockaddr_t **sa, : const char *hostname, apr_int32_t family, : apr_port_t port, apr_int32_t flags, : apr_pool_t *p) :{ : struct hostent *hp; : apr_sockaddr_t *prev_sa; : int curaddr; :#if APR_HAS_THREADS && !defined(GETHOSTBYNAME_IS_THREAD_SAFE) && \ : defined(HAVE_GETHOSTBYNAME_R) && !defined(BEOS) :#ifdef GETHOSTBYNAME_R_HOSTENT_DATA : struct hostent_data hd; :#else : /* If you see ERANGE, that means GETHOSBYNAME_BUFLEN needs to be : * bumped. */ : char tmp[GETHOSTBYNAME_BUFLEN]; :#endif : int hosterror; :#endif : struct hostent hs; : struct in_addr ipaddr; : char *addr_list[2]; : const char *orig_hostname = hostname; : : if (hostname == NULL) { : /* if we are given a NULL hostname, assume '0.0.0.0' */ : hostname = "0.0.0.0"; : } : : if (*hostname >= '0' && *hostname <= '9' && : strspn(hostname, "0123456789.") == strlen(hostname)) { : : ipaddr.s_addr = inet_addr(hostname); : addr_list[0] = (char *)&ipaddr; : addr_list[1] = NULL; /* just one IP in list */ : hs.h_addr_list = (char **)addr_list; : hp = &hs; : } : else { :#if APR_HAS_THREADS && !defined(GETHOSTBYNAME_IS_THREAD_SAFE) && \ : defined(HAVE_GETHOSTBYNAME_R) && !defined(BEOS) :#if defined(GETHOSTBYNAME_R_HOSTENT_DATA) : /* AIX, HP/UX, D/UX et alia */ : gethostbyname_r(hostname, &hs, &hd); : hp = &hs; :#else :#if defined(GETHOSTBYNAME_R_GLIBC2) : /* Linux glibc2+ */ : gethostbyname_r(hostname, &hs, tmp, GETHOSTBYNAME_BUFLEN - 1, : &hp, &hosterror); :#else : /* Solaris, Irix et alia */ : hp = gethostbyname_r(hostname, &hs, tmp, GETHOSTBYNAME_BUFLEN - 1, : &hosterror); :#endif /* !defined(GETHOSTBYNAME_R_GLIBC2) */ : if (!hp) { : return (hosterror + APR_OS_START_SYSERR); : } :#endif /* !defined(GETHOSTBYNAME_R_HOSTENT_DATA) */ :#else : hp = gethostbyname(hostname); :#endif : : if (!hp) { :#ifdef WIN32 : return apr_get_netos_error(); :#else : return (h_errno + APR_OS_START_SYSERR); :#endif : } : } : : prev_sa = NULL; : curaddr = 0; : while (hp->h_addr_list[curaddr]) { : apr_sockaddr_t *new_sa = apr_pcalloc(p, sizeof(apr_sockaddr_t)); : : new_sa->pool = p; : new_sa->sa.sin.sin_addr = *(struct in_addr *)hp->h_addr_list[curaddr]; : apr_sockaddr_vars_set(new_sa, AF_INET, port); : : if (!prev_sa) { /* first element in new list */ : if (orig_hostname) { : new_sa->hostname = apr_pstrdup(p, orig_hostname); : } : *sa = new_sa; : } : else { : new_sa->hostname = prev_sa->hostname; : prev_sa->next = new_sa; : } : : prev_sa = new_sa; : ++curaddr; : } : : return APR_SUCCESS; :} : :#endif /* end of !HAVE_GETADDRINFO code */ : :APR_DECLARE(apr_status_t) apr_sockaddr_info_get(apr_sockaddr_t **sa, : const char *hostname, : apr_int32_t family, apr_port_t port, : apr_int32_t flags, apr_pool_t *p) 5 0.0087 :{ /* apr_sockaddr_info_get total: 8 0.0139 */ : apr_int32_t masked; : *sa = NULL; : : if ((masked = flags & (APR_IPV4_ADDR_OK | APR_IPV6_ADDR_OK))) { : if (!hostname || : family != APR_UNSPEC || : masked == (APR_IPV4_ADDR_OK | APR_IPV6_ADDR_OK)) { : return APR_EINVAL; : } :#if !APR_HAVE_IPV6 : if (flags & APR_IPV6_ADDR_OK) { : return APR_ENOTIMPL; : } :#endif : } :#if !APR_HAVE_IPV6 : /* What may happen is that APR is not IPv6-enabled, but we're still : * going to call getaddrinfo(), so we have to tell the OS we only : * want IPv4 addresses back since we won't know what to do with : * IPv6 addresses. : */ : if (family == APR_UNSPEC) { : family = APR_INET; : } :#endif : : return find_addresses(sa, hostname, family, port, flags, p); 1 0.0017 :} : :APR_DECLARE(apr_status_t) apr_getnameinfo(char **hostname, : apr_sockaddr_t *sockaddr, : apr_int32_t flags) :{ :#if defined(HAVE_GETNAMEINFO) : int rc; :#if defined(NI_MAXHOST) : char tmphostname[NI_MAXHOST]; :#else : char tmphostname[256]; :#endif : : /* don't know if it is portable for getnameinfo() to set h_errno; : * clear it then see if it was set */ : SET_H_ERRNO(0); : : /* default flags are NI_NAMREQD; otherwise, getnameinfo() will return : * a numeric address string if it fails to resolve the host name; : * that is *not* what we want here : * : * For IPv4-mapped IPv6 addresses, drop down to IPv4 before calling : * getnameinfo() to avoid getnameinfo bugs (MacOS X, glibc). : */ :#if APR_HAVE_IPV6 : if (sockaddr->family == AF_INET6 && : IN6_IS_ADDR_V4MAPPED(&sockaddr->sa.sin6.sin6_addr)) { : struct sockaddr_in tmpsa; : tmpsa.sin_family = AF_INET; : tmpsa.sin_port = 0; : tmpsa.sin_addr.s_addr = ((apr_uint32_t *)sockaddr->ipaddr_ptr)[3]; :#ifdef SIN6_LEN : tmpsa.sin_len = sizeof(tmpsa); :#endif : : rc = getnameinfo((const struct sockaddr *)&tmpsa, sizeof(tmpsa), : tmphostname, sizeof(tmphostname), NULL, 0, : flags != 0 ? flags : NI_NAMEREQD); : } : else :#endif : rc = getnameinfo((const struct sockaddr *)&sockaddr->sa, sockaddr->salen, : tmphostname, sizeof(tmphostname), NULL, 0, : flags != 0 ? flags : NI_NAMEREQD); : if (rc != 0) { : *hostname = NULL; : :#ifndef WIN32 : /* something went wrong. Look at the EAI_ error code */ : if (rc == EAI_SYSTEM) { : /* EAI_SYSTEM System error returned in errno. */ : /* IMHO, Implementations that set h_errno a simply broken. */ : if (h_errno) { /* for broken implementations which set h_errno */ : return h_errno + APR_OS_START_SYSERR; : } : else { /* "normal" case */ : return errno + APR_OS_START_SYSERR; : } : } : else :#endif : { :#if defined(NEGATIVE_EAI) : if (rc < 0) rc = -rc; :#endif : return rc + APR_OS_START_EAIERR; /* return the EAI_ error */ : } : } : *hostname = sockaddr->hostname = apr_pstrdup(sockaddr->pool, : tmphostname); : return APR_SUCCESS; :#else :#if APR_HAS_THREADS && !defined(GETHOSTBYADDR_IS_THREAD_SAFE) && \ : defined(HAVE_GETHOSTBYADDR_R) && !defined(BEOS) :#ifdef GETHOSTBYNAME_R_HOSTENT_DATA : struct hostent_data hd; :#else : char tmp[GETHOSTBYNAME_BUFLEN]; :#endif : int hosterror; : struct hostent hs, *hptr; : :#if defined(GETHOSTBYNAME_R_HOSTENT_DATA) : /* AIX, HP/UX, D/UX et alia */ : gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, : sizeof(struct in_addr), AF_INET, &hs, &hd); : hptr = &hs; :#else :#if defined(GETHOSTBYNAME_R_GLIBC2) : /* Linux glibc2+ */ : gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, : sizeof(struct in_addr), AF_INET, : &hs, tmp, GETHOSTBYNAME_BUFLEN - 1, &hptr, &hosterror); :#else : /* Solaris, Irix et alia */ : hptr = gethostbyaddr_r((char *)&sockaddr->sa.sin.sin_addr, : sizeof(struct in_addr), AF_INET, : &hs, tmp, GETHOSTBYNAME_BUFLEN, &hosterror); :#endif /* !defined(GETHOSTBYNAME_R_GLIBC2) */ : if (!hptr) { : *hostname = NULL; : return hosterror + APR_OS_START_SYSERR; : } :#endif /* !defined(GETHOSTBYNAME_R_HOSTENT_DATA) */ :#else : struct hostent *hptr; : hptr = gethostbyaddr((char *)&sockaddr->sa.sin.sin_addr, : sizeof(struct in_addr), AF_INET); :#endif : : if (hptr) { : *hostname = sockaddr->hostname = apr_pstrdup(sockaddr->pool, hptr->h_name); : return APR_SUCCESS; : } : *hostname = NULL; :#if defined(WIN32) : return apr_get_netos_error(); :#elif defined(OS2) : return h_errno; :#else : return h_errno + APR_OS_START_SYSERR; :#endif :#endif :} : :APR_DECLARE(apr_status_t) apr_getservbyname(apr_sockaddr_t *sockaddr, : const char *servname) :{ : struct servent *se; : : if (servname == NULL) : return APR_EINVAL; : : if ((se = getservbyname(servname, NULL)) != NULL){ : sockaddr->port = htons(se->s_port); : sockaddr->servname = apr_pstrdup(sockaddr->pool, servname); : sockaddr->sa.sin.sin_port = se->s_port; : return APR_SUCCESS; : } : return errno; :} : :#define V4MAPPED_EQUAL(a,b) \ :((a)->sa.sin.sin_family == AF_INET && \ : (b)->sa.sin.sin_family == AF_INET6 && \ : IN6_IS_ADDR_V4MAPPED((struct in6_addr *)(b)->ipaddr_ptr) && \ : !memcmp((a)->ipaddr_ptr, \ : &((struct in6_addr *)(b)->ipaddr_ptr)->s6_addr[12], \ : (a)->ipaddr_len)) : :APR_DECLARE(int) apr_sockaddr_equal(const apr_sockaddr_t *addr1, : const apr_sockaddr_t *addr2) :{ : if (addr1->ipaddr_len == addr2->ipaddr_len && : !memcmp(addr1->ipaddr_ptr, addr2->ipaddr_ptr, addr1->ipaddr_len)) { : return 1; : } :#if APR_HAVE_IPV6 : if (V4MAPPED_EQUAL(addr1, addr2)) { : return 1; : } : if (V4MAPPED_EQUAL(addr2, addr1)) { : return 1; : } :#endif : return 0; /* not equal */ :} : :static apr_status_t parse_network(apr_ipsubnet_t *ipsub, const char *network) :{ : /* legacy syntax for ip addrs: a.b.c. ==> a.b.c.0/24 for example */ : int shift; : char *s, *t; : int octet; : char buf[sizeof "255.255.255.255"]; : : if (strlen(network) < sizeof buf) { : strcpy(buf, network); : } : else { : return APR_EBADIP; : } : : /* parse components */ : s = buf; : ipsub->sub[0] = 0; : ipsub->mask[0] = 0; : shift = 24; : while (*s) { : t = s; : if (!apr_isdigit(*t)) { : return APR_EBADIP; : } : while (apr_isdigit(*t)) { : ++t; : } : if (*t == '.') { : *t++ = 0; : } : else if (*t) { : return APR_EBADIP; : } : if (shift < 0) { : return APR_EBADIP; : } : octet = atoi(s); : if (octet < 0 || octet > 255) { : return APR_EBADIP; : } : ipsub->sub[0] |= octet << shift; : ipsub->mask[0] |= 0xFFUL << shift; : s = t; : shift -= 8; : } : ipsub->sub[0] = ntohl(ipsub->sub[0]); : ipsub->mask[0] = ntohl(ipsub->mask[0]); : ipsub->family = AF_INET; : return APR_SUCCESS; :} : :/* return values: : * APR_EINVAL not an IP address; caller should see if it is something else : * APR_BADIP IP address portion is is not valid : * APR_BADMASK mask portion is not valid : */ : :static apr_status_t parse_ip(apr_ipsubnet_t *ipsub, const char *ipstr, int network_allowed) :{ : /* supported flavors of IP: : * : * . IPv6 numeric address string (e.g., "fe80::1") : * : * IMPORTANT: Don't store IPv4-mapped IPv6 address as an IPv6 address. : * : * . IPv4 numeric address string (e.g., "127.0.0.1") : * : * . IPv4 network string (e.g., "9.67") : * : * IMPORTANT: This network form is only allowed if network_allowed is on. : */ : int rc; : :#if APR_HAVE_IPV6 : rc = apr_inet_pton(AF_INET6, ipstr, ipsub->sub); : if (rc == 1) { : if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ipsub->sub)) { : /* apr_ipsubnet_test() assumes that we don't create IPv4-mapped IPv6 : * addresses; this of course forces the user to specify IPv4 addresses : * in a.b.c.d style instead of ::ffff:a.b.c.d style. : */ : return APR_EBADIP; : } : ipsub->family = AF_INET6; : } : else :#endif : { : rc = apr_inet_pton(AF_INET, ipstr, ipsub->sub); : if (rc == 1) { : ipsub->family = AF_INET; : } : } : if (rc != 1) { : if (network_allowed) { : return parse_network(ipsub, ipstr); : } : else { : return APR_EBADIP; : } : } : return APR_SUCCESS; :} : :static int looks_like_ip(const char *ipstr) :{ : if (strchr(ipstr, ':')) { : /* definitely not a hostname; assume it is intended to be an IPv6 address */ : return 1; : } : : /* simple IPv4 address string check */ : while ((*ipstr == '.') || apr_isdigit(*ipstr)) : ipstr++; : return (*ipstr == '\0'); :} : :static void fix_subnet(apr_ipsubnet_t *ipsub) :{ : /* in case caller specified more bits in network address than are : * valid according to the mask, turn off the extra bits : */ : int i; : : for (i = 0; i < sizeof ipsub->mask / sizeof(apr_int32_t); i++) { : ipsub->sub[i] &= ipsub->mask[i]; : } :} : :/* be sure not to store any IPv4 address as a v4-mapped IPv6 address */ :APR_DECLARE(apr_status_t) apr_ipsubnet_create(apr_ipsubnet_t **ipsub, const char *ipstr, : const char *mask_or_numbits, apr_pool_t *p) :{ : apr_status_t rv; : char *endptr; : long bits, maxbits = 32; : : /* filter out stuff which doesn't look remotely like an IP address; this helps : * callers like mod_access which have a syntax allowing hostname or IP address; : * APR_EINVAL tells the caller that it was probably not intended to be an IP : * address : */ : if (!looks_like_ip(ipstr)) { : return APR_EINVAL; : } : : *ipsub = apr_pcalloc(p, sizeof(apr_ipsubnet_t)); : : /* assume ipstr is an individual IP address, not a subnet */ : memset((*ipsub)->mask, 0xFF, sizeof (*ipsub)->mask); : : rv = parse_ip(*ipsub, ipstr, mask_or_numbits == NULL); : if (rv != APR_SUCCESS) { : return rv; : } : : if (mask_or_numbits) { :#if APR_HAVE_IPV6 : if ((*ipsub)->family == AF_INET6) { : maxbits = 128; : } :#endif : bits = strtol(mask_or_numbits, &endptr, 10); : if (*endptr == '\0' && bits > 0 && bits <= maxbits) { : /* valid num-bits string; fill in mask appropriately */ : int cur_entry = 0; : apr_int32_t cur_bit_value; : : memset((*ipsub)->mask, 0, sizeof (*ipsub)->mask); : while (bits > 32) { : (*ipsub)->mask[cur_entry] = 0xFFFFFFFF; /* all 32 bits */ : bits -= 32; : ++cur_entry; : } : cur_bit_value = 0x80000000; : while (bits) { : (*ipsub)->mask[cur_entry] |= cur_bit_value; : --bits; : cur_bit_value /= 2; : } : (*ipsub)->mask[cur_entry] = htonl((*ipsub)->mask[cur_entry]); : } : else if (apr_inet_pton(AF_INET, mask_or_numbits, (*ipsub)->mask) == 1 && : (*ipsub)->family == AF_INET) { : /* valid IPv4 netmask */ : } : else { : return APR_EBADMASK; : } : } : : fix_subnet(*ipsub); : : return APR_SUCCESS; :} : :APR_DECLARE(int) apr_ipsubnet_test(apr_ipsubnet_t *ipsub, apr_sockaddr_t *sa) :{ :#if APR_HAVE_IPV6 : /* XXX This line will segv on Win32 build with APR_HAVE_IPV6, : * but without the IPV6 drivers installed. : */ : if (sa->sa.sin.sin_family == AF_INET) { : if (ipsub->family == AF_INET && : ((sa->sa.sin.sin_addr.s_addr & ipsub->mask[0]) == ipsub->sub[0])) { : return 1; : } : } : else if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)sa->ipaddr_ptr)) { : if (ipsub->family == AF_INET && : (((apr_uint32_t *)sa->ipaddr_ptr)[3] & ipsub->mask[0]) == ipsub->sub[0]) { : return 1; : } : } : else { : apr_uint32_t *addr = (apr_uint32_t *)sa->ipaddr_ptr; : : if ((addr[0] & ipsub->mask[0]) == ipsub->sub[0] && : (addr[1] & ipsub->mask[1]) == ipsub->sub[1] && : (addr[2] & ipsub->mask[2]) == ipsub->sub[2] && : (addr[3] & ipsub->mask[3]) == ipsub->sub[3]) { : return 1; : } : } :#else : if ((sa->sa.sin.sin_addr.s_addr & ipsub->mask[0]) == ipsub->sub[0]) { : return 1; : } :#endif /* APR_HAVE_IPV6 */ : return 0; /* no match */ :} /* * Total samples for file : "threadproc/unix/thread.c" * * 14 0.0244 */ :/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as : * applicable. : * : * Licensed 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. : */ : :#include "apr.h" :#include "apr_portable.h" :#include "apr_arch_threadproc.h" : :#if APR_HAS_THREADS : :#if APR_HAVE_PTHREAD_H : :/* Destroy the threadattr object */ :static apr_status_t threadattr_cleanup(void *data) :{ : apr_threadattr_t *attr = data; : apr_status_t rv; : 2 0.0035 : rv = pthread_attr_destroy(&attr->attr); /* threadattr_cleanup total: 2 0.0035 */ :#ifdef PTHREAD_SETS_ERRNO : if (rv) { : rv = errno; : } :#endif : return rv; :} : :APR_DECLARE(apr_status_t) apr_threadattr_create(apr_threadattr_t **new, : apr_pool_t *pool) 1 0.0017 :{ /* apr_threadattr_create total: 2 0.0035 */ : apr_status_t stat; : 1 0.0017 : (*new) = apr_palloc(pool, sizeof(apr_threadattr_t)); : (*new)->pool = pool; : stat = pthread_attr_init(&(*new)->attr); : : if (stat == 0) { : apr_pool_cleanup_register(pool, *new, threadattr_cleanup, : apr_pool_cleanup_null); : return APR_SUCCESS; : } :#ifdef PTHREAD_SETS_ERRNO : stat = errno; :#endif : : return stat; :} : :#define DETACH_ARG(v) ((v) ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE) : :APR_DECLARE(apr_status_t) apr_threadattr_detach_set(apr_threadattr_t *attr, : apr_int32_t on) :{ : apr_status_t stat; :#ifdef PTHREAD_ATTR_SETDETACHSTATE_ARG2_ADDR : int arg = DETACH_ARG(v); : : if ((stat = pthread_attr_setdetachstate(&attr->attr, &arg)) == 0) { :#else 4 0.0070 : if ((stat = pthread_attr_setdetachstate(&attr->attr, /* apr_threadattr_detach_set total: 4 0.0070 */ : DETACH_ARG(on))) == 0) { :#endif : return APR_SUCCESS; : } : else { :#ifdef PTHREAD_SETS_ERRNO : stat = errno; :#endif : : return stat; : } :} : :APR_DECLARE(apr_status_t) apr_threadattr_detach_get(apr_threadattr_t *attr) :{ : int state; : :#ifdef PTHREAD_ATTR_GETDETACHSTATE_TAKES_ONE_ARG : state = pthread_attr_getdetachstate(&attr->attr); :#else : pthread_attr_getdetachstate(&attr->attr, &state); :#endif : if (state == 1) : return APR_DETACH; : return APR_NOTDETACH; :} : :APR_DECLARE(apr_status_t) apr_threadattr_stacksize_set(apr_threadattr_t *attr, : apr_size_t stacksize) :{ : int stat; : : stat = pthread_attr_setstacksize(&attr->attr, stacksize); : if (stat == 0) { : return APR_SUCCESS; : } :#ifdef PTHREAD_SETS_ERRNO : stat = errno; :#endif : : return stat; :} : :APR_DECLARE(apr_status_t) apr_threadattr_guardsize_set(apr_threadattr_t *attr, : apr_size_t size) :{ :#ifdef HAVE_PTHREAD_ATTR_SETGUARDSIZE : apr_status_t rv; : : rv = pthread_attr_setguardsize(&attr->attr, size); : if (rv == 0) { : return APR_SUCCESS; : } :#ifdef PTHREAD_SETS_ERRNO : rv = errno; :#endif : return rv; :#else : return APR_ENOTIMPL; :#endif :} : :static void *dummy_worker(void *opaque) :{ : apr_thread_t *thread = (apr_thread_t*)opaque; : return thread->func(thread, thread->data); :} : :APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new, : apr_threadattr_t *attr, : apr_thread_start_t func, : void *data, : apr_pool_t *pool) 4 0.0070 :{ /* apr_thread_create total: 6 0.0104 */ : apr_status_t stat; : pthread_attr_t *temp; : : (*new) = (apr_thread_t *)apr_pcalloc(pool, sizeof(apr_thread_t)); : : if ((*new) == NULL) { : return APR_ENOMEM; : } : : (*new)->td = (pthread_t *)apr_pcalloc(pool, sizeof(pthread_t)); : : if ((*new)->td == NULL) { : return APR_ENOMEM; : } : : (*new)->pool = pool; : (*new)->data = data; : (*new)->func = func; : : if (attr) : temp = &attr->attr; : else : temp = NULL; : 1 0.0017 : stat = apr_pool_create(&(*new)->pool, pool); : if (stat != APR_SUCCESS) { : return stat; : } : : if ((stat = pthread_create((*new)->td, temp, dummy_worker, (*new))) == 0) { : return APR_SUCCESS; : } : else { :#ifdef PTHREAD_SETS_ERRNO : stat = errno; :#endif : : return stat; : } 1 0.0017 :} : :APR_DECLARE(apr_os_thread_t) apr_os_thread_current(void) :{ : return pthread_self(); :} : :APR_DECLARE(int) apr_os_thread_equal(apr_os_thread_t tid1, : apr_os_thread_t tid2) :{ : return pthread_equal(tid1, tid2); :} : :APR_DECLARE(apr_status_t) apr_thread_exit(apr_thread_t *thd, : apr_status_t retval) :{ : thd->exitval = retval; : apr_pool_destroy(thd->pool); : pthread_exit(NULL); : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_thread_join(apr_status_t *retval, : apr_thread_t *thd) :{ : apr_status_t stat; : apr_status_t *thread_stat; : : if ((stat = pthread_join(*thd->td,(void *)&thread_stat)) == 0) { : *retval = thd->exitval; : return APR_SUCCESS; : } : else { :#ifdef PTHREAD_SETS_ERRNO : stat = errno; :#endif : : return stat; : } :} : :APR_DECLARE(apr_status_t) apr_thread_detach(apr_thread_t *thd) :{ : apr_status_t stat; : :#ifdef PTHREAD_DETACH_ARG1_ADDR : if ((stat = pthread_detach(thd->td)) == 0) { :#else : if ((stat = pthread_detach(*thd->td)) == 0) { :#endif : : return APR_SUCCESS; : } : else { :#ifdef PTHREAD_SETS_ERRNO : stat = errno; :#endif : : return stat; : } :} : :void apr_thread_yield() :{ :} : :APR_DECLARE(apr_status_t) apr_thread_data_get(void **data, const char *key, : apr_thread_t *thread) :{ : return apr_pool_userdata_get(data, key, thread->pool); :} : :APR_DECLARE(apr_status_t) apr_thread_data_set(void *data, const char *key, : apr_status_t (*cleanup)(void *), : apr_thread_t *thread) :{ : return apr_pool_userdata_set(data, key, cleanup, thread->pool); :} : :APR_DECLARE(apr_status_t) apr_os_thread_get(apr_os_thread_t **thethd, : apr_thread_t *thd) :{ : *thethd = thd->td; : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_os_thread_put(apr_thread_t **thd, : apr_os_thread_t *thethd, : apr_pool_t *pool) :{ : if (pool == NULL) { : return APR_ENOPOOL; : } : : if ((*thd) == NULL) { : (*thd) = (apr_thread_t *)apr_pcalloc(pool, sizeof(apr_thread_t)); : (*thd)->pool = pool; : } : : (*thd)->td = thethd; : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_thread_once_init(apr_thread_once_t **control, : apr_pool_t *p) :{ : static const pthread_once_t once_init = PTHREAD_ONCE_INIT; : : *control = apr_palloc(p, sizeof(**control)); : (*control)->once = once_init; : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_thread_once(apr_thread_once_t *control, : void (*func)(void)) :{ : return pthread_once(&control->once, func); :} : :APR_POOL_IMPLEMENT_ACCESSOR(thread) : :#endif /* HAVE_PTHREAD_H */ :#endif /* APR_HAS_THREADS */ : :#if !APR_HAS_THREADS : :/* avoid warning for no prototype */ :APR_DECLARE(apr_status_t) apr_os_thread_get(void); : :APR_DECLARE(apr_status_t) apr_os_thread_get(void) :{ : return APR_ENOTIMPL; :} : :#endif /* * Total samples for file : "locks/unix/thread_cond.c" * * 14 0.0244 */ :/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as : * applicable. : * : * Licensed 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. : */ : :#include "apr.h" : :#if APR_HAS_THREADS : :#include "apr_arch_thread_mutex.h" :#include "apr_arch_thread_cond.h" : :static apr_status_t thread_cond_cleanup(void *data) :{ : apr_thread_cond_t *cond = (apr_thread_cond_t *)data; : apr_status_t rv; : 1 0.0017 : rv = pthread_cond_destroy(&cond->cond); /* thread_cond_cleanup total: 1 0.0017 */ :#ifdef PTHREAD_SETS_ERRNO : if (rv) { : rv = errno; : } :#endif : return rv; :} : :APR_DECLARE(apr_status_t) apr_thread_cond_create(apr_thread_cond_t **cond, : apr_pool_t *pool) 2 0.0035 :{ /* apr_thread_cond_create total: 2 0.0035 */ : apr_thread_cond_t *new_cond; : apr_status_t rv; : : new_cond = apr_palloc(pool, sizeof(apr_thread_cond_t)); : : new_cond->pool = pool; : : if ((rv = pthread_cond_init(&new_cond->cond, NULL))) { :#ifdef PTHREAD_SETS_ERRNO : rv = errno; :#endif : return rv; : } : : apr_pool_cleanup_register(new_cond->pool, : (void *)new_cond, thread_cond_cleanup, : apr_pool_cleanup_null); : : *cond = new_cond; : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_thread_cond_wait(apr_thread_cond_t *cond, : apr_thread_mutex_t *mutex) :{ : apr_status_t rv; : 4 0.0070 : rv = pthread_cond_wait(&cond->cond, &mutex->mutex); /* apr_thread_cond_wait total: 4 0.0070 */ :#ifdef PTHREAD_SETS_ERRNO : if (rv) { : rv = errno; : } :#endif : return rv; :} : :APR_DECLARE(apr_status_t) apr_thread_cond_timedwait(apr_thread_cond_t *cond, : apr_thread_mutex_t *mutex, : apr_interval_time_t timeout) :{ : apr_status_t rv; : apr_time_t then; : struct timespec abstime; : : then = apr_time_now() + timeout; : abstime.tv_sec = apr_time_sec(then); : abstime.tv_nsec = apr_time_usec(then) * 1000; /* nanoseconds */ : : rv = pthread_cond_timedwait(&cond->cond, &mutex->mutex, &abstime); :#ifdef PTHREAD_SETS_ERRNO : if (rv) { : rv = errno; : } :#endif : if (ETIMEDOUT == rv) { : return APR_TIMEUP; : } : return rv; :} : : :APR_DECLARE(apr_status_t) apr_thread_cond_signal(apr_thread_cond_t *cond) :{ : apr_status_t rv; : 7 0.0122 : rv = pthread_cond_signal(&cond->cond); /* apr_thread_cond_signal total: 7 0.0122 */ :#ifdef PTHREAD_SETS_ERRNO : if (rv) { : rv = errno; : } :#endif : return rv; :} : :APR_DECLARE(apr_status_t) apr_thread_cond_broadcast(apr_thread_cond_t *cond) :{ : apr_status_t rv; : : rv = pthread_cond_broadcast(&cond->cond); :#ifdef PTHREAD_SETS_ERRNO : if (rv) { : rv = errno; : } :#endif : return rv; :} : :APR_DECLARE(apr_status_t) apr_thread_cond_destroy(apr_thread_cond_t *cond) :{ : return apr_pool_cleanup_run(cond->pool, cond, thread_cond_cleanup); :} : :APR_POOL_IMPLEMENT_ACCESSOR(thread_cond) : :#endif /* APR_HAS_THREADS */ /* * Total samples for file : "locks/unix/thread_rwlock.c" * * 11 0.0192 */ :/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as : * applicable. : * : * Licensed 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. : */ : :#include "apr_arch_thread_rwlock.h" :#include "apr_private.h" : :#if APR_HAS_THREADS : :#ifdef HAVE_PTHREAD_RWLOCKS : :/* The rwlock must be initialized but not locked by any thread when : * cleanup is called. */ :static apr_status_t thread_rwlock_cleanup(void *data) :{ : apr_thread_rwlock_t *rwlock = (apr_thread_rwlock_t *)data; : apr_status_t stat; : 3 0.0052 : stat = pthread_rwlock_destroy(&rwlock->rwlock); /* thread_rwlock_cleanup total: 3 0.0052 */ :#ifdef PTHREAD_SETS_ERRNO : if (stat) { : stat = errno; : } :#endif : return stat; :} : :APR_DECLARE(apr_status_t) apr_thread_rwlock_create(apr_thread_rwlock_t **rwlock, : apr_pool_t *pool) 3 0.0052 :{ /* apr_thread_rwlock_create total: 4 0.0070 */ : apr_thread_rwlock_t *new_rwlock; : apr_status_t stat; : : new_rwlock = apr_palloc(pool, sizeof(apr_thread_rwlock_t)); : new_rwlock->pool = pool; : : if ((stat = pthread_rwlock_init(&new_rwlock->rwlock, NULL))) { :#ifdef PTHREAD_SETS_ERRNO : stat = errno; :#endif : return stat; : } : 1 0.0017 : apr_pool_cleanup_register(new_rwlock->pool, : (void *)new_rwlock, thread_rwlock_cleanup, : apr_pool_cleanup_null); : : *rwlock = new_rwlock; : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_thread_rwlock_rdlock(apr_thread_rwlock_t *rwlock) :{ : apr_status_t stat; : 1 0.0017 : stat = pthread_rwlock_rdlock(&rwlock->rwlock); /* apr_thread_rwlock_rdlock total: 1 0.0017 */ :#ifdef PTHREAD_SETS_ERRNO : if (stat) { : stat = errno; : } :#endif : return stat; :} : :APR_DECLARE(apr_status_t) apr_thread_rwlock_tryrdlock(apr_thread_rwlock_t *rwlock) :{ : apr_status_t stat; : : stat = pthread_rwlock_tryrdlock(&rwlock->rwlock); :#ifdef PTHREAD_SETS_ERRNO : if (stat) { : stat = errno; : } :#endif : /* Normalize the return code. */ : if (stat == EBUSY) : stat = APR_EBUSY; : return stat; :} : :APR_DECLARE(apr_status_t) apr_thread_rwlock_wrlock(apr_thread_rwlock_t *rwlock) :{ : apr_status_t stat; : : stat = pthread_rwlock_wrlock(&rwlock->rwlock); :#ifdef PTHREAD_SETS_ERRNO : if (stat) { : stat = errno; : } :#endif : return stat; :} : :APR_DECLARE(apr_status_t) apr_thread_rwlock_trywrlock(apr_thread_rwlock_t *rwlock) :{ : apr_status_t stat; : : stat = pthread_rwlock_trywrlock(&rwlock->rwlock); :#ifdef PTHREAD_SETS_ERRNO : if (stat) { : stat = errno; : } :#endif : /* Normalize the return code. */ : if (stat == EBUSY) : stat = APR_EBUSY; : return stat; :} : :APR_DECLARE(apr_status_t) apr_thread_rwlock_unlock(apr_thread_rwlock_t *rwlock) :{ : apr_status_t stat; : 3 0.0052 : stat = pthread_rwlock_unlock(&rwlock->rwlock); /* apr_thread_rwlock_unlock total: 3 0.0052 */ :#ifdef PTHREAD_SETS_ERRNO : if (stat) { : stat = errno; : } :#endif : return stat; :} : :APR_DECLARE(apr_status_t) apr_thread_rwlock_destroy(apr_thread_rwlock_t *rwlock) :{ : return apr_pool_cleanup_run(rwlock->pool, rwlock, thread_rwlock_cleanup); :} : :#else /* HAVE_PTHREAD_RWLOCKS */ : :APR_DECLARE(apr_status_t) apr_thread_rwlock_create(apr_thread_rwlock_t **rwlock, : apr_pool_t *pool) :{ : return APR_ENOTIMPL; :} : :APR_DECLARE(apr_status_t) apr_thread_rwlock_rdlock(apr_thread_rwlock_t *rwlock) :{ : return APR_ENOTIMPL; :} : :APR_DECLARE(apr_status_t) apr_thread_rwlock_tryrdlock(apr_thread_rwlock_t *rwlock) :{ : return APR_ENOTIMPL; :} : :APR_DECLARE(apr_status_t) apr_thread_rwlock_wrlock(apr_thread_rwlock_t *rwlock) :{ : return APR_ENOTIMPL; :} : :APR_DECLARE(apr_status_t) apr_thread_rwlock_trywrlock(apr_thread_rwlock_t *rwlock) :{ : return APR_ENOTIMPL; :} : :APR_DECLARE(apr_status_t) apr_thread_rwlock_unlock(apr_thread_rwlock_t *rwlock) :{ : return APR_ENOTIMPL; :} : :APR_DECLARE(apr_status_t) apr_thread_rwlock_destroy(apr_thread_rwlock_t *rwlock) :{ : return APR_ENOTIMPL; :} : :#endif /* HAVE_PTHREAD_RWLOCKS */ :APR_POOL_IMPLEMENT_ACCESSOR(thread_rwlock) : :#endif /* APR_HAS_THREADS */ /* * Total samples for file : "strings/apr_strings.c" * * 5 0.0087 */ :/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as : * applicable. : * : * Licensed 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. : */ :/* : * Copyright (c) 1990, 1993 : * The Regents of the University of California. All rights reserved. : * : * Redistribution and use in source and binary forms, with or without : * modification, are permitted provided that the following conditions : * are met: : * 1. Redistributions of source code must retain the above copyright : * notice, this list of conditions and the following disclaimer. : * 2. Redistributions in binary form must reproduce the above copyright : * notice, this list of conditions and the following disclaimer in the : * documentation and/or other materials provided with the distribution. : * 3. All advertising materials mentioning features or use of this software : * must display the following acknowledgement: : * This product includes software developed by the University of : * California, Berkeley and its contributors. : * 4. Neither the name of the University nor the names of its contributors : * may be used to endorse or promote products derived from this software : * without specific prior written permission. : * : * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE : * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF : * SUCH DAMAGE. : */ : :#include "apr.h" :#include "apr_strings.h" :#include "apr_general.h" :#include "apr_private.h" :#include "apr_lib.h" :#define APR_WANT_STDIO :#define APR_WANT_STRFUNC :#include "apr_want.h" : :#ifdef HAVE_STDDEF_H :#include /* NULL */ :#endif : :#ifdef HAVE_STDLIB_H :#include /* strtol and strtoll */ :#endif : :/** this is used to cache lengths in apr_pstrcat */ :#define MAX_SAVED_LENGTHS 6 : :APR_DECLARE(char *) apr_pstrdup(apr_pool_t *a, const char *s) :{ : char *res; : apr_size_t len; : : if (s == NULL) { : return NULL; : } : len = strlen(s) + 1; : res = apr_palloc(a, len); : memcpy(res, s, len); : return res; :} : :APR_DECLARE(char *) apr_pstrndup(apr_pool_t *a, const char *s, apr_size_t n) :{ : char *res; : const char *end; : : if (s == NULL) { : return NULL; : } : end = memchr(s, '\0', n); : if (end != NULL) : n = end - s; : res = apr_palloc(a, n + 1); : memcpy(res, s, n); : res[n] = '\0'; : return res; :} : :APR_DECLARE(char *) apr_pstrmemdup(apr_pool_t *a, const char *s, apr_size_t n) :{ : char *res; : : if (s == NULL) { : return NULL; : } : res = apr_palloc(a, n + 1); : memcpy(res, s, n); : res[n] = '\0'; : return res; :} : :APR_DECLARE(void *) apr_pmemdup(apr_pool_t *a, const void *m, apr_size_t n) :{ : void *res; : : if (m == NULL) : return NULL; : res = apr_palloc(a, n); : memcpy(res, m, n); : return res; :} : :APR_DECLARE_NONSTD(char *) apr_pstrcat(apr_pool_t *a, ...) :{ : char *cp, *argp, *res; : apr_size_t saved_lengths[MAX_SAVED_LENGTHS]; : int nargs = 0; : : /* Pass one --- find length of required string */ : : apr_size_t len = 0; : va_list adummy; : : va_start(adummy, a); : : while ((cp = va_arg(adummy, char *)) != NULL) { : apr_size_t cplen = strlen(cp); : if (nargs < MAX_SAVED_LENGTHS) { : saved_lengths[nargs++] = cplen; : } : len += cplen; : } : : va_end(adummy); : : /* Allocate the required string */ : : res = (char *) apr_palloc(a, len + 1); : cp = res; : : /* Pass two --- copy the argument strings into the result space */ : : va_start(adummy, a); : : nargs = 0; : while ((argp = va_arg(adummy, char *)) != NULL) { : if (nargs < MAX_SAVED_LENGTHS) { : len = saved_lengths[nargs++]; : } : else { : len = strlen(argp); : } : : memcpy(cp, argp, len); : cp += len; : } : : va_end(adummy); : : /* Return the result string */ : : *cp = '\0'; : : return res; :} : :APR_DECLARE(char *) apr_pstrcatv(apr_pool_t *a, const struct iovec *vec, : apr_size_t nvec, apr_size_t *nbytes) :{ : apr_size_t i; : apr_size_t len; : const struct iovec *src; : char *res; : char *dst; : : /* Pass one --- find length of required string */ : len = 0; : src = vec; : for (i = nvec; i; i--) { : len += src->iov_len; : src++; : } : if (nbytes) { : *nbytes = len; : } : : /* Allocate the required string */ : res = (char *) apr_palloc(a, len + 1); : : /* Pass two --- copy the argument strings into the result space */ : src = vec; : dst = res; : for (i = nvec; i; i--) { : memcpy(dst, src->iov_base, src->iov_len); : dst += src->iov_len; : src++; : } : : /* Return the result string */ : *dst = '\0'; : : return res; :} : :#if (!APR_HAVE_MEMCHR) :void *memchr(const void *s, int c, size_t n) :{ : const char *cp; : : for (cp = s; n > 0; n--, cp++) { : if (*cp == c) : return (char *) cp; /* Casting away the const here */ : } : : return NULL; :} :#endif : :#ifndef INT64_MAX :#define INT64_MAX APR_INT64_C(0x7fffffffffffffff) :#endif :#ifndef INT64_MIN :#define INT64_MIN (-APR_INT64_C(0x7fffffffffffffff) - APR_INT64_C(1)) :#endif : :APR_DECLARE(apr_status_t) apr_strtoff(apr_off_t *offset, const char *nptr, : char **endptr, int base) :{ : errno = 0; : *offset = APR_OFF_T_STRFN(nptr, endptr, base); : return APR_FROM_OS_ERROR(errno); :} : :APR_DECLARE(apr_int64_t) apr_strtoi64(const char *nptr, char **endptr, int base) :{ :#ifdef APR_INT64_STRFN : return APR_INT64_STRFN(nptr, endptr, base); :#else : const char *s; : apr_int64_t acc; : apr_int64_t val; : int neg, any; : char c; : : /* : * Skip white space and pick up leading +/- sign if any. : * If base is 0, allow 0x for hex and 0 for octal, else : * assume decimal; if base is already 16, allow 0x. : */ : s = nptr; : do { : c = *s++; : } while (apr_isspace(c)); : if (c == '-') { : neg = 1; : c = *s++; : } else { : neg = 0; : if (c == '+') : c = *s++; : } : if ((base == 0 || base == 16) && : c == '0' && (*s == 'x' || *s == 'X')) { : c = s[1]; : s += 2; : base = 16; : } : if (base == 0) : base = c == '0' ? 8 : 10; : acc = any = 0; : if (base < 2 || base > 36) { : errno = EINVAL; : if (endptr != NULL) : *endptr = (char *)(any ? s - 1 : nptr); : return acc; : } : : /* The classic bsd implementation requires div/mod operators : * to compute a cutoff. Benchmarking proves that is very, very : * evil to some 32 bit processors. Instead, look for underflow : * in both the mult and add/sub operation. Unlike the bsd impl, : * we also work strictly in a signed int64 word as we haven't : * implemented the unsigned type in win32. : * : * Set 'any' if any `digits' consumed; make it negative to indicate : * overflow. : */ : val = 0; : for ( ; ; c = *s++) { : if (c >= '0' && c <= '9') : c -= '0'; :#if (('Z' - 'A') == 25) : else if (c >= 'A' && c <= 'Z') : c -= 'A' - 10; : else if (c >= 'a' && c <= 'z') : c -= 'a' - 10; :#elif APR_CHARSET_EBCDIC : else if (c >= 'A' && c <= 'I') : c -= 'A' - 10; : else if (c >= 'J' && c <= 'R') : c -= 'J' - 19; : else if (c >= 'S' && c <= 'Z') : c -= 'S' - 28; : else if (c >= 'a' && c <= 'i') : c -= 'a' - 10; : else if (c >= 'j' && c <= 'r') : c -= 'j' - 19; : else if (c >= 's' && c <= 'z') : c -= 'z' - 28; :#else :#error "CANNOT COMPILE apr_strtoi64(), only ASCII and EBCDIC supported" :#endif : else : break; : if (c >= base) : break; : val *= base; : if ( (any < 0) /* already noted an over/under flow - short circuit */ : || (neg && (val > acc || (val -= c) > acc)) /* underflow */ : || (!neg && (val < acc || (val += c) < acc))) { /* overflow */ : any = -1; /* once noted, over/underflows never go away */ :#ifdef APR_STRTOI64_OVERFLOW_IS_BAD_CHAR : break; :#endif : } else { : acc = val; : any = 1; : } : } : : if (any < 0) { : acc = neg ? INT64_MIN : INT64_MAX; : errno = ERANGE; : } else if (!any) { : errno = EINVAL; : } : if (endptr != NULL) : *endptr = (char *)(any ? s - 1 : nptr); : return (acc); :#endif :} : :APR_DECLARE(apr_int64_t) apr_atoi64(const char *buf) :{ : return apr_strtoi64(buf, NULL, 10); :} : :APR_DECLARE(char *) apr_itoa(apr_pool_t *p, int n) 5 0.0087 :{ /* apr_itoa total: 5 0.0087 */ : const int BUFFER_SIZE = sizeof(int) * 3 + 2; : char *buf = apr_palloc(p, BUFFER_SIZE); : char *start = buf + BUFFER_SIZE - 1; : int negative; : if (n < 0) { : negative = 1; : n = -n; : } : else { : negative = 0; : } : *start = 0; : do { : *--start = '0' + (n % 10); : n /= 10; : } while (n); : if (negative) { : *--start = '-'; : } : return start; :} : :APR_DECLARE(char *) apr_ltoa(apr_pool_t *p, long n) :{ : const int BUFFER_SIZE = sizeof(long) * 3 + 2; : char *buf = apr_palloc(p, BUFFER_SIZE); : char *start = buf + BUFFER_SIZE - 1; : int negative; : if (n < 0) { : negative = 1; : n = -n; : } : else { : negative = 0; : } : *start = 0; : do { : *--start = (char)('0' + (n % 10)); : n /= 10; : } while (n); : if (negative) { : *--start = '-'; : } : return start; :} : :APR_DECLARE(char *) apr_off_t_toa(apr_pool_t *p, apr_off_t n) :{ : const int BUFFER_SIZE = sizeof(apr_off_t) * 3 + 2; : char *buf = apr_palloc(p, BUFFER_SIZE); : char *start = buf + BUFFER_SIZE - 1; : int negative; : if (n < 0) { : negative = 1; : n = -n; : } : else { : negative = 0; : } : *start = 0; : do { : *--start = '0' + (char)(n % 10); : n /= 10; : } while (n); : if (negative) { : *--start = '-'; : } : return start; :} : :APR_DECLARE(char *) apr_strfsize(apr_off_t size, char *buf) :{ : const char ord[] = "KMGTPE"; : const char *o = ord; : int remain; : : if (size < 0) { : return strcpy(buf, " - "); : } : if (size < 973) { : if (apr_snprintf(buf, 5, "%3d ", (int) size) < 0) : return strcpy(buf, "****"); : return buf; : } : do { : remain = (int)(size & 1023); : size >>= 10; : if (size >= 973) { : ++o; : continue; : } : if (size < 9 || (size == 9 && remain < 973)) { : if ((remain = ((remain * 5) + 256) / 512) >= 10) : ++size, remain = 0; : if (apr_snprintf(buf, 5, "%d.%d%c", (int) size, remain, *o) < 0) : return strcpy(buf, "****"); : return buf; : } : if (remain >= 512) : ++size; : if (apr_snprintf(buf, 5, "%3d%c", (int) size, *o) < 0) : return strcpy(buf, "****"); : return buf; : } while (1); :} : /* * Total samples for file : "strings/apr_cpystrn.c" * * 5 0.0087 */ :/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as : * applicable. : * : * Licensed 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. : */ : :#include "apr.h" :#include "apr_strings.h" :#include "apr_private.h" :#include "apr_lib.h" : :#if APR_HAVE_SYS_TYPES_H :#include :#endif :#if APR_HAVE_STRING_H :#include :#endif :#if APR_HAVE_CTYPE_H :#include :#endif : :/* : * Apache's "replacement" for the strncpy() function. We roll our : * own to implement these specific changes: : * (1) strncpy() doesn't always null terminate and we want it to. : * (2) strncpy() null fills, which is bogus, esp. when copy 8byte : * strings into 8k blocks. : * (3) Instead of returning the pointer to the beginning of : * the destination string, we return a pointer to the : * terminating '\0' to allow us to "check" for truncation : * : * apr_cpystrn() follows the same call structure as strncpy(). : */ : :APR_DECLARE(char *) apr_cpystrn(char *dst, const char *src, apr_size_t dst_size) 1 0.0017 :{ : : char *d, *end; : 2 0.0035 : if (dst_size == 0) { /* apr_cpystrn total: 5 0.0087 */ : return (dst); : } : : d = dst; : end = dst + dst_size - 1; : : for (; d < end; ++d, ++src) { 2 0.0035 : if (!(*d = *src)) { : return (d); : } : } : : *d = '\0'; /* always null terminate */ : : return (d); :} : : :/* : * This function provides a way to parse a generic argument string : * into a standard argv[] form of argument list. It respects the : * usual "whitespace" and quoteing rules. In the future this could : * be expanded to include support for the apr_call_exec command line : * string processing (including converting '+' to ' ' and doing the : * url processing. It does not currently support this function. : * : * token_context: Context from which pool allocations will occur. : * arg_str: Input argument string for conversion to argv[]. : * argv_out: Output location. This is a pointer to an array : * of pointers to strings (ie. &(char *argv[]). : * This value will be allocated from the contexts : * pool and filled in with copies of the tokens : * found during parsing of the arg_str. : */ :APR_DECLARE(apr_status_t) apr_tokenize_to_argv(const char *arg_str, : char ***argv_out, : apr_pool_t *token_context) :{ : const char *cp; : const char *ct; : char *cleaned, *dirty; : int escaped; : int isquoted, numargs = 0, argnum; : :#define SKIP_WHITESPACE(cp) \ : for ( ; *cp == ' ' || *cp == '\t'; ) { \ : cp++; \ : }; : :#define CHECK_QUOTATION(cp,isquoted) \ : isquoted = 0; \ : if (*cp == '"') { \ : isquoted = 1; \ : cp++; \ : } \ : else if (*cp == '\'') { \ : isquoted = 2; \ : cp++; \ : } : :/* DETERMINE_NEXTSTRING: : * At exit, cp will point to one of the following: NULL, SPACE, TAB or QUOTE. : * NULL implies the argument string has been fully traversed. : */ :#define DETERMINE_NEXTSTRING(cp,isquoted) \ : for ( ; *cp != '\0'; cp++) { \ : if ( (isquoted && (*cp == ' ' || *cp == '\t')) \ : || (*cp == '\\' && (*(cp+1) == ' ' || *(cp+1) == '\t' || \ : *(cp+1) == '"' || *(cp+1) == '\''))) { \ : cp++; \ : continue; \ : } \ : if ( (!isquoted && (*cp == ' ' || *cp == '\t')) \ : || (isquoted == 1 && *cp == '"') \ : || (isquoted == 2 && *cp == '\'') ) { \ : break; \ : } \ : } : :/* REMOVE_ESCAPE_CHARS: : * Compresses the arg string to remove all of the '\' escape chars. : * The final argv strings should not have any extra escape chars in it. : */ :#define REMOVE_ESCAPE_CHARS(cleaned, dirty, escaped) \ : escaped = 0; \ : while(*dirty) { \ : if (!escaped && *dirty == '\\') { \ : escaped = 1; \ : } \ : else { \ : escaped = 0; \ : *cleaned++ = *dirty; \ : } \ : ++dirty; \ : } \ : *cleaned = 0; /* last line of macro... */ : : cp = arg_str; : SKIP_WHITESPACE(cp); : ct = cp; : : /* This is ugly and expensive, but if anyone wants to figure a : * way to support any number of args without counting and : * allocating, please go ahead and change the code. : * : * Must account for the trailing NULL arg. : */ : numargs = 1; : while (*ct != '\0') { : CHECK_QUOTATION(ct, isquoted); : DETERMINE_NEXTSTRING(ct, isquoted); : if (*ct != '\0') { : ct++; : } : numargs++; : SKIP_WHITESPACE(ct); : } : *argv_out = apr_palloc(token_context, numargs * sizeof(char*)); : : /* determine first argument */ : for (argnum = 0; argnum < (numargs-1); argnum++) { : SKIP_WHITESPACE(cp); : CHECK_QUOTATION(cp, isquoted); : ct = cp; : DETERMINE_NEXTSTRING(cp, isquoted); : cp++; : (*argv_out)[argnum] = apr_palloc(token_context, cp - ct); : apr_cpystrn((*argv_out)[argnum], ct, cp - ct); : cleaned = dirty = (*argv_out)[argnum]; : REMOVE_ESCAPE_CHARS(cleaned, dirty, escaped); : } : (*argv_out)[argnum] = NULL; : : return APR_SUCCESS; :} : :/* Filepath_name_get returns the final element of the pathname. : * Using the current platform's filename syntax. : * "/foo/bar/gum" -> "gum" : * "/foo/bar/gum/" -> "" : * "gum" -> "gum" : * "wi\\n32\\stuff" -> "stuff : * : * Corrected Win32 to accept "a/b\\stuff", "a:stuff" : */ : :APR_DECLARE(const char *) apr_filepath_name_get(const char *pathname) :{ : const char path_separator = '/'; : const char *s = strrchr(pathname, path_separator); : :#ifdef WIN32 : const char path_separator_win = '\\'; : const char drive_separator_win = ':'; : const char *s2 = strrchr(pathname, path_separator_win); : : if (s2 > s) s = s2; : : if (!s) s = strrchr(pathname, drive_separator_win); :#endif : : return s ? ++s : pathname; :} : :/* length of dest assumed >= length of src : * collapse in place (src == dest) is legal. : * returns terminating null ptr to dest string. : */ :APR_DECLARE(char *) apr_collapse_spaces(char *dest, const char *src) :{ : while (*src) { : if (!apr_isspace(*src)) : *dest++ = *src; : ++src; : } : *dest = 0; : return (dest); :} : :#if !APR_HAVE_STRDUP :char *strdup(const char *str) :{ : char *sdup; : size_t len = strlen(str) + 1; : : sdup = (char *) malloc(len); : memcpy(sdup, str, len); : : return sdup; :} :#endif : :/* The following two routines were donated for SVR4 by Andreas Vogel */ :#if (!APR_HAVE_STRCASECMP && !APR_HAVE_STRICMP) :int strcasecmp(const char *a, const char *b) :{ : const char *p = a; : const char *q = b; : for (p = a, q = b; *p && *q; p++, q++) { : int diff = apr_tolower(*p) - apr_tolower(*q); : if (diff) : return diff; : } : if (*p) : return 1; /* p was longer than q */ : if (*q) : return -1; /* p was shorter than q */ : return 0; /* Exact match */ :} : :#endif : :#if (!APR_HAVE_STRNCASECMP && !APR_HAVE_STRNICMP) :int strncasecmp(const char *a, const char *b, size_t n) :{ : const char *p = a; : const char *q = b; : : for (p = a, q = b; /*NOTHING */ ; p++, q++) { : int diff; : if (p == a + n) : return 0; /* Match up to n characters */ : if (!(*p && *q)) : return *p - *q; : diff = apr_tolower(*p) - apr_tolower(*q); : if (diff) : return diff; : } : /*NOTREACHED */ :} :#endif : :/* The following routine was donated for UTS21 by dwd@bell-labs.com */ :#if (!APR_HAVE_STRSTR) :char *strstr(char *s1, char *s2) :{ : char *p1, *p2; : if (*s2 == '\0') { : /* an empty s2 */ : return(s1); : } : while((s1 = strchr(s1, *s2)) != NULL) { : /* found first character of s2, see if the rest matches */ : p1 = s1; : p2 = s2; : while (*++p1 == *++p2) { : if (*p1 == '\0') { : /* both strings ended together */ : return(s1); : } : } : if (*p2 == '\0') { : /* second string ended, a match */ : break; : } : /* didn't find a match here, try starting at next character in s1 */ : s1++; : } : return(s1); :} :#endif : /* * Total samples for file : "network_io/unix/sockopt.c" * * 3 0.0052 */ :/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as : * applicable. : * : * Licensed 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. : */ : :#include "apr_arch_networkio.h" :#include "apr_strings.h" : : :static apr_status_t soblock(int sd) :{ :/* BeOS uses setsockopt at present for non blocking... */ :#ifndef BEOS : 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 APR how to make sockets blocking on your platform. :#endif : if (fcntl(sd, F_SETFL, fd_flags) == -1) { : return errno; : } :#else : int on = 0; : if (setsockopt(sd, SOL_SOCKET, SO_NONBLOCK, &on, sizeof(int)) < 0) : return errno; :#endif /* BEOS */ : return APR_SUCCESS; :} : :static apr_status_t sononblock(int sd) :{ /* sononblock total: 1 0.0017 */ :#ifndef BEOS : int fd_flags; : 1 0.0017 : 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 APR how to make sockets non-blocking on your platform. :#endif : if (fcntl(sd, F_SETFL, fd_flags) == -1) { : return errno; : } :#else : int on = 1; : if (setsockopt(sd, SOL_SOCKET, SO_NONBLOCK, &on, sizeof(int)) < 0) : return errno; :#endif /* BEOS */ : return APR_SUCCESS; :} : : :apr_status_t apr_socket_timeout_set(apr_socket_t *sock, apr_interval_time_t t) :{ : apr_status_t stat; : : /* If our new timeout is non-negative and our old timeout was : * negative, then we need to ensure that we are non-blocking. : * Conversely, if our new timeout is negative and we had : * non-negative timeout, we must make sure our socket is blocking. : * We want to avoid calling fcntl more than necessary on the : * socket. : */ : if (t >= 0 && sock->timeout < 0) { : if (apr_is_option_set(sock, APR_SO_NONBLOCK) != 1) { : if ((stat = sononblock(sock->socketdes)) != APR_SUCCESS) { : return stat; : } : apr_set_option(sock, APR_SO_NONBLOCK, 1); : } : } : else if (t < 0 && sock->timeout >= 0) { : if (apr_is_option_set(sock, APR_SO_NONBLOCK) != 0) { : if ((stat = soblock(sock->socketdes)) != APR_SUCCESS) { : return stat; : } : apr_set_option(sock, APR_SO_NONBLOCK, 0); : } : } : /* must disable the incomplete read support if we disable : * a timeout : */ : if (t <= 0) { : sock->options &= ~APR_INCOMPLETE_READ; : } : sock->timeout = t; : return APR_SUCCESS; :} : : :apr_status_t apr_socket_opt_set(apr_socket_t *sock, : apr_int32_t opt, apr_int32_t on) :{ /* apr_socket_opt_set total: 2 0.0035 */ : int one; : apr_status_t rv; : : if (on) : one = 1; : else : one = 0; : switch(opt) { : case APR_SO_KEEPALIVE: :#ifdef SO_KEEPALIVE : if (on != apr_is_option_set(sock, APR_SO_KEEPALIVE)) { : if (setsockopt(sock->socketdes, SOL_SOCKET, SO_KEEPALIVE, (void *)&one, sizeof(int)) == -1) { : return errno; : } : apr_set_option(sock, APR_SO_KEEPALIVE, on); : } :#else : return APR_ENOTIMPL; :#endif : break; : case APR_SO_DEBUG: : if (on != apr_is_option_set(sock, APR_SO_DEBUG)) { : if (setsockopt(sock->socketdes, SOL_SOCKET, SO_DEBUG, (void *)&one, sizeof(int)) == -1) { : return errno; : } : apr_set_option(sock, APR_SO_DEBUG, on); : } : break; : case APR_SO_REUSEADDR: : if (on != apr_is_option_set(sock, APR_SO_REUSEADDR)) { : if (setsockopt(sock->socketdes, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(int)) == -1) { : return errno; : } : apr_set_option(sock, APR_SO_REUSEADDR, on); : } : break; : case APR_SO_SNDBUF: :#ifdef SO_SNDBUF : if (setsockopt(sock->socketdes, SOL_SOCKET, SO_SNDBUF, (void *)&on, sizeof(int)) == -1) { : return errno; : } :#else : return APR_ENOTIMPL; :#endif : break; : case APR_SO_RCVBUF: :#ifdef SO_RCVBUF : if (setsockopt(sock->socketdes, SOL_SOCKET, SO_RCVBUF, (void *)&on, sizeof(int)) == -1) { : return errno; : } :#else : return APR_ENOTIMPL; :#endif : break; : case APR_SO_NONBLOCK: : if (apr_is_option_set(sock, APR_SO_NONBLOCK) != on) { : if (on) { : if ((rv = sononblock(sock->socketdes)) != APR_SUCCESS) : return rv; : } : else { : if ((rv = soblock(sock->socketdes)) != APR_SUCCESS) : return rv; : } : apr_set_option(sock, APR_SO_NONBLOCK, on); : } : break; : case APR_SO_LINGER: :#ifdef SO_LINGER : if (apr_is_option_set(sock, APR_SO_LINGER) != on) { : struct linger li; : li.l_onoff = on; : li.l_linger = APR_MAX_SECS_TO_LINGER; : if (setsockopt(sock->socketdes, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(struct linger)) == -1) { : return errno; : } : apr_set_option(sock, APR_SO_LINGER, on); : } :#else : return APR_ENOTIMPL; :#endif : break; : case APR_TCP_DEFER_ACCEPT: :#if defined(TCP_DEFER_ACCEPT) : if (apr_is_option_set(sock, APR_TCP_DEFER_ACCEPT) != on) { : int optlevel = IPPROTO_TCP; : int optname = TCP_DEFER_ACCEPT; : : if (setsockopt(sock->socketdes, optlevel, optname, : (void *)&on, sizeof(int)) == -1) { : return errno; : } : apr_set_option(sock, APR_TCP_DEFER_ACCEPT, on); : } :#else : return APR_ENOTIMPL; :#endif : break; : case APR_TCP_NODELAY: :#if defined(TCP_NODELAY) : if (apr_is_option_set(sock, APR_TCP_NODELAY) != on) { : int optlevel = IPPROTO_TCP; : int optname = TCP_NODELAY; : :#if APR_HAVE_SCTP : if (sock->protocol == IPPROTO_SCTP) { : optlevel = IPPROTO_SCTP; : optname = SCTP_NODELAY; : } :#endif : if (setsockopt(sock->socketdes, optlevel, optname, (void *)&on, sizeof(int)) == -1) { : return errno; : } : apr_set_option(sock, APR_TCP_NODELAY, on); : } :#else : /* BeOS pre-BONE has TCP_NODELAY set by default. : * As it can't be turned off we might as well check if they're asking : * for it to be turned on! : */ :#ifdef BEOS : if (on == 1) : return APR_SUCCESS; : else :#endif : return APR_ENOTIMPL; :#endif : break; : case APR_TCP_NOPUSH: :#if APR_TCP_NOPUSH_FLAG : /* TCP_NODELAY and TCP_CORK are mutually exclusive on Linux : * kernels < 2.6; on newer kernels they can be used together : * and TCP_CORK takes preference, which is the desired : * behaviour. On older kernels, TCP_NODELAY must be toggled : * to "off" whilst TCP_CORK is in effect. */ : if (apr_is_option_set(sock, APR_TCP_NOPUSH) != on) { :#ifndef HAVE_TCP_NODELAY_WITH_CORK : int optlevel = IPPROTO_TCP; : int optname = TCP_NODELAY; : :#if APR_HAVE_SCTP : if (sock->protocol == IPPROTO_SCTP) { : optlevel = IPPROTO_SCTP; : optname = SCTP_NODELAY; : } :#endif : /* OK we're going to change some settings here... */ : if (apr_is_option_set(sock, APR_TCP_NODELAY) == 1 && on) { : /* Now toggle TCP_NODELAY to off, if TCP_CORK is being : * turned on: */ : int tmpflag = 0; : if (setsockopt(sock->socketdes, optlevel, optname, : (void*)&tmpflag, sizeof(int)) == -1) { : return errno; : } : apr_set_option(sock, APR_RESET_NODELAY, 1); : apr_set_option(sock, APR_TCP_NODELAY, 0); : } else if (on) { : apr_set_option(sock, APR_RESET_NODELAY, 0); : } :#endif /* HAVE_TCP_NODELAY_WITH_CORK */ : : /* OK, now we can just set the TCP_NOPUSH flag accordingly...*/ : if (setsockopt(sock->socketdes, IPPROTO_TCP, APR_TCP_NOPUSH_FLAG, : (void*)&on, sizeof(int)) == -1) { : return errno; : } : apr_set_option(sock, APR_TCP_NOPUSH, on); :#ifndef HAVE_TCP_NODELAY_WITH_CORK : if (!on && apr_is_option_set(sock, APR_RESET_NODELAY)) { : /* Now, if TCP_CORK was just turned off, turn : * TCP_NODELAY back on again if it was earlier toggled : * to off: */ : int tmpflag = 1; : if (setsockopt(sock->socketdes, optlevel, optname, : (void*)&tmpflag, sizeof(int)) == -1) { : return errno; : } : apr_set_option(sock, APR_RESET_NODELAY,0); : apr_set_option(sock, APR_TCP_NODELAY, 1); : } :#endif /* HAVE_TCP_NODELAY_WITH_CORK */ : } :#else : return APR_ENOTIMPL; :#endif : break; : case APR_INCOMPLETE_READ: : apr_set_option(sock, APR_INCOMPLETE_READ, on); : break; : case APR_IPV6_V6ONLY: :#if APR_HAVE_IPV6 && defined(IPV6_V6ONLY) : /* we don't know the initial setting of this option, : * so don't check sock->options since that optimization : * won't work : */ : if (setsockopt(sock->socketdes, IPPROTO_IPV6, IPV6_V6ONLY, : (void *)&on, sizeof(int)) == -1) { : return errno; : } : apr_set_option(sock, APR_IPV6_V6ONLY, on); :#else : return APR_ENOTIMPL; :#endif : break; : default: : return APR_EINVAL; : } : : return APR_SUCCESS; 2 0.0035 :} : : :apr_status_t apr_socket_timeout_get(apr_socket_t *sock, apr_interval_time_t *t) :{ : *t = sock->timeout; : return APR_SUCCESS; :} : : :apr_status_t apr_socket_opt_get(apr_socket_t *sock, : apr_int32_t opt, apr_int32_t *on) :{ : switch(opt) { : default: : *on = apr_is_option_set(sock, opt); : } : return APR_SUCCESS; :} : : :apr_status_t apr_socket_atmark(apr_socket_t *sock, int *atmark) :{ :#ifndef BEOS_R5 : int oobmark; : : if (ioctl(sock->socketdes, SIOCATMARK, (void*) &oobmark) < 0) : return apr_get_netos_error(); : : *atmark = (oobmark != 0); : : return APR_SUCCESS; :#else /* BEOS_R5 */ : return APR_ENOTIMPL; :#endif :} : :apr_status_t apr_gethostname(char *buf, apr_int32_t len, apr_pool_t *cont) :{ :#ifdef BEOS_R5 : if (gethostname(buf, len) == 0) { :#else : if (gethostname(buf, len) != 0) { :#endif : buf[0] = '\0'; : return errno; : } : else if (!memchr(buf, '\0', len)) { /* buffer too small */ : /* note... most platforms just truncate in this condition : * linux+glibc return an error : */ : buf[0] = '\0'; : return APR_ENAMETOOLONG; : } : return APR_SUCCESS; :} : :#if APR_HAS_SO_ACCEPTFILTER :apr_status_t apr_socket_accept_filter(apr_socket_t *sock, char *name, : char *args) :{ : struct accept_filter_arg af; : strncpy(af.af_name, name, 16); : strncpy(af.af_arg, args, 256 - 16); : : if ((setsockopt(sock->socketdes, SOL_SOCKET, SO_ACCEPTFILTER, : &af, sizeof(af))) < 0) { : return errno; : } : return APR_SUCCESS; :} :#endif /* * Total samples for file : "misc/unix/rand.c" * * 3 0.0052 */ :/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as : * applicable. : * : * Licensed 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. : */ : :#define APR_WANT_MEMFUNC :#include "apr_want.h" :#include "apr_general.h" : :#include "apr_arch_misc.h" :#include :#if APR_HAVE_SYS_TYPES_H :#include :#endif :#if APR_HAVE_SYS_SOCKET_H :#include :#endif :#if APR_HAVE_FCNTL_H :#include :#endif :#if APR_HAVE_UNISTD_H :#include :#endif :#if APR_HAVE_SYS_UN_H :#include :#endif :#if defined(HAVE_UUID_H) :#include :#elif defined(HAVE_UUID_UUID_H) :#include :#elif defined(HAVE_SYS_UUID_H) :#include :#endif : :#ifndef SHUT_RDWR :#define SHUT_RDWR 2 :#endif : :#if APR_HAS_OS_UUID : :#if defined(HAVE_UUID_CREATE) : :APR_DECLARE(apr_status_t) apr_os_uuid_get(unsigned char *uuid_data) :{ : uint32_t rv; : uuid_t g; : : uuid_create(&g, &rv); : : if (rv != uuid_s_ok) : return APR_EGENERAL; : : memcpy(uuid_data, &g, sizeof(uuid_t)); : : return APR_SUCCESS; :} : :#elif defined(HAVE_UUID_GENERATE) : :APR_DECLARE(apr_status_t) apr_os_uuid_get(unsigned char *uuid_data) 3 0.0052 :{ /* apr_os_uuid_get total: 3 0.0052 */ : uuid_t g; : : uuid_generate(g); : : memcpy(uuid_data, g, sizeof(uuid_t)); : : return APR_SUCCESS; :} :#endif : :#endif /* APR_HAS_OS_UUID */ : :#if APR_HAS_RANDOM : :APR_DECLARE(apr_status_t) apr_generate_random_bytes(unsigned char *buf, : apr_size_t length) :{ :#ifdef DEV_RANDOM : : int fd = -1; : : /* On BSD/OS 4.1, /dev/random gives out 8 bytes at a time, then : * gives EOF, so reading 'length' bytes may require opening the : * device several times. */ : do { : apr_ssize_t rc; : : if (fd == -1) : if ((fd = open(DEV_RANDOM, O_RDONLY)) == -1) : return errno; : : rc = read(fd, buf, length); : if (rc < 0) { : int errnum = errno; : close(fd); : return errnum; : } : else if (rc == 0) { : close(fd); : fd = -1; /* force open() again */ : } : else { : buf += rc; : length -= rc; : } : } while (length > 0); : : close(fd); :#elif defined(OS2) : static UCHAR randbyte(); : unsigned int idx; : : for (idx=0; idx 0; egdsockname++) { : egd_path_len = strlen(*egdsockname); : : if (egd_path_len > sizeof(addr.sun_path)) { : return APR_EINVAL; : } : : memset(&addr, 0, sizeof(struct sockaddr_un)); : addr.sun_family = AF_UNIX; : memcpy(addr.sun_path, *egdsockname, egd_path_len); : egd_addr_len = APR_OFFSETOF(struct sockaddr_un, sun_path) + : egd_path_len; : : egd_socket = socket(PF_UNIX, SOCK_STREAM, 0); : : if (egd_socket == -1) { : return errno; : } : : rv = connect(egd_socket, (struct sockaddr*)&addr, egd_addr_len); : : if (rv == -1) { : bad_errno = errno; : continue; : } : : /* EGD can only return 255 bytes of data at a time. Silly. */ : while (length > 0) { : apr_ssize_t srv; : req[0] = 2; /* We'll block for now. */ : req[1] = length > 255 ? 255: length; : : srv = write(egd_socket, req, 2); : if (srv == -1) { : bad_errno = errno; : shutdown(egd_socket, SHUT_RDWR); : close(egd_socket); : break; : } : : if (srv != 2) { : shutdown(egd_socket, SHUT_RDWR); : close(egd_socket); : return APR_EGENERAL; : } : : resp_expected = req[1]; : srv = read(egd_socket, resp, resp_expected); : if (srv == -1) { : bad_errno = errno; : shutdown(egd_socket, SHUT_RDWR); : close(egd_socket); : return bad_errno; : } : : memcpy(curbuf, resp, srv); : curbuf += srv; : length -= srv; : } : : shutdown(egd_socket, SHUT_RDWR); : close(egd_socket); : } : : if (length > 0) { : /* We must have iterated through the list of sockets, : * and no go. Return the errno. : */ : return bad_errno; : } : :#elif defined(HAVE_TRUERAND) /* use truerand */ : : extern int randbyte(void); /* from the truerand library */ : unsigned int idx; : : /* this will increase the startup time of the server, unfortunately... : * (generating 20 bytes takes about 8 seconds) : */ : for (idx=0; idx :#endif :#if APR_HAVE_STDLIB_H :#include /* malloc(), free() */ :#endif :#if APR_HAVE_STRING_H :#include /* for strerror() on HP-UX */ :#endif : :#if defined(DSO_USE_DYLD) :#define DYLD_LIBRARY_HANDLE (void *)-1 :#endif : :APR_DECLARE(apr_status_t) apr_os_dso_handle_put(apr_dso_handle_t **aprdso, : apr_os_dso_handle_t osdso, : apr_pool_t *pool) :{ : *aprdso = apr_pcalloc(pool, sizeof **aprdso); : (*aprdso)->handle = osdso; : (*aprdso)->pool = pool; : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_os_dso_handle_get(apr_os_dso_handle_t *osdso, : apr_dso_handle_t *aprdso) :{ : *osdso = aprdso->handle; : return APR_SUCCESS; :} : :static apr_status_t dso_cleanup(void *thedso) 1 0.0017 :{ /* dso_cleanup total: 1 0.0017 */ : apr_dso_handle_t *dso = thedso; : : if (dso->handle == NULL) : return APR_SUCCESS; : :#if defined(DSO_USE_SHL) : shl_unload((shl_t)dso->handle); :#elif defined(DSO_USE_DYLD) : if (dso->handle != DYLD_LIBRARY_HANDLE) { : NSUnLinkModule(dso->handle, FALSE); : } :#elif defined(DSO_USE_DLFCN) : if (dlclose(dso->handle) != 0) : return APR_EINIT; :#endif : dso->handle = NULL; : : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_dso_load(apr_dso_handle_t **res_handle, : const char *path, apr_pool_t *pool) :{ :#if defined(DSO_USE_SHL) : shl_t os_handle = shl_load(path, BIND_IMMEDIATE, 0L); : :#elif defined(DSO_USE_DYLD) : NSObjectFileImage image; : NSModule os_handle = NULL; : NSObjectFileImageReturnCode dsoerr; : const char* err_msg = NULL; : dsoerr = NSCreateObjectFileImageFromFile(path, &image); : : if (dsoerr == NSObjectFileImageSuccess) { :#if defined(NSLINKMODULE_OPTION_RETURN_ON_ERROR) && defined(NSLINKMODULE_OPTION_NONE) : os_handle = NSLinkModule(image, path, : NSLINKMODULE_OPTION_RETURN_ON_ERROR | : NSLINKMODULE_OPTION_NONE); : /* If something went wrong, get the errors... */ : if (!os_handle) { : NSLinkEditErrors errors; : int errorNumber; : const char *fileName; : NSLinkEditError(&errors, &errorNumber, &fileName, &err_msg); : } :#else : os_handle = NSLinkModule(image, path, FALSE); :#endif : NSDestroyObjectFileImage(image); : } : else if ((dsoerr == NSObjectFileImageFormat || : dsoerr == NSObjectFileImageInappropriateFile) && : NSAddLibrary(path) == TRUE) { : os_handle = (NSModule)DYLD_LIBRARY_HANDLE; : } : else { : err_msg = "cannot create object file image or add library"; : } : :#elif defined(DSO_USE_DLFCN) :#if defined(OSF1) || defined(SEQUENT) || defined(SNI) ||\ : (defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)) ||\ : defined(__DragonFly__) : void *os_handle = dlopen((char *)path, RTLD_NOW | RTLD_GLOBAL); : :#else : int flags = RTLD_NOW | RTLD_GLOBAL; : void *os_handle; :#ifdef _AIX : if (strchr(path + 1, '(') && path[strlen(path) - 1] == ')') : { : /* This special archive.a(dso.so) syntax is required for : * the way libtool likes to build shared libraries on AIX. : * dlopen() support for such a library requires that the : * RTLD_MEMBER flag be enabled. : */ : flags |= RTLD_MEMBER; : } :#endif : os_handle = dlopen(path, flags); :#endif :#endif /* DSO_USE_x */ : : *res_handle = apr_pcalloc(pool, sizeof(**res_handle)); : : if(os_handle == NULL) { :#if defined(DSO_USE_SHL) : (*res_handle)->errormsg = strerror(errno); : return APR_EDSOOPEN; :#elif defined(DSO_USE_DYLD) : (*res_handle)->errormsg = (err_msg) ? err_msg : "link failed"; : return APR_EDSOOPEN; :#elif defined(DSO_USE_DLFCN) : (*res_handle)->errormsg = dlerror(); : return APR_EDSOOPEN; :#endif : } : : (*res_handle)->handle = (void*)os_handle; : (*res_handle)->pool = pool; : (*res_handle)->errormsg = NULL; : : apr_pool_cleanup_register(pool, *res_handle, dso_cleanup, apr_pool_cleanup_null); : : return APR_SUCCESS; :} : :APR_DECLARE(apr_status_t) apr_dso_unload(apr_dso_handle_t *handle) :{ : return apr_pool_cleanup_run(handle->pool, handle, dso_cleanup); :} : :APR_DECLARE(apr_status_t) apr_dso_sym(apr_dso_handle_sym_t *ressym, : apr_dso_handle_t *handle, : const char *symname) :{ :#if defined(DSO_USE_SHL) : void *symaddr = NULL; : int status; : : errno = 0; : status = shl_findsym((shl_t *)&handle->handle, symname, TYPE_PROCEDURE, &symaddr); : if (status == -1 && errno == 0) /* try TYPE_DATA instead */ : status = shl_findsym((shl_t *)&handle->handle, symname, TYPE_DATA, &symaddr); : if (status == -1) : return APR_ESYMNOTFOUND; : *ressym = symaddr; : return APR_SUCCESS; : :#elif defined(DSO_USE_DYLD) : void *retval = NULL; : NSSymbol symbol; : char *symname2 = (char*)malloc(sizeof(char)*(strlen(symname)+2)); : sprintf(symname2, "_%s", symname); :#ifdef NSLINKMODULE_OPTION_PRIVATE : if (handle->handle == DYLD_LIBRARY_HANDLE) { : symbol = NSLookupAndBindSymbol(symname2); : } : else { : symbol = NSLookupSymbolInModule((NSModule)handle->handle, symname2); : } :#else : symbol = NSLookupAndBindSymbol(symname2); :#endif : free(symname2); : if (symbol == NULL) { : handle->errormsg = "undefined symbol"; : return APR_ESYMNOTFOUND; : } : retval = NSAddressOfSymbol(symbol); : if (retval == NULL) { : handle->errormsg = "cannot resolve symbol"; : return APR_ESYMNOTFOUND; : } : *ressym = retval; : return APR_SUCCESS; :#elif defined(DSO_USE_DLFCN) : :#if defined(DLSYM_NEEDS_UNDERSCORE) : void *retval; : char *symbol = (char*)malloc(sizeof(char)*(strlen(symname)+2)); : sprintf(symbol, "_%s", symname); : retval = dlsym(handle->handle, symbol); : free(symbol); :#elif defined(SEQUENT) || defined(SNI) : void *retval = dlsym(handle->handle, (char *)symname); :#else : void *retval = dlsym(handle->handle, symname); :#endif /* DLSYM_NEEDS_UNDERSCORE */ : : if (retval == NULL) { : handle->errormsg = dlerror(); : return APR_ESYMNOTFOUND; : } : : *ressym = retval; : : return APR_SUCCESS; :#endif /* DSO_USE_x */ :} : :APR_DECLARE(const char *) apr_dso_error(apr_dso_handle_t *dso, char *buffer, : apr_size_t buflen) :{ : if (dso->errormsg) { : apr_cpystrn(buffer, dso->errormsg, buflen); : return dso->errormsg; : } : return "No Error"; :} : :#endif