Adaptive Framework  0.9.0
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
afw_server_fcgi.c
Go to the documentation of this file.
1 // See the 'COPYING' file in the project root for licensing information.
2 /*
3  * Adaptive Frame FCGI Support
4  *
5  * Copyright (c) 2010-2023 Clemson University
6  *
7  */
8 
9 
16 /* This header has to be first because it includes fcgi_stdio.h. */
18 
19 #include "afw.h"
20 #include "afw_request_impl.h"
21 #include <fcgiapp.h>
22 #include <apr_signal.h>
23 
24 /* Declares and rti/inf defines for interface afw_server */
25 #define AFW_IMPLEMENTATION_ID "fcgi"
29 
30 /* Global to hold base xctx pointer. */
31 static afw_xctx_t *impl_server_xctx;
32 
33 /* Compiled afw version. */
34 static const afw_utf8_t impl_compiled_afw_version =
35 AFW_UTF8_LITERAL(AFW_VERSION_STRING);
36 
37 #ifdef __FIXME__
39 static void impl_handle_sigterm(int signum)
40 {
41  afw_environment_t *env;
42 
43  /* Set flag in environment. */
44  env = (afw_environment_t *)impl_server_xctx->env;
45  env->terminating = true;
46 
47  /* Tell FCGI shutdown is pending. */
48  FCGX_ShutdownPending();
49 }
50 #endif
51 
52 
53 /* Internal server create. */
54 const afw_server_t *
56  afw_integer_t thread_count, afw_xctx_t *xctx)
57 {
58  afw_server_fcgi_internal_t *self = NULL;
59  int rc;
60 
61  /* Initialize FCGX. */
62  rc = FCGX_Init();
63  if (rc != 0) {
64  AFW_THROW_ERROR_Z(general,
65  "FCGX_Init() error", xctx);
66  }
67 
68  /* Call FCGI_Finish on exit. */
69  atexit(&FCGX_Finish);
70 
71 
72  /* Set signal handler function for sigterm. */
73  impl_server_xctx = xctx;
74 
80  /* Allocate and initialize self. */
82  self->pub.inf = &impl_afw_server_inf;
83  self->pub.xctx = xctx;
84  self->pub.properties = afw_object_create_managed(xctx->p, xctx);
85  self->pub.thread_count = thread_count;
86  self->pub.afw_version = afw_version_string();
87  self->pub.afw_compiled_version = &impl_compiled_afw_version;
88  self->pub.server_version = &impl_compiled_afw_version; /* Use afw version. */
89  self->pub.server_type = &afw_server_fcgi_s_afw_server_fcgi;
90  self->pub.start_time = afw_dateTime_now_local(xctx->p, xctx);
91 
92  /* Use afw version. */
93  self->pub.server_version = &impl_compiled_afw_version;
94 
95  /* Set object used to access environment variables. */
96  self->environment_variables_object =
98  afw_runtime_xctx_set_object(self->environment_variables_object,
99  true, xctx);
100  afw_xctx_push_qualifier_object(&afw_s_environment,
101  self->environment_variables_object, true, xctx->p, xctx);
102 
103  /* Open socket. */
104  self->sock = FCGX_OpenSocket(path, 500);
105  if (self->sock < 0) {
106  AFW_THROW_ERROR_Z(general,
107  "FCGX_OpenSocket() error", xctx);
108  }
109 
110  /* Make sure this is not a CGI.
111  if (FCGX_IsCGI()) {
112  AFW_THROW_ERROR_Z(general,
113  "This is not Fast CGI", xctx);
114  } */
115 
116  /* Create and set runtime object for server. */
118  &afw_s__AdaptiveServer_,
119  &afw_s_current, self, true, xctx);
120 
121  /* Register flag trace:server */
123  &afw_server_fcgi_s_a_flag_trace_server,
124  &afw_server_fcgi_s_a_flag_trace_server_brief,
125  &afw_server_fcgi_s_a_flag_trace_server_description,
126  &afw_s_a_flag_trace,
127  xctx);
128 
129  /* Register flag trace:server:request */
131  &afw_server_fcgi_s_a_flag_trace_server_request,
132  &afw_server_fcgi_s_a_flag_trace_server_request_brief,
133  &afw_server_fcgi_s_a_flag_trace_server_request_description,
134  &afw_server_fcgi_s_a_flag_trace_server,
135  xctx);
136 
137  /* Register flag trace:server:request:process */
139  &afw_server_fcgi_s_a_flag_trace_server_request_process,
140  &afw_server_fcgi_s_a_flag_trace_server_request_process_brief,
141  &afw_server_fcgi_s_a_flag_trace_server_request_process_description,
142  &afw_server_fcgi_s_a_flag_trace_server_request,
143  xctx);
144  self->flag_index_trace_process = afw_flag_get_index(
145  &afw_server_fcgi_s_a_flag_trace_server_request_process,
146  xctx);
147 
148  /* Get flag_index for request trace. */
149 
150  /* Return new adaptor. */
151  return (afw_server_t *)self;
152 }
153 
154 
155 /*
156  * Implementation of method release of interface afw_server.
157  */
158 void
160  const afw_server_t * instance,
161  afw_xctx_t *xctx)
162 {
165  /*
166  * Continue release, even if there is already an error. Don't overwrite
167  * existing error.
168  */
169 }
170 
171 
172 /* Process a request. */
173 static void impl_process_request(afw_server_fcgi_internal_t *self,
174  const afw_request_handler_t *director,
176  afw_xctx_t *xctx)
177 {
178  const afw_request_t * request;
179 
180  /* Create request. */
182  self, server_thread->fcgx_request, xctx);
183  xctx->request = request;
184 
185  afw_trace_fz(1, self->flag_index_trace_process,
186  &self->pub, xctx,
187  "Request begin thread %d concurrent %d",
188  server_thread->thread->thread_number,
189  server_thread->server->pub.concurrent);
190 
191  /* Handle request errors in request session xctx. */
192  AFW_TRY{
193 
194  afw_request_impl_trace_begin(request, xctx);
195 
196  /* Process request. */
197  afw_request_handler_process(self->director, request, xctx);
198  }
199 
200  /* If client_closed, don't try to write response, just log it. */
201  AFW_CATCH(client_closed) {
203  }
204 
205  /* If memory error, try not to use memory. */
206  AFW_CATCH(memory) {
208  }
209 
210  /* For all other errors, log and write to response body. */
215  }
216 
217  /* Always cleanup. */
218  AFW_FINALLY{
219  afw_request_release(request, xctx);
220  }
221 
222  AFW_ENDTRY;
223 
224  afw_trace_fz(1, self->flag_index_trace_process,
225  &self->pub, xctx,
226  "Request end thread %d concurrent %d",
227  server_thread->thread->thread_number,
228  server_thread->server->pub.concurrent);
229 }
230 
231 
232 /* Request thread run loop. */
233 static void* AFW_THREAD_FUNCTION
234 impl_afw_server_request_thread_start(const afw_thread_t *thread,
235  void *arg)
236 {
237  afw_server_fcgi_internal_server_thread_t *server_thread = arg;
238  afw_server_fcgi_internal_t * server = server_thread->server;
239  afw_xctx_t *xctx = thread->xctx;
240  afw_xctx_t *request_session_xctx = NULL;
241  afw_integer_t request_count;
242  afw_integer_t concurrent;
243  afw_integer_t max_concurrent;
244 
245  /* Initialize a FCGX_Request for this thread. */
246  server_thread->fcgx_request = afw_xctx_calloc_type(FCGX_Request, xctx);
247  FCGX_InitRequest(server_thread->fcgx_request, server->sock,
248  FCGI_FAIL_ACCEPT_ON_INTR);
249 
250  /* Request loop. */
251  while (!afw_xctx_environment_is_terminating(xctx) &&
252  FCGX_Accept_r(server_thread->fcgx_request) >= 0)
253  {
254  /* Increment count. */
255  request_count = afw_atomic_integer_increment(&server->pub.request_count);
256 
257  /* Process request. */
258  AFW_TRY {
259 
260  /* Increment concurrent count. */
261  max_concurrent = server->pub.max_concurrent;
262  concurrent = afw_atomic_integer_increment(&server->pub.concurrent);
263  if (concurrent > max_concurrent) {
264  afw_atomic_integer_cas(&server->pub.max_concurrent,
265  max_concurrent, concurrent);
266  }
267 
268  /* Create Adaptive Framework xctx for request session. */
269  request_session_xctx = afw_xctx_create(
270  &AFW_XCTX_s_NAME_REQUEST_SESSION, request_count, xctx);
271 
272  /* Process request. */
273  impl_process_request(server, server->director,
274  server_thread, request_session_xctx);
275  }
276 
278  /* Increment unhandled error count. */
279  afw_atomic_integer_increment(&server->pub.unhandled_errors);
280  }
281 
282  AFW_FINALLY {
283 
284  /* Decrement concurrent count. */
285  afw_atomic_integer_decrement(&server->pub.concurrent);
286 
287  /* Release xctx resources. */
288  if (request_session_xctx) {
289  afw_xctx_release(request_session_xctx, xctx);
290  }
291 
292  }
293 
294  AFW_ENDTRY;
295  }
296 
297  /* Normal return. */
298  return NULL;
299 }
300 
301 
302 /*
303  * Implementation of method run of interface afw_server.
304  */
305 void
307  const afw_server_t * instance,
308  const afw_request_handler_t * handler,
309  afw_xctx_t *xctx)
310 {
311  afw_server_fcgi_internal_t * server =
312  (afw_server_fcgi_internal_t *)instance;
313 
314  afw_integer_t count;
316  afw_thread_attr_t *thread_attr;
317 
318  server->director = handler;
319  server->xctx = xctx;
320  server->threads = afw_xctx_calloc(
322  (afw_size_t)server->pub.thread_count,
323  xctx);
324 
327  /* The default thread attribute: detachable */
328  thread_attr = afw_thread_attr_create(xctx->p, xctx);
329 
330 
331  /* Create the request threads. */
332  for (count = 1, server_thread = server->threads;
333  count <= server->pub.thread_count;
334  count++, server_thread++)
335  {
336  server_thread->server = server;
337  server_thread->thread = afw_thread_create(
338  thread_attr,
339  impl_afw_server_request_thread_start, server_thread,
341  count, xctx);
342  }
343 
344  /* Wait for request threads to die. */
345  for (count = 1, server_thread = server->threads;
346  count <= server->pub.thread_count;
347  count++, server_thread++)
348  {
349  afw_thread_join(server_thread->thread, xctx);
350  }
351 
352 
353  /* Run is finished. */
354 }
Adaptive Framework Core API.
Header for interface afw_request* implementation development.
const afw_server_t * afw_server_fcgi_internal_create(const char *path, afw_integer_t thread_count, afw_xctx_t *xctx)
Create an FCGI afw_server.
Internal header file for AFW FCGI Server.
afw_server_fcgi_internal_request_t * afw_server_fcgi_internal_create_request(afw_server_fcgi_internal_t *server, FCGX_Request *fcgx_request, afw_xctx_t *xctx)
Adaptive Framework (afw_server_fcgi_) strings header.
Adaptive Framework Version (afw_server_fcgi_) header.
Interface afw_interface implementation declares.
afw_integer_t afw_atomic_integer_decrement(AFW_ATOMIC afw_integer_t *mem)
Integer atomic decrement.
Definition: afw_atomic.h:96
afw_integer_t afw_atomic_integer_increment(AFW_ATOMIC afw_integer_t *mem)
Integer atomic increment.
Definition: afw_atomic.h:127
afw_boolean_t afw_atomic_integer_cas(AFW_ATOMIC afw_integer_t *mem, afw_integer_t expected, afw_integer_t desired)
Integer atomic decrement.
Definition: afw_atomic.h:61
#define AFW_UTF8_LITERAL(A_STRING)
String literal initializer.
Definition: afw_common.h:582
#define AFW_THREAD_FUNCTION
Uses APR_THREAD_FUNC as AFW_THREAD_FUNCTION.
Definition: afw_common.h:1366
apr_size_t afw_size_t
size_t.
Definition: afw_common.h:151
struct afw_thread_attr_s afw_thread_attr_t
Typedef for afw_thread_attr.
Definition: afw_common.h:1374
apr_int64_t afw_integer_t
typedef for big signed int.
Definition: afw_common.h:321
@ afw_log_priority_info
Definition: afw_common.h:988
const afw_object_t * afw_environment_create_environment_variables_object(afw_boolean_t preload_variables, afw_xctx_t *xctx)
Create a readonly object for accessing environment variables.
#define AFW_FINALLY
Always executed regardless of error.
Definition: afw_error.h:702
afw_error_http_status(const afw_error_t *error)
Returns http status for error.
Definition: afw_error.c:1041
#define AFW_CATCH_UNHANDLED
Catch an unhandled error that occurs in a AFW_TRY block.
Definition: afw_error.h:684
afw_error_write_log(afw_log_priority_t priority, const afw_error_t *error, afw_xctx_t *xctx)
Write error to environment log.
Definition: afw_error.c:639
#define AFW_ENDTRY
Ends an AFW try block.
Definition: afw_error.h:727
#define AFW_TRY
Begin an AFW TRY block.
Definition: afw_error.h:634
#define AFW_ERROR_THROWN
Access the thrown error. See AFW_TRY.
Definition: afw_error.h:554
#define AFW_THROW_ERROR_Z(code, message_z, xctx)
Macro used to set error and 0 rv in xctx and throw it.
Definition: afw_error.h:283
#define AFW_CATCH(__CODE_)
Catch a particular error that occurs in a AFW_TRY block.
Definition: afw_error.h:668
void afw_flag_environment_register_flag(const afw_utf8_t *flag_id, const afw_utf8_t *brief, const afw_utf8_t *description, const afw_utf8_t *included_by_flag_id, afw_xctx_t *xctx)
Register a flag definition.
Definition: afw_flag.c:579
afw_flag_get_index(const afw_utf8_t *flag_id, afw_xctx_t *xctx)
Get the flag index for a flag id.
Definition: afw_flag.c:546
#define afw_object_create_managed(p, xctx)
Create an empty entity object in its own pool.
Definition: afw_object.h:913
afw_request_impl_trace_begin(const afw_request_t *instance, afw_xctx_t *xctx)
Trace request begin if requested.
#define afw_request_handler_process(instance, request, xctx)
Call method process of interface afw_request_handler.
#define afw_request_release(instance, xctx)
Call method release of interface afw_request.
afw_request_write_error_to_response_body(const afw_request_t *instance, const afw_utf8_t *code, const afw_error_t *error, afw_xctx_t *xctx)
Write xctx error to response body.
Definition: afw_request.c:216
afw_runtime_env_create_and_set_indirect_object(const afw_utf8_t *object_type_id, const afw_utf8_t *object_id, void *internal, afw_boolean_t overwrite, afw_xctx_t *xctx)
Create and set an indirect runtime object.
Definition: afw_runtime.c:528
afw_runtime_xctx_set_object(const afw_object_t *object, afw_boolean_t overwrite, afw_xctx_t *xctx)
Set an object pointer in the xctx's runtime objects.
Definition: afw_runtime.c:292
void impl_afw_server_release(const afw_server_t *instance, afw_xctx_t *xctx)
void impl_afw_server_run(const afw_server_t *instance, const afw_request_handler_t *handler, afw_xctx_t *xctx)
afw_thread_join(const afw_thread_t *thread, afw_xctx_t *xctx)
Join a thread.
Definition: afw_thread.c:71
afw_thread_create(afw_thread_attr_t *thread_attr, afw_thread_function_t start_function, void *start_function_arg, const afw_utf8_t *name, afw_integer_t thread_number, afw_xctx_t *xctx)
Create a thread.
Definition: afw_thread.c:41
afw_thread_attr_create(const afw_pool_t *p, afw_xctx_t *xctx)
Create a thread attr.
Definition: afw_thread.c:19
afw_dateTime_now_local(const afw_pool_t *p, afw_xctx_t *xctx)
Get now local time as dateTime in specified pool.
Definition: afw_time.c:639
#define afw_trace_fz(trace_level, flag_index, instance, xctx, format_z,...)
If applicable, write trace using a printf style format.
Definition: afw_trace.h:88
const afw_utf8_t * afw_version_string()
#define afw_xctx_release(instance, xctx)
Call method release of interface afw_xctx.
#define AFW_XCTX_s_NAME_REQUEST_SESSION
Definition: afw_xctx.h:46
#define AFW_XCTX_s_NAME_REQUEST_THREAD
Definition: afw_xctx.h:40
afw_xctx_push_qualifier_object(const afw_utf8_t *qualifier_name, const afw_object_t *qualifier_object, afw_boolean_t secure, const afw_pool_t *p, afw_xctx_t *xctx)
Push qualifier object on to stack.
Definition: afw_xctx.c:406
afw_boolean_t afw_xctx_environment_is_terminating(afw_xctx_t *xctx)
Test for environment terminating.
Definition: afw_xctx.h:173
#define afw_xctx_calloc(size, xctx)
Macro to allocate cleared memory in xctx's pool.
Definition: afw_xctx.h:185
afw_xctx_create(const afw_utf8_t *name, afw_integer_t number, afw_xctx_t *xctx)
Create an Adaptive Framework xctx.
Definition: afw_xctx.c:145
#define afw_xctx_calloc_type(type, xctx)
Macro to allocate cleared memory to hold type in xctx's pool.
Definition: afw_xctx.h:199
Struct for typedef afw_environment_t defined in afw_common.h.
Definition: afw_common.h:1383
afw_boolean_t terminating
Indicates that environment is terminating.
Definition: afw_common.h:1467
Interface afw_request_handler public struct.
Interface afw_request public struct.
Interface afw_server public struct.
Struct for public part of afw_pool_t.
Definition: afw_thread.h:56
afw_integer_t thread_number
The thread number within the afw environment.
Definition: afw_thread.h:69
afw_xctx_t * xctx
The base xctx for the thread.
Definition: afw_thread.h:75
NFC normalized UTF-8 string.
Definition: afw_common.h:545
Interface afw_xctx public struct.