1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
|
/*
Unix SMB/CIFS implementation.
Common server globals
Copyright (C) Simo Sorce <idra@samba.org> 2011
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "system/network.h"
#include <tevent.h>
#include "lib/tsocket/tsocket.h"
struct prefork_pool;
enum pf_worker_status {
PF_WORKER_NONE = 0,
PF_WORKER_IDLE,
PF_WORKER_ACCEPTING,
PF_WORKER_BUSY,
PF_WORKER_EXITING
};
enum pf_server_cmds {
PF_SRV_MSG_NONE = 0,
PF_SRV_MSG_EXIT
};
/**
* @brief This structure is shared between the controlling parent and the
* the child. The parent can only write to the 'cmds' and
* 'allowed_clients' variables, while a child is running.
* The child can change 'status', and 'num_clients'.
* All other variables are initialized by the parent before forking the
* child.
*/
struct pf_worker_data {
pid_t pid;
enum pf_worker_status status;
time_t started;
time_t last_used;
int num_clients;
enum pf_server_cmds cmds;
int allowed_clients;
};
/**
* @brief This is the 'main' function called by a child right after the fork.
* It is daemon specific and should initialize and perform whatever
* operation the child is meant to do. Returning from this function will
* cause the termination of the child.
*
* @param ev The event context
* @param msg_ctx The messaging context
* @param pf The mmaped area used to communicate with parent
* @param listen_fd_size The number of file descriptors to monitor
* @param listen_fds The array of file descriptors
* @param lock_fd The locking file descriptor
* @param private_data Private data that needs to be passed to the main
* function from the calling parent.
*
* @return Returns the exit status to be reported to the parent via exit()
*/
typedef int (prefork_main_fn_t)(struct tevent_context *ev,
struct messaging_context *msg_ctx,
struct pf_worker_data *pf,
int child_id,
int listen_fd_size,
int *listen_fds,
int lock_fd,
void *private_data);
/**
* @brief Callback function for parents that also want to be called on sigchld
*
* @param ev_ctx The event context
* @param pool The pool handler
* @param private_data Data private to the parent
*/
typedef void (prefork_sigchld_fn_t)(struct tevent_context *ev_ctx,
struct prefork_pool *pool,
void *private_data);
/* ==== Functions used by controlling process ==== */
/**
* @brief Creates the first pool of preforked processes
*
* @param mem_ctx The memory context used to hold the pool structure
* @param ev_ctx The event context
* @param msg_ctx The messaging context
* @param listen_fd_size The number of file descriptors to monitor
* @param listen_fds The array of file descriptors to monitor
* @param min_children Minimum number of children that must be available at
* any given time
* @param max_children Maximum number of children that can be started. Also
* determines the initial size of the pool.
* @param main_fn The children 'main' function to be called after fork
* @param private_data The children private data.
* @param pf_pool The allocated pool.
*
* @return True if it was successful, False otherwise.
*/
bool prefork_create_pool(TALLOC_CTX *mem_ctx,
struct tevent_context *ev_ctx,
struct messaging_context *msg_ctx,
int listen_fd_size, int *listen_fds,
int min_children, int max_children,
prefork_main_fn_t *main_fn, void *private_data,
struct prefork_pool **pf_pool);
/**
* @brief Function used to attempt to expand the size of children.
*
* @param pfp The pool structure.
* @param new_max The new max number of children.
*
* @return 0 if operation was successful
* ENOSPC if the mmap area could not be grown to the requested size
* EINVAL if the new max is invalid.
*
* NOTE: this function can easily fail if the mmap area cannot be enlarged.
* A well behaving parent MUST NOT error out if this happen.
*/
int prefork_expand_pool(struct prefork_pool *pfp, int new_max);
/**
* @brief Used to prefork a number of new children
*
* @param ev_ctx The event context
* @param msg_ctx The messaging context
* @param pfp The pool structure
* @param num_children The number of children to be started
*
* @return The number of new children effectively forked.
*
* NOTE: This method does not expand the pool, if the max number of children
* has already been forked it will do nothing.
*/
int prefork_add_children(struct tevent_context *ev_ctx,
struct messaging_context *msg_ctx,
struct prefork_pool *pfp,
int num_children);
/**
* @brief Commands a number of children to stop and exit
*
* @param pfp The pool.
* @param num_children The number of children we need to retire.
* @param age_limit The minimum age a child has been active to be
* considered for retirement. (Compared against the
* 'started' value in the pf_worker_data structure of the
* children.
*
* @return Number of children that were signaled to stop
*
* NOTE: Only children that have no attached clients can be stopped.
* If all the available children are too young or are busy then it
* is possible that none will be asked to stop.
*/
int prefork_retire_children(struct prefork_pool *pfp,
int num_children, time_t age_limit);
/**
* @brief Count the number of active children
*
* @param pfp The pool.
* @param total Returns the number of children currently alive
*
* @return The number of children actually serving clients
*/
int prefork_count_active_children(struct prefork_pool *pfp, int *total);
/**
* @brief Count the number of actual connections currently allowed
*
* @param pfp The pool.
*
* @return The number of connections that can still be opened by clients
* with the current pool of children.
*/
int prefork_count_allowed_connections(struct prefork_pool *pfp);
/**
* @brief Increase the amount of clients each child is allowed to handle
* simultaneaously. It will allow each child to handle more than
* one client at a time, up to 'max' (currently set to 100).
*
* @param pfp The pool.
* @param max Max number of allowed connections per child
*/
void prefork_increase_allowed_clients(struct prefork_pool *pfp, int max);
/**
* @brief Decrease the amount of clients each child is allowed to handle.
* Min is 1.
*
* @param pfp The pool.
*/
void prefork_decrease_allowed_clients(struct prefork_pool *pfp);
/**
* @brief Reset the maximum allowd clients per child to 1.
* Does not reduce the number of clients actually beeing served by
* any given child, but prevents children from overcommitting from
* now on.
*
* @param pfp The pool.
*/
void prefork_reset_allowed_clients(struct prefork_pool *pfp);
/**
* @brief Send a specific signal to all children.
* Used to send SIGHUP when a reload of the configuration is needed
* for example.
*
* @param pfp The pool.
* @param signal_num The signal number to be sent.
*/
void prefork_send_signal_to_all(struct prefork_pool *pfp, int signal_num);
/**
* @brief Sets the SIGCHLD callback
*
* @param pfp The pool handler.
* @param sigchld_fn The callback function (pass NULL to unset).
* @param private_data Private data for the callback function.
*/
void prefork_set_sigchld_callback(struct prefork_pool *pfp,
prefork_sigchld_fn_t *sigchld_fn,
void *private_data);
/* ==== Functions used by children ==== */
/**
* @brief Try to listen and accept on one of the listening sockets.
* Asynchronusly tries to grab the lock and perform an accept.
* Will automatically update the 'status' of the child and handle
* all the locking/unlocking/timingout as necessary.
* Changes behavior depending on whether the child already has other
* client connections. If not it blocks on the lock call for periods of
* time. Otherwise it loops on the lock using a timer in order to allow
* processing of the other clients requests.
*
* @param mem_ctx The memory context on whic to allocate the request
* @param ev The event context
* @param pf The child/parent shared structure
* @param listen_fd_size The number of listening file descriptors
* @param listen_fds The array of listening file descriptors
* @param lock_fd The locking file descriptor
*
* @return The tevent request pointer or NULL on allocation errors.
*/
struct tevent_req *prefork_listen_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct pf_worker_data *pf,
int listen_fd_size,
int *listen_fds,
int lock_fd);
/**
* @brief Returns the file descriptor after the new client connection has
* been accepted.
*
* @param req The request
* @param mem_ctx The memory context for cli_addr and srv_addr
* @param fd The new file descriptor.
* @param srv_addr The server address in tsocket_address format
* @param cli_addr The client address in tsocket_address format
*
* @return The error in case the operation failed.
*/
int prefork_listen_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx, int *fd,
struct tsocket_address **srv_addr,
struct tsocket_address **cli_addr);
|