Perchild: Setting Users and Groups per Virtual Host Page 2

The obvious question now, is how does this work internally. The Perchild MPM has a special global table which it uses to start children and allow those children to change to the correct user Ids. It also uses the per-server configuration to pass requests between child processes. When the MPM encounters a ChildPerUserID directive it begins to fill out the global child table. Each child process gets one place in the table, which stores the User and Group Id that the child should run as. The table also stores a socket descriptor, but it isn't filled out until later.

While parsing the configuration for each VirtualHost, if the server encounters an AssignUserId directive, it fills out a perchild per-server configuration structure, which contains the two socket descriptors. In order to do this, the server creates a set of anonymous Unix Domain Sockets which are used to pass the request between processes. After the sockets are created, the server searches the child table to find the child processes that have the same User and Group Ids. Once found, one of the socket descriptors is attached to all of the processes with that User Group combination. Both socket descriptors are attached to the specific VirtualHost that is being configured. This step is repeated for all VirtualHosts. Once all VirtualHosts have been configured, the server ensures that each host has been assigned a socket. If not, the server creates a set of default sockets and stores those in any server that doesn't already have a socket.

The next step is to create the child processes. When each process is started, it checks the global child table, and switches to the appropriate User and Group Ids. If no User and Group Id are specified for this child process, then the User and Group specified in the main server are used. Each child also adds the socket in the socket table to the list of sockets it will poll on. From here, child startup proceeds as normal with each child process polling on all of the ports opened in the parent process. This leaves the server looking like Figure 1.

Figure 1

Figure 1.

When a request comes in, the Perchild MPM is the first module called in the post_read_request phase. During this phase, the Perchild MPM ensures that the request is for the current child process. If so, processing continues as normal. If not, the child process uses the VirtualHost that is attached to the request to find the correct Unix Domain Socket to use. The child process begins by finding the socket that is currently being used to communicate with the client in the connection structure. Once this socket is found, it is passed to the correct child process through the Unix Domain socket (S1 or S2 in the diagram). Finally, the part of the request that has already been read from the client is sent to the new child over the Unix Domain socket. The original child process then closes its connection to the client, and longjmps out of the post_read_request phase to the end of processing a request. This thread then goes back to listening for another new request.

This article was originally published on Aug 18, 2000
Page 2 of 3

Thanks for your registration, follow us on our social networks to keep up-to-date