1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2014 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Author: David Hedbor <neotron@php.net> |
16 | Based on aolserver SAPI by Sascha Schumann <sascha@schumann.cx> |
17 +----------------------------------------------------------------------+
18 */
19
20 /* $Id$ */
21
22 #include "php.h"
23 #ifdef HAVE_CAUDIUM
24
25 #include "php_ini.h"
26 #include "php_globals.h"
27 #include "SAPI.h"
28 #include "php_main.h"
29 #include "ext/standard/info.h"
30
31 #include "php_version.h"
32
33 /* Pike Include Files
34 *
35 * conflicts with pike avoided by only using long names. Requires a new
36 * Pike 0.7 since it was implemented for this interface only.
37 *
38 */
39 #define NO_PIKE_SHORTHAND
40
41 /* Ok, we are now using Pike level threads to handle PHP5 since
42 * the nice th_farm threads aren't working on Linux with glibc 2.2
43 * (why this is I don't know).
44 */
45 #define USE_PIKE_LEVEL_THREADS
46
47 #include <fdlib.h>
48 #include <program.h>
49 #include <pike_types.h>
50 #include <interpret.h>
51 #include <module_support.h>
52 #include <array.h>
53 #include <backend.h>
54 #include <stralloc.h>
55 #include <mapping.h>
56 #include <object.h>
57 #include <threads.h>
58 #include <builtin_functions.h>
59 #include <operators.h>
60 #include <version.h>
61
62 #if (PIKE_MAJOR_VERSION == 7 && PIKE_MINOR_VERSION == 1 && PIKE_BUILD_VERSION >= 12) || PIKE_MAJOR_VERSION > 7 || (PIKE_MAJOR_VERSION == 7 && PIKE_MINOR_VERSION > 1)
63 # include "pike_error.h"
64 #else
65 # include "error.h"
66 # ifndef Pike_error
67 # define Pike_error error
68 # endif
69 #endif
70
71 /* Pike 7.x and newer */
72 #define MY_MAPPING_LOOP(md, COUNT, KEY) \
73 for(COUNT=0;COUNT < md->data->hashsize; COUNT++ ) \
74 for(KEY=md->data->hash[COUNT];KEY;KEY=KEY->next)
75
76 #ifndef ZTS
77 /* Need thread safety */
78 #error You need to compile PHP with threads.
79 #endif
80
81 #ifndef PIKE_THREADS
82 #error The PHP5 module requires that your Pike has thread support.
83 #endif
84
85 #undef HIDE_GLOBAL_VARIABLES
86 #undef REVEAL_GLOBAL_VARIABLES
87 #define HIDE_GLOBAL_VARIABLES()
88 #define REVEAL_GLOBAL_VARIABLES()
89
90 /* php_caudium_request is per-request object storage */
91
92 typedef struct
93 {
94 struct mapping *request_data;
95 struct object *my_fd_obj;
96 struct svalue done_cb;
97 struct pike_string *filename;
98 int my_fd;
99 int written;
100 TSRMLS_D;
101 } php_caudium_request;
102
103
104 void pike_module_init(void);
105 void pike_module_exit(void);
106 static void free_struct(TSRMLS_D);
107 void f_php_caudium_request_handler(INT32 args);
108
109 /* Defines to get to the data supplied when the script is started. */
110
111 /* Per thread storage area id... */
112 static int caudium_globals_id;
113
114 #define GET_THIS() php_caudium_request *_request = ts_resource(caudium_globals_id)
115 #define THIS _request
116 #define PTHIS ((php_caudium_request *)(Pike_fp->current_storage))
117 /* File descriptor integer. Used to write directly to the FD without
118 * passing Pike
119 */
120 #define MY_FD (THIS->my_fd)
121
122 /* FD object. Really a PHPScript object from Pike which implements a couple
123 * of functions to handle headers, writing and buffering.
124 */
125 #define MY_FD_OBJ ((struct object *)(THIS->my_fd_obj))
126
127 /* Mapping with data supplied from the calling Caudium module. Contains
128 * a mapping with headers, an FD object etc.
129 */
130 #define REQUEST_DATA ((struct mapping *)(THIS->request_data))
131
132 extern int fd_from_object(struct object *o);
133 static unsigned char caudium_php_initialized;
134
135 #ifndef mt_lock_interpreter
136 #define mt_lock_interpreter() mt_lock(&interpreter_lock);
137 #define mt_unlock_interpreter() mt_unlock(&interpreter_lock);
138 #endif
139
140
141 /* This allows calling of pike functions from the PHP callbacks,
142 * which requires the Pike interpreter to be locked.
143 */
144 #define THREAD_SAFE_RUN(COMMAND, what) do {\
145 struct thread_state *state;\
146 if((state = thread_state_for_id(th_self()))!=NULL) {\
147 if(!state->swapped) {\
148 COMMAND;\
149 } else {\
150 mt_lock_interpreter();\
151 SWAP_IN_THREAD(state);\
152 COMMAND;\
153 SWAP_OUT_THREAD(state);\
154 mt_unlock_interpreter();\
155 }\
156 }\
157 } while(0)
158
159
160
161 /* Low level header lookup. Basically looks for the named header in the mapping
162 * headers in the supplied options mapping.
163 */
164
lookup_header(char * headername)165 INLINE static struct svalue *lookup_header(char *headername)
166 {
167 struct svalue *headers, *value;
168 struct pike_string *sind;
169 GET_THIS();
170 sind = make_shared_string("env");
171 headers = low_mapping_string_lookup(REQUEST_DATA, sind);
172 free_string(sind);
173 if(!headers || headers->type != PIKE_T_MAPPING) return NULL;
174 sind = make_shared_string(headername);
175 value = low_mapping_string_lookup(headers->u.mapping, sind);
176 free_string(sind);
177 if(!value) return NULL;
178 return value;
179 }
180
181 /* Lookup a header in the mapping and return the value as a string, or
182 * return the default if it's missing
183 */
lookup_string_header(char * headername,char * default_value)184 INLINE static char *lookup_string_header(char *headername, char *default_value)
185 {
186 struct svalue *head = NULL;
187 THREAD_SAFE_RUN(head = lookup_header(headername), "header lookup");
188 if(!head || head->type != PIKE_T_STRING)
189 return default_value;
190 return head->u.string->str;
191 }
192
193 /* Lookup a header in the mapping and return the value as if it's an integer
194 * and otherwise return the default.
195 */
lookup_integer_header(char * headername,int default_value)196 INLINE static int lookup_integer_header(char *headername, int default_value)
197 {
198 struct svalue *head = NULL;
199 THREAD_SAFE_RUN(head = lookup_header(headername), "header lookup");
200 if(!head || head->type != PIKE_T_INT)
201 return default_value;
202 return head->u.integer;
203 }
204
205 /*
206 * php_caudium_low_ub_write() writes data to the client connection. Might be
207 * rewritten to do more direct IO to save CPU and the need to lock the
208 * interpreter for better threading.
209 */
210
211 INLINE static int
php_caudium_low_ub_write(const char * str,uint str_length TSRMLS_DC)212 php_caudium_low_ub_write(const char *str, uint str_length TSRMLS_DC) {
213 int sent_bytes = 0;
214 struct pike_string *to_write = NULL;
215 GET_THIS();
216 if(!MY_FD_OBJ->prog) {
217 PG(connection_status) = PHP_CONNECTION_ABORTED;
218 zend_bailout();
219 return -1;
220 }
221 to_write = make_shared_binary_string(str, str_length);
222 push_string(to_write);
223 safe_apply(MY_FD_OBJ, "write", 1);
224 if(Pike_sp[-1].type == PIKE_T_INT)
225 sent_bytes = Pike_sp[-1].u.integer;
226 pop_stack();
227 if(sent_bytes != str_length) {
228 /* This means the connection is closed. Dead. Gone. *sniff* */
229 PG(connection_status) = PHP_CONNECTION_ABORTED;
230 zend_bailout();
231 }
232 return sent_bytes;
233 }
234
235 /*
236 * php_caudium_sapi_ub_write() calls php_caudium_low_ub_write in a Pike thread
237 * safe manner or writes directly to the output FD if RXML post-parsing is
238 * disabled.
239 */
240
241 static int
php_caudium_sapi_ub_write(const char * str,uint str_length TSRMLS_DC)242 php_caudium_sapi_ub_write(const char *str, uint str_length TSRMLS_DC)
243 {
244 GET_THIS();
245 int sent_bytes = 0, fd = MY_FD;
246 if(fd)
247 {
248 for(sent_bytes=0;sent_bytes < str_length;)
249 {
250 int written;
251 written = fd_write(fd, str + sent_bytes, str_length - sent_bytes);
252 if(written < 0)
253 {
254 switch(errno)
255 {
256 default:
257 /* This means the connection is closed. Dead. Gone. *sniff* */
258 PG(connection_status) = PHP_CONNECTION_ABORTED;
259 zend_bailout();
260 THIS->written += sent_bytes;
261 return sent_bytes;
262 case EINTR:
263 case EWOULDBLOCK:
264 continue;
265 }
266 } else {
267 sent_bytes += written;
268 }
269 }
270 THIS->written += sent_bytes;
271 } else {
272 THREAD_SAFE_RUN(sent_bytes = php_caudium_low_ub_write(str, str_length TSRMLS_CC),
273 "write");
274 }
275 return sent_bytes;
276 }
277
278 /* php_caudium_set_header() sets a header in the header mapping. Called in a
279 * thread safe manner from php_caudium_sapi_header_handler.
280 */
281 INLINE static void
php_caudium_set_header(char * header_name,char * value,char * p)282 php_caudium_set_header(char *header_name, char *value, char *p)
283 {
284 struct svalue hsval;
285 struct pike_string *hval, *ind, *hind;
286 struct mapping *headermap;
287 struct svalue *s_headermap, *soldval;
288 int vallen;
289 GET_THIS();
290 /* hval = make_shared_string(value); */
291 ind = make_shared_string(" _headers");
292 hind = make_shared_binary_string(header_name,
293 (int)(p - header_name));
294
295 s_headermap = low_mapping_string_lookup(REQUEST_DATA, ind);
296 if(!s_headermap || s_headermap->type != PIKE_T_MAPPING)
297 {
298 struct svalue mappie;
299 mappie.type = PIKE_T_MAPPING;
300 headermap = allocate_mapping(1);
301 mappie.u.mapping = headermap;
302 mapping_string_insert(REQUEST_DATA, ind, &mappie);
303 free_mapping(headermap);
304 hval = make_shared_string(value);
305 } else {
306 headermap = s_headermap->u.mapping;
307 soldval = low_mapping_string_lookup(headermap, hind);
308 vallen = strlen(value);
309 if(soldval != NULL &&
310 soldval->type == PIKE_T_STRING &&
311 soldval->u.string->size_shift == 0) {
312 /* Existing, valid header. Prepend.*/
313 hval = begin_shared_string(soldval->u.string->len + 1 + vallen);
314 MEMCPY(hval->str, soldval->u.string->str, soldval->u.string->len);
315 STR0(hval)[soldval->u.string->len] = '\0';
316 MEMCPY(hval->str+soldval->u.string->len+1, value, vallen);
317 hval = end_shared_string(hval);
318 } else {
319 hval = make_shared_string(value);
320 }
321 }
322 hsval.type = PIKE_T_STRING;
323 hsval.u.string = hval;
324
325 mapping_string_insert(headermap, hind, &hsval);
326
327 free_string(hval);
328 free_string(ind);
329 free_string(hind);
330 }
331
332 /*
333 * php_caudium_sapi_header_handler() sets a HTTP reply header to be
334 * sent to the client.
335 */
336 static int
php_caudium_sapi_header_handler(sapi_header_struct * sapi_header,sapi_headers_struct * sapi_headers TSRMLS_DC)337 php_caudium_sapi_header_handler(sapi_header_struct *sapi_header,
338 sapi_headers_struct *sapi_headers TSRMLS_DC)
339 {
340 char *header_name, *header_content, *p;
341 header_name = sapi_header->header;
342 header_content = p = strchr(header_name, ':');
343
344 if(p) {
345 do {
346 header_content++;
347 } while(*header_content == ' ');
348 THREAD_SAFE_RUN(php_caudium_set_header(header_name, header_content, p), "header handler");
349 }
350 sapi_free_header(sapi_header);
351 return 0;
352 }
353
354 /*
355 * php_caudium_sapi_send_headers() flushes the headers to the client.
356 * Called before real content is sent by PHP.
357 */
358
359 INLINE static int
php_caudium_low_send_headers(sapi_headers_struct * sapi_headers TSRMLS_DC)360 php_caudium_low_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
361 {
362 struct pike_string *ind;
363 struct svalue *s_headermap;
364 GET_THIS();
365 if(!MY_FD_OBJ->prog) {
366 PG(connection_status) = PHP_CONNECTION_ABORTED;
367 zend_bailout();
368 return SAPI_HEADER_SEND_FAILED;
369 }
370 ind = make_shared_string(" _headers");
371 s_headermap = low_mapping_string_lookup(REQUEST_DATA, ind);
372 free_string(ind);
373
374 push_int(SG(sapi_headers).http_response_code);
375 if(s_headermap && s_headermap->type == PIKE_T_MAPPING)
376 ref_push_mapping(s_headermap->u.mapping);
377 else
378 push_int(0);
379 safe_apply(MY_FD_OBJ, "send_headers", 2);
380 pop_stack();
381
382 return SAPI_HEADER_SENT_SUCCESSFULLY;
383 }
384
385 static int
php_caudium_sapi_send_headers(sapi_headers_struct * sapi_headers TSRMLS_DC)386 php_caudium_sapi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
387 {
388 int res = 0;
389 THREAD_SAFE_RUN(res = php_caudium_low_send_headers(sapi_headers TSRMLS_CC), "send headers");
390 return res;
391 }
392
393 /*
394 * php_caudium_sapi_read_post() reads a specified number of bytes from
395 * the client. Used for POST/PUT requests.
396 */
397
php_caudium_low_read_post(char * buf,uint count_bytes)398 INLINE static int php_caudium_low_read_post(char *buf, uint count_bytes)
399 {
400 uint total_read = 0;
401 GET_THIS();
402 TSRMLS_FETCH();
403
404 if(!MY_FD_OBJ->prog)
405 {
406 PG(connection_status) = PHP_CONNECTION_ABORTED;
407 zend_bailout();
408 return -1;
409 }
410 push_int(count_bytes);
411 safe_apply(MY_FD_OBJ, "read_post", 1);
412 if(Pike_sp[-1].type == PIKE_T_STRING) {
413 MEMCPY(buf, Pike_sp[-1].u.string->str,
414 (total_read = Pike_sp[-1].u.string->len));
415 buf[total_read] = '\0';
416 } else
417 total_read = 0;
418 pop_stack();
419 return total_read;
420 }
421
422 static int
php_caudium_sapi_read_post(char * buf,uint count_bytes TSRMLS_DC)423 php_caudium_sapi_read_post(char *buf, uint count_bytes TSRMLS_DC)
424 {
425 uint total_read = 0;
426 THREAD_SAFE_RUN(total_read = php_caudium_low_read_post(buf, count_bytes), "read post");
427 return total_read;
428 }
429
430 /*
431 * php_caudium_sapi_read_cookies() returns the Cookie header from
432 * the HTTP request header
433 */
434
435 static char *
php_caudium_sapi_read_cookies(TSRMLS_D)436 php_caudium_sapi_read_cookies(TSRMLS_D)
437 {
438 char *cookies;
439 cookies = lookup_string_header("HTTP_COOKIE", NULL);
440 return cookies;
441 }
442
php_info_caudium(ZEND_MODULE_INFO_FUNC_ARGS)443 static void php_info_caudium(ZEND_MODULE_INFO_FUNC_ARGS)
444 {
445 /* char buf[512]; */
446 php_info_print_table_start();
447 php_info_print_table_row(2, "SAPI module version", "$Id$");
448 /* php_info_print_table_row(2, "Build date", Ns_InfoBuildDate());
449 php_info_print_table_row(2, "Config file path", Ns_InfoConfigFile());
450 php_info_print_table_row(2, "Error Log path", Ns_InfoErrorLog());
451 php_info_print_table_row(2, "Installation path", Ns_InfoHomePath());
452 php_info_print_table_row(2, "Hostname of server", Ns_InfoHostname());
453 php_info_print_table_row(2, "Source code label", Ns_InfoLabel());
454 php_info_print_table_row(2, "Server platform", Ns_InfoPlatform());
455 snprintf(buf, 511, "%s/%s", Ns_InfoServerName(), Ns_InfoServerVersion());
456 php_info_print_table_row(2, "Server version", buf);
457 snprintf(buf, 511, "%d day(s), %02d:%02d:%02d",
458 uptime / 86400,
459 (uptime / 3600) % 24,
460 (uptime / 60) % 60,
461 uptime % 60);
462 php_info_print_table_row(2, "Server uptime", buf);
463 */
464 php_info_print_table_end();
465 }
466
467 static zend_module_entry php_caudium_module = {
468 STANDARD_MODULE_HEADER,
469 "Caudium",
470 NULL,
471 NULL,
472 NULL,
473 NULL,
474 NULL,
475 php_info_caudium,
476 NULL,
477 STANDARD_MODULE_PROPERTIES
478 };
479
480
low_sapi_caudium_register_variables(zval * track_vars_array TSRMLS_DC)481 INLINE static void low_sapi_caudium_register_variables(zval *track_vars_array TSRMLS_DC)
482 {
483 int i;
484 struct keypair *k;
485 struct svalue *headers;
486 struct pike_string *sind;
487 struct svalue *ind;
488 struct svalue *val;
489 GET_THIS();
490 php_register_variable("PHP_SELF", SG(request_info).request_uri,
491 track_vars_array TSRMLS_CC);
492 php_register_variable("GATEWAY_INTERFACE", "CGI/1.1",
493 track_vars_array TSRMLS_CC);
494 php_register_variable("REQUEST_METHOD",
495 (char *) SG(request_info).request_method,
496 track_vars_array TSRMLS_CC);
497 php_register_variable("REQUEST_URI", SG(request_info).request_uri,
498 track_vars_array TSRMLS_CC);
499 php_register_variable("PATH_TRANSLATED", SG(request_info).path_translated,
500 track_vars_array TSRMLS_CC);
501
502 sind = make_shared_string("env");
503 headers = low_mapping_string_lookup(REQUEST_DATA, sind);
504 free_string(sind);
505 if(headers && headers->type == PIKE_T_MAPPING) {
506 MY_MAPPING_LOOP(headers->u.mapping, i, k) {
507 ind = &k->ind;
508 val = &k->val;
509 if(ind && ind->type == PIKE_T_STRING &&
510 val && val->type == PIKE_T_STRING) {
511 php_register_variable(ind->u.string->str, val->u.string->str,
512 track_vars_array TSRMLS_CC );
513 }
514 }
515 }
516 }
517
sapi_caudium_register_variables(zval * track_vars_array TSRMLS_DC)518 static void sapi_caudium_register_variables(zval *track_vars_array TSRMLS_DC)
519 {
520 THREAD_SAFE_RUN(low_sapi_caudium_register_variables(track_vars_array TSRMLS_CC), "register_variables");
521 }
522
523
php_caudium_startup(sapi_module_struct * sapi_module)524 static int php_caudium_startup(sapi_module_struct *sapi_module)
525 {
526 if (php_module_startup(sapi_module, &php_caudium_module, 1)==FAILURE) {
527 return FAILURE;
528 }
529 return SUCCESS;
530 }
531
532
533 /* this structure is static (as in "it does not change") */
534 static sapi_module_struct caudium_sapi_module = {
535 "caudium",
536 "Caudium",
537 php_caudium_startup, /* startup */
538 php_module_shutdown_wrapper, /* shutdown */
539 NULL, /* activate */
540 NULL, /* deactivate */
541 php_caudium_sapi_ub_write, /* unbuffered write */
542 NULL, /* flush */
543 NULL, /* get uid */
544 NULL, /* getenv */
545 php_error, /* error handler */
546 php_caudium_sapi_header_handler, /* header handler */
547 php_caudium_sapi_send_headers, /* send headers handler */
548 NULL, /* send header handler */
549 php_caudium_sapi_read_post, /* read POST data */
550 php_caudium_sapi_read_cookies, /* read cookies */
551 sapi_caudium_register_variables, /* register server variables */
552 NULL, /* Log message */
553 NULL, /* Get request time */
554 NULL, /* Child terminate */
555
556 STANDARD_SAPI_MODULE_PROPERTIES
557 };
558
559 /*
560 * php_caudium_module_main() is called by the per-request handler and
561 * "executes" the script
562 */
563
php_caudium_module_main(php_caudium_request * ureq)564 static void php_caudium_module_main(php_caudium_request *ureq)
565 {
566 int res;
567 zend_file_handle file_handle;
568 #ifndef USE_PIKE_LEVEL_THREADS
569 struct thread_state *state;
570 extern struct program *thread_id_prog;
571 #endif
572 TSRMLS_FETCH();
573 GET_THIS();
574 THIS->filename = ureq->filename;
575 THIS->done_cb = ureq->done_cb;
576 THIS->my_fd_obj = ureq->my_fd_obj;
577 THIS->my_fd = ureq->my_fd;
578 THIS->request_data = ureq->request_data;
579 free(ureq);
580
581 #ifndef USE_PIKE_LEVEL_THREADS
582 mt_lock_interpreter();
583 init_interpreter();
584 #if PIKE_MAJOR_VERSION == 7 && PIKE_MINOR_VERSION < 1
585 thread_id = low_clone(thread_id_prog);
586 state = OBJ2THREAD(thread_id);
587 Pike_stack_top=((char *)&state)+ (thread_stack_size-16384) * STACK_DIRECTION;
588 recoveries = NULL;
589 call_c_initializers(thread_id);
590 OBJ2THREAD(thread_id)->id=th_self();
591 num_threads++;
592 thread_table_insert(thread_id);
593 state->status=THREAD_RUNNING;
594 #else
595 Pike_interpreter.thread_id = low_clone(thread_id_prog);
596 state = OBJ2THREAD(Pike_interpreter.thread_id);
597 Pike_interpreter.stack_top=((char *)&state)+ (thread_stack_size-16384) * STACK_DIRECTION;
598 Pike_interpreter.recoveries = NULL;
599 call_c_initializers(Pike_interpreter.thread_id);
600 state->id=th_self();
601 /* SWAP_OUT_THREAD(OBJ2THREAD(Pike_interpreter.thread_id)); */
602 num_threads++;
603 thread_table_insert(Pike_interpreter.thread_id);
604 state->status=THREAD_RUNNING;
605 #endif
606 state->swapped = 0;
607 #endif
608 SG(request_info).query_string = lookup_string_header("QUERY_STRING", 0);
609 SG(server_context) = (void *)1; /* avoid server_context == NULL */
610
611 /* path_translated is apparently the absolute path to the file, not
612 the translated PATH_INFO
613 */
614 SG(request_info).path_translated =
615 lookup_string_header("SCRIPT_FILENAME", NULL);
616 SG(request_info).request_uri = lookup_string_header("DOCUMENT_URI", NULL);
617 if(!SG(request_info).request_uri)
618 SG(request_info).request_uri = lookup_string_header("SCRIPT_NAME", NULL);
619 SG(request_info).request_method = lookup_string_header("REQUEST_METHOD", "GET");
620 SG(request_info).content_length = lookup_integer_header("HTTP_CONTENT_LENGTH", 0);
621 SG(request_info).content_type = lookup_string_header("HTTP_CONTENT_TYPE", NULL);
622 SG(sapi_headers).http_response_code = 200;
623 if (!strcmp(SG(request_info).request_method, "HEAD")) {
624 SG(request_info).headers_only = 1;
625 } else {
626 SG(request_info).headers_only = 0;
627 }
628
629 /* Let PHP5 handle the deconding of the AUTH */
630 php_handle_auth_data(lookup_string_header("HTTP_AUTHORIZATION", NULL), TSRMLS_C);
631 /* Swap out this thread and release the interpreter lock to allow
632 * Pike threads to run. We wait since the above would otherwise require
633 * a lot of unlock/lock.
634 */
635 #ifndef USE_PIKE_LEVEL_THREADS
636 SWAP_OUT_THREAD(state);
637 mt_unlock_interpreter();
638 #else
639 THREADS_ALLOW();
640 #endif
641
642 file_handle.type = ZEND_HANDLE_FILENAME;
643 file_handle.filename = THIS->filename->str;
644 file_handle.opened_path = NULL;
645 file_handle.free_filename = 0;
646
647 THIS->written = 0;
648 res = php_request_startup(TSRMLS_C);
649
650 if(res == FAILURE) {
651 THREAD_SAFE_RUN({
652 apply_svalue(&THIS->done_cb, 0);
653 pop_stack();
654 free_struct(TSRMLS_C);
655 }, "Negative run response");
656 } else {
657 php_execute_script(&file_handle TSRMLS_CC);
658 php_request_shutdown(NULL);
659 THREAD_SAFE_RUN({
660 push_int(THIS->written);
661 apply_svalue(&THIS->done_cb, 1);
662 pop_stack();
663 free_struct(TSRMLS_C);
664 }, "positive run response");
665 }
666
667 #ifndef USE_PIKE_LEVEL_THREADS
668 mt_lock_interpreter();
669 SWAP_IN_THREAD(state);
670 #if PIKE_MAJOR_VERSION == 7 && PIKE_MINOR_VERSION < 1
671 state->status=THREAD_EXITED;
672 co_signal(& state->status_change);
673 thread_table_delete(thread_id);
674 free_object(thread_id);
675 thread_id=NULL;
676 #else
677 state->status=THREAD_EXITED;
678 co_signal(& state->status_change);
679 thread_table_delete(Pike_interpreter.thread_id);
680 free_object(Pike_interpreter.thread_id);
681 Pike_interpreter.thread_id=NULL;
682 #endif
683 cleanup_interpret();
684 num_threads--;
685 mt_unlock_interpreter();
686 #else
687 THREADS_DISALLOW();
688 #endif
689 }
690
691 /*
692 * The php_caudium_request_handler() is called per request and handles
693 * everything for one request.
694 */
695
f_php_caudium_request_handler(INT32 args)696 void f_php_caudium_request_handler(INT32 args)
697 {
698 struct object *my_fd_obj;
699 struct mapping *request_data;
700 struct svalue *done_callback;
701 struct pike_string *script;
702 struct svalue *raw_fd;
703 struct pike_string *ind;
704 php_caudium_request *_request;
705 THIS = malloc(sizeof(php_caudium_request));
706 if(THIS == NULL)
707 Pike_error("Out of memory.");
708
709 get_all_args("PHP5.Interpreter->run", args, "%S%m%O%*", &script,
710 &request_data, &my_fd_obj, &done_callback);
711 if(done_callback->type != PIKE_T_FUNCTION)
712 Pike_error("PHP5.Interpreter->run: Bad argument 4, expected function.\n");
713 add_ref(request_data);
714 add_ref(my_fd_obj);
715 add_ref(script);
716
717 THIS->request_data = request_data;
718 THIS->my_fd_obj = my_fd_obj;
719 THIS->filename = script;
720 assign_svalue_no_free(&THIS->done_cb, done_callback);
721
722 ind = make_shared_binary_string("my_fd", 5);
723 raw_fd = low_mapping_string_lookup(THIS->request_data, ind);
724 if(raw_fd && raw_fd->type == PIKE_T_OBJECT)
725 {
726 int fd = fd_from_object(raw_fd->u.object);
727 if(fd == -1)
728 THIS->my_fd = 0; /* Don't send directly to this FD... */
729 else
730 THIS->my_fd = fd;
731 } else
732 THIS->my_fd = 0;
733 #ifdef USE_PIKE_LEVEL_THREADS
734 php_caudium_module_main(THIS);
735 #else
736 th_farm((void (*)(void *))php_caudium_module_main, THIS);
737 #endif
738 pop_n_elems(args);
739 }
740
free_struct(TSRMLS_D)741 static void free_struct(TSRMLS_D)
742 {
743 GET_THIS();
744 if(THIS->request_data) free_mapping(THIS->request_data);
745 if(THIS->my_fd_obj) free_object(THIS->my_fd_obj);
746 free_svalue(&THIS->done_cb);
747 if(THIS->filename) free_string(THIS->filename);
748 MEMSET(THIS, 0, sizeof(php_caudium_request));
749 }
750
751
752 /*
753 * pike_module_init() is called by Pike once at startup
754 *
755 * This functions allocates basic structures
756 */
757
pike_module_init(void)758 void pike_module_init( void )
759 {
760 if (!caudium_php_initialized) {
761 caudium_php_initialized = 1;
762 tsrm_startup(1, 1, 0, NULL);
763 ts_allocate_id(&caudium_globals_id, sizeof(php_caudium_request), NULL, NULL);
764 sapi_startup(&caudium_sapi_module);
765 sapi_module.startup(&caudium_sapi_module);
766 }
767 start_new_program(); /* Text */
768 pike_add_function("run", f_php_caudium_request_handler,
769 "function(string, mapping, object, function:void)", 0);
770 end_class("Interpreter", 0);
771 }
772
773 /*
774 * pike_module_exit() performs the last steps before the
775 * server exists. Shutdowns basic services and frees memory
776 */
777
pike_module_exit(void)778 void pike_module_exit(void)
779 {
780 caudium_php_initialized = 0;
781 sapi_module.shutdown(&caudium_sapi_module);
782 tsrm_shutdown();
783 }
784 #endif
785