Lines 151-158
Link Here
|
151 |
#include "apr_hash.h" |
151 |
#include "apr_hash.h" |
152 |
#include "apr_optional.h" |
152 |
#include "apr_optional.h" |
153 |
#include "apr_anylock.h" |
153 |
#include "apr_anylock.h" |
|
|
154 |
#include "apr_env.h" |
154 |
|
155 |
|
155 |
#define APR_WANT_STRFUNC |
156 |
#define APR_WANT_STRFUNC |
|
|
157 |
#define APR_WANT_BYTEFUNC /* for htons() et al */ |
156 |
#include "apr_want.h" |
158 |
#include "apr_want.h" |
157 |
|
159 |
|
158 |
#include "ap_config.h" |
160 |
#include "ap_config.h" |
Lines 164-169
Link Here
|
164 |
#include "http_protocol.h" |
166 |
#include "http_protocol.h" |
165 |
#include "util_time.h" |
167 |
#include "util_time.h" |
166 |
#include "ap_mpm.h" |
168 |
#include "ap_mpm.h" |
|
|
169 |
#include "scoreboard.h" |
167 |
|
170 |
|
168 |
#if APR_HAVE_UNISTD_H |
171 |
#if APR_HAVE_UNISTD_H |
169 |
#include <unistd.h> |
172 |
#include <unistd.h> |
Lines 177-201
Link Here
|
177 |
module AP_MODULE_DECLARE_DATA log_config_module; |
180 |
module AP_MODULE_DECLARE_DATA log_config_module; |
178 |
|
181 |
|
179 |
|
182 |
|
|
|
183 |
typedef struct { |
184 |
apr_file_t *handle; |
185 |
apr_size_t outcnt; |
186 |
char outbuf[LOG_BUFSIZE]; |
187 |
apr_anylock_t mutex; |
188 |
} buffered_log; |
189 |
|
180 |
static int xfer_flags = (APR_WRITE | APR_APPEND | APR_CREATE | APR_LARGEFILE); |
190 |
static int xfer_flags = (APR_WRITE | APR_APPEND | APR_CREATE | APR_LARGEFILE); |
181 |
static apr_fileperms_t xfer_perms = APR_OS_DEFAULT; |
191 |
static apr_fileperms_t xfer_perms = APR_OS_DEFAULT; |
182 |
static apr_hash_t *log_hash; |
192 |
static apr_hash_t *log_hash; |
|
|
193 |
static apr_status_t write_atomic_pipe_chunks(request_rec *r, |
194 |
void *handle, |
195 |
const char *str, |
196 |
apr_size_t len, |
197 |
buffered_log *buf); |
183 |
static apr_status_t ap_default_log_writer(request_rec *r, |
198 |
static apr_status_t ap_default_log_writer(request_rec *r, |
184 |
void *handle, |
199 |
void *handle, |
185 |
const char **strs, |
200 |
const char **strs, |
186 |
int *strl, |
201 |
int *strl, |
187 |
int nelts, |
202 |
int nelts, |
188 |
apr_size_t len); |
203 |
apr_size_t len, |
|
|
204 |
int chunk_msgs); |
189 |
static apr_status_t ap_buffered_log_writer(request_rec *r, |
205 |
static apr_status_t ap_buffered_log_writer(request_rec *r, |
190 |
void *handle, |
206 |
void *handle, |
191 |
const char **strs, |
207 |
const char **strs, |
192 |
int *strl, |
208 |
int *strl, |
193 |
int nelts, |
209 |
int nelts, |
194 |
apr_size_t len); |
210 |
apr_size_t len, |
|
|
211 |
int chunk_msgs); |
195 |
static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s, |
212 |
static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s, |
196 |
const char* name); |
213 |
config_log_state* cls); |
197 |
static void *ap_buffered_log_writer_init(apr_pool_t *p, server_rec *s, |
214 |
static void *ap_buffered_log_writer_init(apr_pool_t *p, server_rec *s, |
198 |
const char* name); |
215 |
config_log_state* cls); |
199 |
|
216 |
|
200 |
static ap_log_writer_init *ap_log_set_writer_init(ap_log_writer_init *handle); |
217 |
static ap_log_writer_init *ap_log_set_writer_init(ap_log_writer_init *handle); |
201 |
static ap_log_writer *ap_log_set_writer(ap_log_writer *handle); |
218 |
static ap_log_writer *ap_log_set_writer(ap_log_writer *handle); |
Lines 204-224
static ap_log_writer_init *log_writer_init = ap_default_log_writer_init;
Link Here
|
204 |
static int buffered_logs = 0; /* default unbuffered */ |
221 |
static int buffered_logs = 0; /* default unbuffered */ |
205 |
static apr_array_header_t *all_buffered_logs = NULL; |
222 |
static apr_array_header_t *all_buffered_logs = NULL; |
206 |
|
223 |
|
207 |
/* POSIX.1 defines PIPE_BUF as the maximum number of bytes that is |
|
|
208 |
* guaranteed to be atomic when writing a pipe. And PIPE_BUF >= 512 |
209 |
* is guaranteed. So we'll just guess 512 in the event the system |
210 |
* doesn't have this. Now, for file writes there is actually no limit, |
211 |
* the entire write is atomic. Whether all systems implement this |
212 |
* correctly is another question entirely ... so we'll just use PIPE_BUF |
213 |
* because it's probably a good guess as to what is implemented correctly |
214 |
* everywhere. |
215 |
*/ |
216 |
#ifdef PIPE_BUF |
217 |
#define LOG_BUFSIZE PIPE_BUF |
218 |
#else |
219 |
#define LOG_BUFSIZE (512) |
220 |
#endif |
221 |
|
222 |
/* |
224 |
/* |
223 |
* multi_log_state is our per-(virtual)-server configuration. We store |
225 |
* multi_log_state is our per-(virtual)-server configuration. We store |
224 |
* an array of the logs we are going to use, each of type config_log_state. |
226 |
* an array of the logs we are going to use, each of type config_log_state. |
Lines 252-265
typedef struct {
Link Here
|
252 |
* set to a opaque structure (usually a fd) after it is opened. |
254 |
* set to a opaque structure (usually a fd) after it is opened. |
253 |
|
255 |
|
254 |
*/ |
256 |
*/ |
255 |
typedef struct { |
257 |
struct config_log_state { |
256 |
apr_file_t *handle; |
|
|
257 |
apr_size_t outcnt; |
258 |
char outbuf[LOG_BUFSIZE]; |
259 |
apr_anylock_t mutex; |
260 |
} buffered_log; |
261 |
|
262 |
typedef struct { |
263 |
const char *fname; |
258 |
const char *fname; |
264 |
const char *format_string; |
259 |
const char *format_string; |
265 |
apr_array_header_t *format; |
260 |
apr_array_header_t *format; |
Lines 269-275
typedef struct {
Link Here
|
269 |
ap_expr_info_t *condition_expr; |
264 |
ap_expr_info_t *condition_expr; |
270 |
/** place of definition or NULL if already checked */ |
265 |
/** place of definition or NULL if already checked */ |
271 |
const ap_directive_t *directive; |
266 |
const ap_directive_t *directive; |
272 |
} config_log_state; |
267 |
int chunked; |
|
|
268 |
}; |
273 |
|
269 |
|
274 |
/* |
270 |
/* |
275 |
* log_request_state holds request specific log data that is not |
271 |
* log_request_state holds request specific log data that is not |
Lines 1175-1181
static int config_log_transaction(request_rec *r, config_log_state *cls,
Link Here
|
1175 |
"log writer isn't correctly setup"); |
1171 |
"log writer isn't correctly setup"); |
1176 |
return HTTP_INTERNAL_SERVER_ERROR; |
1172 |
return HTTP_INTERNAL_SERVER_ERROR; |
1177 |
} |
1173 |
} |
1178 |
rv = log_writer(r, cls->log_writer, strs, strl, format->nelts, len); |
1174 |
rv = log_writer(r, cls->log_writer, strs, strl, format->nelts, len, cls->chunked); |
1179 |
if (rv != APR_SUCCESS) { |
1175 |
if (rv != APR_SUCCESS) { |
1180 |
ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, APLOGNO(00646) |
1176 |
ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, APLOGNO(00646) |
1181 |
"Error writing to %s", cls->fname); |
1177 |
"Error writing to %s", cls->fname); |
Lines 1327-1332
static const char *add_custom_log(cmd_parms *cmd, void *dummy, const char *fn,
Link Here
|
1327 |
} |
1323 |
} |
1328 |
|
1324 |
|
1329 |
cls->fname = fn; |
1325 |
cls->fname = fn; |
|
|
1326 |
if (fn && (!strncmp(fn, "|<", 2) || !strncmp(fn, "||<", 3))) { |
1327 |
cls->chunked = 1; |
1328 |
} |
1330 |
cls->format_string = fmt; |
1329 |
cls->format_string = fmt; |
1331 |
cls->directive = cmd->directive; |
1330 |
cls->directive = cmd->directive; |
1332 |
if (fmt == NULL) { |
1331 |
if (fmt == NULL) { |
Lines 1386-1391
static const char *set_buffered_logs_on(cmd_parms *parms, void *dummy, int flag)
Link Here
|
1386 |
} |
1385 |
} |
1387 |
return NULL; |
1386 |
return NULL; |
1388 |
} |
1387 |
} |
|
|
1388 |
|
1389 |
static const command_rec config_log_cmds[] = |
1389 |
static const command_rec config_log_cmds[] = |
1390 |
{ |
1390 |
{ |
1391 |
AP_INIT_TAKE23("CustomLog", add_custom_log, NULL, RSRC_CONF, |
1391 |
AP_INIT_TAKE23("CustomLog", add_custom_log, NULL, RSRC_CONF, |
Lines 1414-1420
static config_log_state *open_config_log(server_rec *s, apr_pool_t *p,
Link Here
|
1414 |
return cls; /* Leave it NULL to decline. */ |
1414 |
return cls; /* Leave it NULL to decline. */ |
1415 |
} |
1415 |
} |
1416 |
|
1416 |
|
1417 |
cls->log_writer = log_writer_init(p, s, cls->fname); |
1417 |
cls->log_writer = log_writer_init(p, s, cls); |
1418 |
if (cls->log_writer == NULL) |
1418 |
if (cls->log_writer == NULL) |
1419 |
return NULL; |
1419 |
return NULL; |
1420 |
|
1420 |
|
Lines 1603-1614
static ap_log_writer *ap_log_set_writer(ap_log_writer *handle)
Link Here
|
1603 |
return old; |
1603 |
return old; |
1604 |
} |
1604 |
} |
1605 |
|
1605 |
|
|
|
1606 |
static apr_status_t write_atomic_pipe_chunks(request_rec *r, |
1607 |
void *handle, |
1608 |
const char *str, |
1609 |
apr_size_t len, |
1610 |
buffered_log *buf) |
1611 |
{ |
1612 |
apr_status_t rv; |
1613 |
apr_size_t chunk_body_len; |
1614 |
apr_size_t write_cnt; |
1615 |
apr_size_t msg_read_len = 0; |
1616 |
uint32_t proc_slot_xfer, thread_slot_xfer; |
1617 |
char msg_chunk[LOG_BUFSIZE]; |
1618 |
uint32_t chunk_order = 1; |
1619 |
uint32_t chunk_order_xfer; |
1620 |
uint32_t total_chunk_cnt = (len / LOG_BUFSIZE_LESS_CHUNKHEAD) + |
1621 |
!!(len % LOG_BUFSIZE_LESS_CHUNKHEAD); |
1622 |
uint32_t total_chunk_cnt_xfer = htonl(total_chunk_cnt); |
1623 |
uint32_t chunk_body_len_xfer; |
1624 |
ap_sb_handle_t *sbh = r->connection->sbh; |
1625 |
uint32_t cpy_pos = 0; |
1626 |
char *msg_buf = msg_chunk; |
1627 |
|
1628 |
if (buf != NULL) |
1629 |
msg_buf = &buf->outbuf[buf->outcnt]; |
1630 |
|
1631 |
proc_slot_xfer = htonl(sbh->child_num); |
1632 |
thread_slot_xfer = htonl(sbh->thread_num); |
1633 |
|
1634 |
/* |
1635 |
* Split the log line into PIPE_BUF chunks to avoid interleaving concurrent |
1636 |
* writes to the pipe that may corrupt the log data. |
1637 |
*/ |
1638 |
do { |
1639 |
if (buf == NULL) |
1640 |
cpy_pos = 0; |
1641 |
chunk_body_len = len - msg_read_len; |
1642 |
if (chunk_body_len > LOG_BUFSIZE_LESS_CHUNKHEAD) |
1643 |
chunk_body_len = LOG_BUFSIZE_LESS_CHUNKHEAD; |
1644 |
memcpy(msg_buf + cpy_pos, &proc_slot_xfer, sizeof(uint32_t)); |
1645 |
cpy_pos += sizeof(uint32_t); |
1646 |
memcpy(msg_buf + cpy_pos, &thread_slot_xfer, sizeof(uint32_t)); |
1647 |
cpy_pos += sizeof(uint32_t); |
1648 |
chunk_order_xfer = htonl(chunk_order); |
1649 |
memcpy(msg_buf + cpy_pos, &chunk_order_xfer, sizeof(uint32_t)); |
1650 |
cpy_pos += sizeof(uint32_t); |
1651 |
memcpy(msg_buf + cpy_pos, &total_chunk_cnt_xfer, sizeof(uint32_t)); |
1652 |
cpy_pos += sizeof(uint32_t); |
1653 |
|
1654 |
/* Convert potentially long int to message header uint32_t. */ |
1655 |
chunk_body_len_xfer = htonl(chunk_body_len); |
1656 |
memcpy(msg_buf + cpy_pos, &chunk_body_len_xfer, sizeof(uint32_t)); |
1657 |
cpy_pos += sizeof(uint32_t); |
1658 |
memcpy(msg_buf + cpy_pos, str + msg_read_len, chunk_body_len); |
1659 |
cpy_pos += chunk_body_len; |
1660 |
|
1661 |
if (buf == NULL) { |
1662 |
write_cnt = chunk_body_len + MSG_HEADER_LEN; |
1663 |
if ((rv = apr_file_write((apr_file_t*)handle, msg_buf, &write_cnt)) |
1664 |
!= APR_SUCCESS) { |
1665 |
return rv; |
1666 |
} |
1667 |
} |
1668 |
|
1669 |
msg_read_len += chunk_body_len; |
1670 |
chunk_order++; |
1671 |
|
1672 |
} while (msg_read_len < len); |
1673 |
|
1674 |
if (buf != NULL) |
1675 |
buf->outcnt += cpy_pos; |
1676 |
|
1677 |
return rv; |
1678 |
} |
1679 |
|
1606 |
static apr_status_t ap_default_log_writer( request_rec *r, |
1680 |
static apr_status_t ap_default_log_writer( request_rec *r, |
1607 |
void *handle, |
1681 |
void *handle, |
1608 |
const char **strs, |
1682 |
const char **strs, |
1609 |
int *strl, |
1683 |
int *strl, |
1610 |
int nelts, |
1684 |
int nelts, |
1611 |
apr_size_t len) |
1685 |
apr_size_t len, |
|
|
1686 |
int chunk_msgs) |
1612 |
|
1687 |
|
1613 |
{ |
1688 |
{ |
1614 |
char *str; |
1689 |
char *str; |
Lines 1627-1642
static apr_status_t ap_default_log_writer( request_rec *r,
Link Here
|
1627 |
s += strl[i]; |
1702 |
s += strl[i]; |
1628 |
} |
1703 |
} |
1629 |
|
1704 |
|
1630 |
rv = apr_file_write((apr_file_t*)handle, str, &len); |
1705 |
if (chunk_msgs) { |
|
|
1706 |
rv = write_atomic_pipe_chunks(r, handle, str, len, NULL); |
1707 |
} |
1708 |
else { |
1709 |
rv = apr_file_write((apr_file_t*)handle, str, &len); |
1710 |
} |
1631 |
|
1711 |
|
1632 |
return rv; |
1712 |
return rv; |
1633 |
} |
1713 |
} |
1634 |
static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s, |
1714 |
static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s, |
1635 |
const char* name) |
1715 |
config_log_state* cls) |
1636 |
{ |
1716 |
{ |
|
|
1717 |
apr_status_t rv; |
1718 |
const char *name = cls->fname; |
1719 |
|
1637 |
if (*name == '|') { |
1720 |
if (*name == '|') { |
1638 |
piped_log *pl; |
1721 |
piped_log *pl; |
1639 |
|
1722 |
|
|
|
1723 |
if (cls->chunked) { |
1724 |
if ((rv = apr_env_set("AP_MOD_LOG_CONFIG_CHUNKED_MSG", |
1725 |
"", p) != APR_SUCCESS)) { |
1726 |
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(03474) |
1727 |
"Unable to apr_env_set"); |
1728 |
return NULL; |
1729 |
} |
1730 |
++name; |
1731 |
if (*name == '|') |
1732 |
++name; |
1733 |
} |
1640 |
pl = ap_open_piped_log(p, name + 1); |
1734 |
pl = ap_open_piped_log(p, name + 1); |
1641 |
if (pl == NULL) { |
1735 |
if (pl == NULL) { |
1642 |
return NULL; |
1736 |
return NULL; |
Lines 1663-1673
static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s,
Link Here
|
1663 |
} |
1757 |
} |
1664 |
} |
1758 |
} |
1665 |
static void *ap_buffered_log_writer_init(apr_pool_t *p, server_rec *s, |
1759 |
static void *ap_buffered_log_writer_init(apr_pool_t *p, server_rec *s, |
1666 |
const char* name) |
1760 |
config_log_state* cls) |
1667 |
{ |
1761 |
{ |
1668 |
buffered_log *b; |
1762 |
buffered_log *b; |
1669 |
b = apr_pcalloc(p, sizeof(buffered_log)); |
1763 |
b = apr_pcalloc(p, sizeof(buffered_log)); |
1670 |
b->handle = ap_default_log_writer_init(p, s, name); |
1764 |
b->handle = ap_default_log_writer_init(p, s, cls); |
1671 |
|
1765 |
|
1672 |
if (b->handle) { |
1766 |
if (b->handle) { |
1673 |
*(buffered_log **)apr_array_push(all_buffered_logs) = b; |
1767 |
*(buffered_log **)apr_array_push(all_buffered_logs) = b; |
Lines 1681-1703
static apr_status_t ap_buffered_log_writer(request_rec *r,
Link Here
|
1681 |
const char **strs, |
1775 |
const char **strs, |
1682 |
int *strl, |
1776 |
int *strl, |
1683 |
int nelts, |
1777 |
int nelts, |
1684 |
apr_size_t len) |
1778 |
apr_size_t len, |
|
|
1779 |
int chunk_msgs) |
1685 |
|
1780 |
|
1686 |
{ |
1781 |
{ |
1687 |
char *str; |
1782 |
char *str; |
1688 |
char *s; |
1783 |
char *s; |
1689 |
int i; |
1784 |
int i; |
1690 |
apr_status_t rv; |
1785 |
apr_status_t rv; |
|
|
1786 |
apr_size_t buf_len_limit = LOG_BUFSIZE; |
1691 |
buffered_log *buf = (buffered_log*)handle; |
1787 |
buffered_log *buf = (buffered_log*)handle; |
1692 |
|
1788 |
|
1693 |
if ((rv = APR_ANYLOCK_LOCK(&buf->mutex)) != APR_SUCCESS) { |
1789 |
if ((rv = APR_ANYLOCK_LOCK(&buf->mutex)) != APR_SUCCESS) { |
1694 |
return rv; |
1790 |
return rv; |
1695 |
} |
1791 |
} |
1696 |
|
1792 |
|
1697 |
if (len + buf->outcnt > LOG_BUFSIZE) { |
1793 |
if (chunk_msgs) { |
|
|
1794 |
buf_len_limit = LOG_BUFSIZE_LESS_CHUNKHEAD; |
1795 |
} |
1796 |
|
1797 |
if (len + buf->outcnt > buf_len_limit) { |
1698 |
flush_log(buf); |
1798 |
flush_log(buf); |
1699 |
} |
1799 |
} |
1700 |
if (len >= LOG_BUFSIZE) { |
1800 |
if (len >= buf_len_limit) { |
1701 |
apr_size_t w; |
1801 |
apr_size_t w; |
1702 |
|
1802 |
|
1703 |
/* |
1803 |
/* |
Lines 1709-1725
static apr_status_t ap_buffered_log_writer(request_rec *r,
Link Here
|
1709 |
memcpy(s, strs[i], strl[i]); |
1809 |
memcpy(s, strs[i], strl[i]); |
1710 |
s += strl[i]; |
1810 |
s += strl[i]; |
1711 |
} |
1811 |
} |
1712 |
w = len; |
1812 |
|
1713 |
rv = apr_file_write(buf->handle, str, &w); |
1813 |
if (chunk_msgs) { |
|
|
1814 |
rv = write_atomic_pipe_chunks(r, buf->handle, str, len, NULL); |
1815 |
} |
1816 |
else { |
1817 |
w = len; |
1818 |
rv = apr_file_write(buf->handle, str, &w); |
1819 |
} |
1714 |
|
1820 |
|
1715 |
} |
1821 |
} |
1716 |
else { |
1822 |
else { |
1717 |
for (i = 0, s = &buf->outbuf[buf->outcnt]; i < nelts; ++i) { |
1823 |
if (chunk_msgs) { |
1718 |
memcpy(s, strs[i], strl[i]); |
1824 |
/* |
1719 |
s += strl[i]; |
1825 |
* We do this memcpy dance because write() is atomic for |
|
|
1826 |
* len < PIPE_BUF, while writev() need not be. |
1827 |
*/ |
1828 |
str = apr_palloc(r->pool, len + 1); |
1829 |
for (i = 0, s = str; i < nelts; ++i) { |
1830 |
memcpy(s, strs[i], strl[i]); |
1831 |
s += strl[i]; |
1832 |
} |
1833 |
|
1834 |
rv = write_atomic_pipe_chunks(r, buf->handle, str, len, buf); |
1835 |
} |
1836 |
else { |
1837 |
for (i = 0, s = &buf->outbuf[buf->outcnt]; i < nelts; ++i) { |
1838 |
memcpy(s, strs[i], strl[i]); |
1839 |
s += strl[i]; |
1840 |
} |
1841 |
buf->outcnt += len; |
1842 |
rv = APR_SUCCESS; |
1720 |
} |
1843 |
} |
1721 |
buf->outcnt += len; |
|
|
1722 |
rv = APR_SUCCESS; |
1723 |
} |
1844 |
} |
1724 |
|
1845 |
|
1725 |
APR_ANYLOCK_UNLOCK(&buf->mutex); |
1846 |
APR_ANYLOCK_UNLOCK(&buf->mutex); |