1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
5: | Copyright (c) 1997-2012 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: caudium.c,v 1.1.1.2 2012/05/29 12:34:35 misho Exp $ */
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:
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: */
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: */
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
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
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
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
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
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
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:
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
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 *
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:
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: caudium.c,v 1.1.1.2 2012/05/29 12:34:35 misho Exp $");
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:
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:
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:
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:
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:
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:
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:
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:
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
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>