📄 perchild.c
字号:
}
return OK;
}
static int pass_request(request_rec *r)
{
int rv;
apr_socket_t *thesock = ap_get_module_config(r->connection->conn_config, &core_module);
struct msghdr msg;
struct cmsghdr *cmsg;
int sfd;
struct iovec iov[2];
conn_rec *c = r->connection;
apr_bucket_brigade *bb = apr_brigade_create(r->pool, c->bucket_alloc);
apr_bucket_brigade *sockbb;
char request_body[HUGE_STRING_LEN] = "\0";
apr_size_t l = sizeof(request_body);
perchild_header h;
apr_bucket *sockbuck;
perchild_server_conf *sconf = (perchild_server_conf *)
ap_get_module_config(r->server->module_config,
&mpm_perchild_module);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
"passing request to another child. Vhost: %s, child %d %d",
apr_table_get(r->headers_in, "Host"), child_num, sconf->output);
ap_get_brigade(r->connection->input_filters, bb, AP_MODE_EXHAUSTIVE, APR_NONBLOCK_READ,
0);
for (sockbuck = APR_BRIGADE_FIRST(bb); sockbuck != APR_BRIGADE_SENTINEL(bb);
sockbuck = APR_BUCKET_NEXT(sockbuck)) {
if (APR_BUCKET_IS_SOCKET(sockbuck)) {
break;
}
}
if (!sockbuck) {
}
sockbb = apr_brigade_split(bb, sockbuck);
if (apr_brigade_flatten(bb, request_body, &l) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
"Unable to flatten brigade, declining request");
return DECLINED;
}
apr_os_sock_get(&sfd, thesock);
h.p = r->pool;
h.headers = apr_pstrcat(h.p, r->the_request, CRLF, "Host: ", r->hostname,
CRLF, NULL);
apr_table_do((int (*) (void *, const char *, const char *))
perchild_header_field, (void *) &h, r->headers_in, NULL);
h.headers = apr_pstrcat(h.p, h.headers, CRLF, NULL);
iov[0].iov_base = h.headers;
iov[0].iov_len = strlen(h.headers) + 1;
iov[1].iov_base = request_body;
iov[1].iov_len = l + 1;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = iov;
msg.msg_iovlen = 2;
cmsg = apr_palloc(r->pool, sizeof(*cmsg) + sizeof(sfd));
cmsg->cmsg_len = sizeof(*cmsg) + sizeof(sfd);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
memcpy(CMSG_DATA(cmsg), &sfd, sizeof(sfd));
msg.msg_control = cmsg;
msg.msg_controllen = cmsg->cmsg_len;
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
"Writing message to %d, passing sd: %d", sconf->output, sfd);
if ((rv = sendmsg(sconf->output, &msg, 0)) == -1) {
apr_pool_destroy(r->pool);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
"Writing message failed %d %d", rv, errno);
return -1;
}
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
"Writing message succeeded %d", rv);
apr_pool_destroy(r->pool);
return 1;
}
static char *make_perchild_socket(const char *fullsockname, int sd[2])
{
socketpair(PF_UNIX, SOCK_STREAM, 0, sd);
return NULL;
}
static int perchild_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
{
int i;
server_rec *sr;
perchild_server_conf *sconf;
int def_sd[2];
def_sd[0] = -1;
def_sd[1] = -1;
for (sr = s; sr; sr = sr->next) {
sconf = (perchild_server_conf *)ap_get_module_config(sr->module_config,
&mpm_perchild_module);
if (sconf->input == -1) {
sconf->fullsockname = apr_pstrcat(sr->process->pool,
sconf->sockname, ".DEFAULT", NULL);
if (def_sd[0] == -1) {
if (!make_perchild_socket(sconf->fullsockname, def_sd)) {
/* log error */
}
}
sconf->input = def_sd[0];
sconf->output = def_sd[1];
}
}
for (i = 0; i < num_daemons; i++) {
if (child_info_table[i].uid == -1) {
child_info_table[i].input = def_sd[0];
child_info_table[i].output = def_sd[1];
}
}
thread_socket_table = (int *)apr_pcalloc(p, thread_limit * sizeof(int));
for (i = 0; i < thread_limit; i++) {
thread_socket_table[i] = AP_PERCHILD_THISCHILD;
}
ap_child_table = (ap_ctable *)apr_pcalloc(p, server_limit * sizeof(ap_ctable));
return OK;
}
static int perchild_post_read(request_rec *r)
{
int thread_num = r->connection->id % thread_limit;
perchild_server_conf *sconf = (perchild_server_conf *)
ap_get_module_config(r->server->module_config,
&mpm_perchild_module);
if (thread_socket_table[thread_num] != AP_PERCHILD_THISCHILD) {
apr_socket_t *csd = NULL;
apr_os_sock_put(&csd, &thread_socket_table[thread_num],
r->connection->pool);
ap_sock_disable_nagle(csd);
ap_set_module_config(r->connection->conn_config, &core_module, csd);
return OK;
}
else {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
"Determining if request should be passed. "
"Child Num: %d, SD: %d, sd from table: %d, hostname from server: %s", child_num,
sconf->input, child_info_table[child_num].input,
r->server->server_hostname);
/* sconf is the server config for this vhost, so if our socket
* is not the same that was set in the config, then the request
* needs to be passed to another child. */
if (sconf->input != child_info_table[child_num].input) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
"Passing request.");
if (pass_request(r) == -1) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0,
ap_server_conf, "Could not pass request to proper "
"child, request will not be honored.");
}
longjmp(jmpbuffer, 1);
}
return OK;
}
return OK;
}
static void perchild_hooks(apr_pool_t *p)
{
/* The perchild open_logs phase must run before the core's, or stderr
* will be redirected to a file, and the messages won't print to the
* console.
*/
static const char *const aszSucc[] = {"core.c", NULL};
one_process = 0;
ap_hook_open_logs(perchild_open_logs, NULL, aszSucc, APR_HOOK_MIDDLE);
ap_hook_pre_config(perchild_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_post_config(perchild_post_config, NULL, NULL, APR_HOOK_MIDDLE);
/* Both of these must be run absolutely first. If this request isn't for
* this server then we need to forward it to the proper child. No sense
* tying up this server running more post_read request hooks if it is
* just going to be forwarded along. The process_connection hook allows
* perchild to receive the passed request correctly, by automatically
* filling in the core_input_filter's ctx pointer.
*/
ap_hook_post_read_request(perchild_post_read, NULL, NULL,
APR_HOOK_REALLY_FIRST);
ap_hook_process_connection(perchild_process_connection, NULL, NULL,
APR_HOOK_REALLY_FIRST);
}
static const char *set_num_daemons(cmd_parms *cmd, void *dummy,
const char *arg)
{
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
num_daemons = atoi(arg);
if (num_daemons > server_limit) {
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
"WARNING: NumServers of %d exceeds ServerLimit value "
"of %d servers,", num_daemons, server_limit);
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
" lowering NumServers to %d. To increase, please "
"see the", server_limit);
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
" ServerLimit directive.");
num_daemons = server_limit;
}
else if (num_daemons < 1) {
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
"WARNING: Require NumServers > 0, setting to 1");
num_daemons = 1;
}
return NULL;
}
static const char *set_threads_to_start(cmd_parms *cmd, void *dummy,
const char *arg)
{
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
threads_to_start = atoi(arg);
if (threads_to_start > thread_limit) {
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
"WARNING: StartThreads of %d exceeds ThreadLimit value"
" of %d threads,", threads_to_start,
thread_limit);
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
" lowering StartThreads to %d. To increase, please"
" see the", thread_limit);
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
" ThreadLimit directive.");
}
else if (threads_to_start < 1) {
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
"WARNING: Require StartThreads > 0, setting to 1");
threads_to_start = 1;
}
return NULL;
}
static const char *set_min_spare_threads(cmd_parms *cmd, void *dummy,
const char *arg)
{
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
min_spare_threads = atoi(arg);
if (min_spare_threads <= 0) {
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
"WARNING: detected MinSpareThreads set to non-positive.");
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
"Resetting to 1 to avoid almost certain Apache failure.");
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
"Please read the documentation.");
min_spare_threads = 1;
}
return NULL;
}
static const char *set_max_spare_threads(cmd_parms *cmd, void *dummy,
const char *arg)
{
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
max_spare_threads = atoi(arg);
if (max_spare_threads >= thread_limit) {
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
"WARNING: detected MinSpareThreads set higher than");
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
"ThreadLimit. Resetting to %d", thread_limit);
max_spare_threads = thread_limit;
}
return NULL;
}
static const char *set_max_threads(cmd_parms *cmd, void *dummy, const char *arg)
{
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
max_threads = atoi(arg);
if (max_threads > thread_limit) {
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
"WARNING: detected MaxThreadsPerChild set higher than");
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
"ThreadLimit. Resetting to %d", thread_limit);
max_threads = thread_limit;
}
return NULL;
}
static const char *set_child_per_uid(cmd_parms *cmd, void *dummy, const char *u,
const char *g, const char *num)
{
int i;
int max_this_time = atoi(num) + curr_child_num;
for (i = curr_child_num; i < max_this_time; i++, curr_child_num++) {
if (i > num_daemons) {
return "Trying to use more child ID's than NumServers. Increase "
"NumServers in your config file.";
}
child_info_table[i].uid = ap_uname2id(u);
child_info_table[i].gid = ap_gname2id(g);
#ifndef BIG_SECURITY_HOLE
if (child_info_table[i].uid == 0 || child_info_table[i].gid == 0) {
return "Assigning root user/group to a child.";
}
#endif
}
return NULL;
}
static const char *assign_childuid(cmd_parms *cmd, void *dummy, const char *uid,
const char *gid)
{
int i;
int matching = 0;
int u = ap_uname2id(uid);
int g = ap_gname2id(gid);
const char *errstr;
int socks[2];
perchild_server_conf *sconf = (perchild_server_conf *)
ap_get_module_config(cmd->server->module_config,
&mpm_perchild_module);
sconf->fullsockname = apr_pstrcat(cmd->pool, sconf->sockname, ".", uid,
":", gid, NULL);
if ((errstr = make_perchild_socket(sconf->fullsockname, socks))) {
return errstr;
}
sconf->input = socks[0];
sconf->output = socks[1];
for (i = 0; i < num_daemons; i++) {
if (u == child_info_table[i].uid && g == child_info_table[i].gid) {
child_info_table[i].input = sconf->input;
child_info_table[i].output = sconf->output;
matching++;
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server,
"filling out child_info_table; UID: %d, GID: %d, "
"SD: %d %d, OUTPUT: %d %d, Child Num: %d",
child_info_tabl
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -