📄 mpm_winnt.c
字号:
&BytesRead, (LPOVERLAPPED) NULL)
|| (BytesRead != sizeof(HANDLE))) {
ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf,
"Child %d: Unable to retrieve the ready event from the parent", my_pid);
exit(APEXIT_CHILDINIT);
}
SetEvent(ready_event);
CloseHandle(ready_event);
if (!ReadFile(pipe, child_exit_event, sizeof(HANDLE),
&BytesRead, (LPOVERLAPPED) NULL)
|| (BytesRead != sizeof(HANDLE))) {
ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf,
"Child %d: Unable to retrieve the exit event from the parent", my_pid);
exit(APEXIT_CHILDINIT);
}
if (!ReadFile(pipe, &os_start, sizeof(os_start),
&BytesRead, (LPOVERLAPPED) NULL)
|| (BytesRead != sizeof(os_start))) {
ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf,
"Child %d: Unable to retrieve the start_mutex from the parent", my_pid);
exit(APEXIT_CHILDINIT);
}
*child_start_mutex = NULL;
if ((rv = apr_os_proc_mutex_put(child_start_mutex, &os_start, s->process->pool))
!= APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
"Child %d: Unable to access the start_mutex from the parent", my_pid);
exit(APEXIT_CHILDINIT);
}
if (!ReadFile(pipe, &hScore, sizeof(hScore),
&BytesRead, (LPOVERLAPPED) NULL)
|| (BytesRead != sizeof(hScore))) {
ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf,
"Child %d: Unable to retrieve the scoreboard from the parent", my_pid);
exit(APEXIT_CHILDINIT);
}
*scoreboard_shm = NULL;
if ((rv = apr_os_shm_put(scoreboard_shm, &hScore, s->process->pool))
!= APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
"Child %d: Unable to access the scoreboard from the parent", my_pid);
exit(APEXIT_CHILDINIT);
}
rv = ap_reopen_scoreboard(s->process->pool, scoreboard_shm, 1);
if (rv || !(sb_shared = apr_shm_baseaddr_get(*scoreboard_shm))) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL,
"Child %d: Unable to reopen the scoreboard from the parent", my_pid);
exit(APEXIT_CHILDINIT);
}
/* We must 'initialize' the scoreboard to relink all the
* process-local pointer arrays into the shared memory block.
*/
ap_init_scoreboard(sb_shared);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
"Child %d: Retrieved our scoreboard from the parent.", my_pid);
}
static int send_handles_to_child(apr_pool_t *p,
HANDLE child_ready_event,
HANDLE child_exit_event,
apr_proc_mutex_t *child_start_mutex,
apr_shm_t *scoreboard_shm,
HANDLE hProcess,
apr_file_t *child_in)
{
apr_status_t rv;
HANDLE hCurrentProcess = GetCurrentProcess();
HANDLE hDup;
HANDLE os_start;
HANDLE hScore;
DWORD BytesWritten;
if (!DuplicateHandle(hCurrentProcess, child_ready_event, hProcess, &hDup,
EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, 0)) {
ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf,
"Parent: Unable to duplicate the ready event handle for the child");
return -1;
}
if ((rv = apr_file_write_full(child_in, &hDup, sizeof(hDup), &BytesWritten))
!= APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
"Parent: Unable to send the exit event handle to the child");
return -1;
}
if (!DuplicateHandle(hCurrentProcess, child_exit_event, hProcess, &hDup,
EVENT_MODIFY_STATE | SYNCHRONIZE, FALSE, 0)) {
ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf,
"Parent: Unable to duplicate the exit event handle for the child");
return -1;
}
if ((rv = apr_file_write_full(child_in, &hDup, sizeof(hDup), &BytesWritten))
!= APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
"Parent: Unable to send the exit event handle to the child");
return -1;
}
if ((rv = apr_os_proc_mutex_get(&os_start, child_start_mutex)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
"Parent: Unable to retrieve the start mutex for the child");
return -1;
}
if (!DuplicateHandle(hCurrentProcess, os_start, hProcess, &hDup,
SYNCHRONIZE, FALSE, 0)) {
ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf,
"Parent: Unable to duplicate the start mutex to the child");
return -1;
}
if ((rv = apr_file_write_full(child_in, &hDup, sizeof(hDup), &BytesWritten))
!= APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
"Parent: Unable to send the start mutex to the child");
return -1;
}
if ((rv = apr_os_shm_get(&hScore, scoreboard_shm)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
"Parent: Unable to retrieve the scoreboard handle for the child");
return -1;
}
if (!DuplicateHandle(hCurrentProcess, hScore, hProcess, &hDup,
FILE_MAP_READ | FILE_MAP_WRITE, FALSE, 0)) {
ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf,
"Parent: Unable to duplicate the scoreboard handle to the child");
return -1;
}
if ((rv = apr_file_write_full(child_in, &hDup, sizeof(hDup), &BytesWritten))
!= APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
"Parent: Unable to send the scoreboard handle to the child");
return -1;
}
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
"Parent: Sent the scoreboard to the child");
return 0;
}
/*
* get_listeners_from_parent()
* The listen sockets are opened in the parent. This function, which runs
* exclusively in the child process, receives them from the parent and
* makes them availeble in the child.
*/
void get_listeners_from_parent(server_rec *s)
{
WSAPROTOCOL_INFO WSAProtocolInfo;
ap_listen_rec *lr;
DWORD BytesRead;
int lcnt = 0;
SOCKET nsd;
/* Set up a default listener if necessary */
if (ap_listeners == NULL) {
ap_listen_rec *lr;
lr = apr_palloc(s->process->pool, sizeof(ap_listen_rec));
lr->sd = NULL;
lr->next = ap_listeners;
ap_listeners = lr;
}
/* Open the pipe to the parent process to receive the inherited socket
* data. The sockets have been set to listening in the parent process.
*
* *** We now do this was back in winnt_rewrite_args
* pipe = GetStdHandle(STD_INPUT_HANDLE);
*/
for (lr = ap_listeners; lr; lr = lr->next, ++lcnt) {
if (!ReadFile(pipe, &WSAProtocolInfo, sizeof(WSAPROTOCOL_INFO),
&BytesRead, (LPOVERLAPPED) NULL)) {
ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), ap_server_conf,
"setup_inherited_listeners: Unable to read socket data from parent");
exit(APEXIT_CHILDINIT);
}
nsd = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,
&WSAProtocolInfo, 0, 0);
if (nsd == INVALID_SOCKET) {
ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_netos_error(), ap_server_conf,
"Child %d: setup_inherited_listeners(), WSASocket failed to open the inherited socket.", my_pid);
exit(APEXIT_CHILDINIT);
}
if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
HANDLE hProcess = GetCurrentProcess();
HANDLE dup;
if (DuplicateHandle(hProcess, (HANDLE) nsd, hProcess, &dup,
0, FALSE, DUPLICATE_SAME_ACCESS)) {
closesocket(nsd);
nsd = (SOCKET) dup;
}
}
else {
/* A different approach. Many users report errors such as
* (32538)An operation was attempted on something that is not
* a socket. : Parent: WSADuplicateSocket failed...
*
* This appears that the duplicated handle is no longer recognized
* as a socket handle. SetHandleInformation should overcome that
* problem by not altering the handle identifier. But this won't
* work on 9x - it's unsupported.
*/
if (!SetHandleInformation((HANDLE)nsd, HANDLE_FLAG_INHERIT, 0)) {
ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_os_error(), ap_server_conf,
"set_listeners_noninheritable: SetHandleInformation failed.");
}
}
apr_os_sock_put(&lr->sd, &nsd, s->process->pool);
}
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
"Child %d: retrieved %d listeners from parent", my_pid, lcnt);
}
static int send_listeners_to_child(apr_pool_t *p, DWORD dwProcessId,
apr_file_t *child_in)
{
apr_status_t rv;
int lcnt = 0;
ap_listen_rec *lr;
LPWSAPROTOCOL_INFO lpWSAProtocolInfo;
DWORD BytesWritten;
/* Run the chain of open sockets. For each socket, duplicate it
* for the target process then send the WSAPROTOCOL_INFO
* (returned by dup socket) to the child.
*/
for (lr = ap_listeners; lr; lr = lr->next, ++lcnt) {
int nsd;
lpWSAProtocolInfo = apr_pcalloc(p, sizeof(WSAPROTOCOL_INFO));
apr_os_sock_get(&nsd,lr->sd);
ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, ap_server_conf,
"Parent: Duplicating socket %d and sending it to child process %d",
nsd, dwProcessId);
if (WSADuplicateSocket(nsd, dwProcessId,
lpWSAProtocolInfo) == SOCKET_ERROR) {
ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_netos_error(), ap_server_conf,
"Parent: WSADuplicateSocket failed for socket %d. Check the FAQ.", lr->sd );
return -1;
}
if ((rv = apr_file_write_full(child_in, lpWSAProtocolInfo,
sizeof(WSAPROTOCOL_INFO), &BytesWritten))
!= APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
"Parent: Unable to write duplicated socket %d to the child.", lr->sd );
return -1;
}
}
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
"Parent: Sent %d listeners to child %d", lcnt, dwProcessId);
return 0;
}
enum waitlist_e {
waitlist_ready = 0,
waitlist_term = 1
};
static int create_process(apr_pool_t *p, HANDLE *child_proc, HANDLE *child_exit_event,
DWORD *child_pid)
{
/* These NEVER change for the lifetime of this parent
*/
static char **args = NULL;
static char **env = NULL;
static char pidbuf[28];
apr_status_t rv;
apr_pool_t *ptemp;
apr_procattr_t *attr;
apr_proc_t new_child;
apr_file_t *child_out, *child_err;
HANDLE hExitEvent;
HANDLE waitlist[2]; /* see waitlist_e */
char *cmd;
char *cwd;
apr_pool_sub_make(&ptemp, p, NULL);
/* Build the command line. Should look something like this:
* C:/apache/bin/apache.exe -f ap_server_confname
* First, get the path to the executable...
*/
apr_procattr_create(&attr, ptemp);
apr_procattr_cmdtype_set(attr, APR_PROGRAM);
apr_procattr_detach_set(attr, 1);
if (((rv = apr_filepath_get(&cwd, 0, ptemp)) != APR_SUCCESS)
|| ((rv = apr_procattr_dir_set(attr, cwd)) != APR_SUCCESS)) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
"Parent: Failed to get the current path");
}
if (!args) {
/* Build the args array, only once since it won't change
* for the lifetime of this parent process.
*/
if ((rv = ap_os_proc_filepath(&cmd, ptemp))
!= APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_CRIT, ERROR_BAD_PATHNAME, ap_server_conf,
"Parent: Failed to get full path of %s",
ap_server_conf->process->argv[0]);
apr_pool_destroy(ptemp);
return -1;
}
args = malloc((ap_server_conf->process->argc + 1) * sizeof (char*));
memcpy(args + 1, ap_server_conf->process->argv + 1,
(ap_server_conf->process->argc - 1) * sizeof (char*));
args[0] = malloc(strlen(cmd) + 1);
strcpy(args[0], cmd);
args[ap_server_conf->process->argc] = NULL;
}
else {
cmd = args[0];
}
/* Create a pipe to send handles to the child */
if ((rv = apr_procattr_io_set(attr, APR_FULL_BLOCK,
APR_NO_PIPE, APR_NO_PIPE)) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf,
"Parent: Unable to create child stdin pipe.");
apr_pool_destroy(ptemp);
return -1;
}
/* httpd-2.0/2.2 specific to work around apr_proc_create bugs */
if (((rv = apr_file_open_stdout(&child_out, p))
!= APR_SUCCESS) ||
((rv = apr_procattr_child_out_set(attr, child_out, NULL))
!= APR_SUCCESS)) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf,
"Parent: Could not set child process stdout");
}
if (((rv = apr_file_open_stderr(&child_err, p))
!= APR_SUCCESS) ||
((rv = apr_procattr_child_err_set(attr, child_err, NULL))
!= APR_SUCCESS)) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf,
"Parent: Could not set child process stderr");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -