Commit | Line | Data |
1b64d24d |
1 | use Config; |
2 | |
3 | open OUT, ">FCGI.xs"; |
4 | |
5 | print "Generating FCGI.xs for Perl version $]\n"; |
6 | #unless (exists $Config{apiversion} && $Config{apiversion} >= 5.005) |
7 | unless ($] >= 5.005) { |
8 | for (qw(sv_undef diehook warnhook in_eval)) { |
9 | print OUT "#define PL_$_ $_\n" |
10 | } |
11 | } |
12 | print OUT while <DATA>; |
13 | close OUT; |
14 | __END__ |
1d209997 |
15 | /* $Id: FCGI.PL,v 1.18 2000/11/01 15:12:26 skimo Exp $ */ |
1b64d24d |
16 | |
17 | #include "EXTERN.h" |
18 | #include "perl.h" |
19 | #include "XSUB.h" |
20 | |
b716743a |
21 | #include "fcgi_config.h" |
1b64d24d |
22 | #include "fcgiapp.h" |
5baeeca7 |
23 | #include "fastcgi.h" |
1b64d24d |
24 | |
25 | #ifndef FALSE |
26 | #define FALSE (0) |
27 | #endif |
28 | |
29 | #ifndef TRUE |
30 | #define TRUE (1) |
31 | #endif |
32 | |
b716743a |
33 | #ifndef dTHX |
34 | #define dTHX |
35 | #endif |
36 | |
1b64d24d |
37 | #ifdef USE_SFIO |
38 | typedef struct |
39 | { |
40 | Sfdisc_t disc; |
41 | FCGX_Stream *stream; |
42 | } FCGI_Disc; |
43 | |
44 | static ssize_t |
45 | sffcgiread(f, buf, n, disc) |
46 | Sfio_t* f; /* stream involved */ |
47 | Void_t* buf; /* buffer to read into */ |
48 | size_t n; /* number of bytes to read */ |
49 | Sfdisc_t* disc; /* discipline */ |
50 | { |
51 | return FCGX_GetStr(buf, n, ((FCGI_Disc *)disc)->stream); |
52 | } |
53 | |
54 | static ssize_t |
55 | sffcgiwrite(f, buf, n, disc) |
56 | Sfio_t* f; /* stream involved */ |
57 | const Void_t* buf; /* buffer to read into */ |
58 | size_t n; /* number of bytes to read */ |
59 | Sfdisc_t* disc; /* discipline */ |
60 | { |
61 | n = FCGX_PutStr(buf, n, ((FCGI_Disc *)disc)->stream); |
62 | FCGX_FFlush(((FCGI_Disc *)disc)->stream); |
63 | return n; |
64 | } |
65 | |
66 | Sfdisc_t * |
67 | sfdcnewfcgi(stream) |
68 | FCGX_Stream *stream; |
69 | { |
70 | FCGI_Disc* disc; |
71 | |
72 | New(1000,disc,1,FCGI_Disc); |
73 | if (!disc) return (Sfdisc_t *)disc; |
74 | |
75 | disc->disc.exceptf = (Sfexcept_f)NULL; |
76 | disc->disc.seekf = (Sfseek_f)NULL; |
77 | disc->disc.readf = sffcgiread; |
78 | disc->disc.writef = sffcgiwrite; |
79 | disc->stream = stream; |
80 | return (Sfdisc_t *)disc; |
81 | } |
82 | |
83 | Sfdisc_t * |
84 | sfdcdelfcgi(disc) |
85 | Sfdisc_t* disc; |
86 | { |
87 | Safefree(disc); |
88 | return 0; |
89 | } |
90 | #endif |
91 | |
b716743a |
92 | #if defined(USE_LOCKING) && defined(USE_THREADS) |
93 | static perl_mutex accept_mutex; |
94 | #endif |
95 | |
90a18d65 |
96 | typedef struct FCGP_Request { |
5baeeca7 |
97 | int accepted; |
b716743a |
98 | int bound; |
90a18d65 |
99 | SV* svin; |
100 | SV* svout; |
101 | SV* sverr; |
eede4b76 |
102 | GV* gv[3]; |
34bfd355 |
103 | HV* hvEnv; |
90a18d65 |
104 | FCGX_Request* requestPtr; |
2c38ecd7 |
105 | #ifdef USE_SFIO |
106 | int sfcreated[3]; |
5baeeca7 |
107 | IO* io[3]; |
2c38ecd7 |
108 | #endif |
90a18d65 |
109 | } FCGP_Request; |
110 | |
5baeeca7 |
111 | static void FCGI_Finish(FCGP_Request* request); |
112 | |
1b64d24d |
113 | static int |
90a18d65 |
114 | FCGI_Flush(FCGP_Request* request) |
1b64d24d |
115 | { |
b716743a |
116 | dTHX; |
117 | |
118 | if(!request->bound) { |
1b64d24d |
119 | return; |
120 | } |
121 | #ifdef USE_SFIO |
2c38ecd7 |
122 | sfsync(IoOFP(GvIOp(request->gv[1]))); |
123 | sfsync(IoOFP(GvIOp(request->gv[2]))); |
1b64d24d |
124 | #else |
90a18d65 |
125 | FCGX_FFlush((FCGX_Stream *) SvIV((SV*) SvRV(request->svout))); |
126 | FCGX_FFlush((FCGX_Stream *) SvIV((SV*) SvRV(request->sverr))); |
1b64d24d |
127 | #endif |
128 | } |
129 | |
34bfd355 |
130 | static void |
131 | FCGI_UndoBinding(FCGP_Request* request) |
132 | { |
b716743a |
133 | dTHX; |
2c38ecd7 |
134 | |
135 | #ifdef USE_SFIO |
5baeeca7 |
136 | sfdcdelfcgi(sfdisc(IoIFP(request->io[0]), SF_POPDISC)); |
137 | sfdcdelfcgi(sfdisc(IoOFP(request->io[1]), SF_POPDISC)); |
138 | sfdcdelfcgi(sfdisc(IoOFP(request->io[2]), SF_POPDISC)); |
34bfd355 |
139 | #else |
34bfd355 |
140 | sv_unmagic((SV *)request->gv[0], 'q'); |
141 | sv_unmagic((SV *)request->gv[1], 'q'); |
142 | sv_unmagic((SV *)request->gv[2], 'q'); |
143 | #endif |
b716743a |
144 | request->bound = FALSE; |
145 | } |
146 | |
147 | static void |
5baeeca7 |
148 | FCGI_Bind(FCGP_Request* request) |
149 | { |
150 | dTHX; |
151 | |
152 | #ifdef USE_SFIO |
37a69de1 |
153 | sfdisc(IoIFP(request->io[0]), sfdcnewfcgi(request->requestPtr->in)); |
154 | sfdisc(IoOFP(request->io[1]), sfdcnewfcgi(request->requestPtr->out)); |
155 | sfdisc(IoOFP(request->io[2]), sfdcnewfcgi(request->requestPtr->err)); |
5baeeca7 |
156 | #else |
157 | sv_magic((SV *)request->gv[1], request->svout, 'q', Nullch, 0); |
158 | sv_magic((SV *)request->gv[2], request->sverr, 'q', Nullch, 0); |
159 | sv_magic((SV *)request->gv[0], request->svin, 'q', Nullch, 0); |
160 | #endif |
161 | request->bound = TRUE; |
162 | } |
163 | |
164 | static void |
b716743a |
165 | populate_env(envp, hv) |
166 | char **envp; |
167 | HV *hv; |
168 | { |
169 | int i; |
170 | char *p, *p1; |
171 | SV *sv; |
172 | dTHX; |
173 | |
6ff77aff |
174 | hv_clear(hv); |
b716743a |
175 | for(i = 0; ; i++) { |
176 | if((p = envp[i]) == NULL) { |
177 | break; |
178 | } |
179 | p1 = strchr(p, '='); |
180 | assert(p1 != NULL); |
181 | sv = newSVpv(p1 + 1, 0); |
182 | /* call magic for this value ourselves */ |
183 | hv_store(hv, p, p1 - p, sv, 0); |
184 | SvSETMAGIC(sv); |
185 | } |
34bfd355 |
186 | } |
187 | |
1d209997 |
188 | static int |
189 | FCGI_IsFastCGI(FCGP_Request* request) |
1b64d24d |
190 | { |
e40fb02c |
191 | static int isCGI = -1; /* -1: not checked; 0: FCGI; 1: CGI */ |
5baeeca7 |
192 | |
1d209997 |
193 | if (request->requestPtr->listen_sock == FCGI_LISTENSOCK_FILENO) { |
194 | if (isCGI == -1) |
195 | isCGI = FCGX_IsCGI(); |
196 | return !isCGI; |
197 | } |
198 | |
199 | /* A explicit socket is being used -> assume FastCGI */ |
200 | return 1; |
201 | } |
5baeeca7 |
202 | |
1d209997 |
203 | static int |
204 | FCGI_Accept(FCGP_Request* request) |
205 | { |
794c66be |
206 | dTHX; |
207 | |
1d209997 |
208 | if (!FCGI_IsFastCGI(request)) { |
209 | static int been_here = 0; |
210 | |
1b64d24d |
211 | /* |
212 | * Not first call to FCGI_Accept and running as CGI means |
213 | * application is done. |
214 | */ |
1d209997 |
215 | if (been_here) |
216 | return EOF; |
217 | |
218 | been_here = 1; |
219 | } else { |
37a69de1 |
220 | #ifdef USE_SFIO |
221 | int i; |
222 | #endif |
6ff77aff |
223 | FCGX_Request *fcgx_req = request->requestPtr; |
b716743a |
224 | int acceptResult; |
225 | |
5baeeca7 |
226 | FCGI_Finish(request); |
b716743a |
227 | #if defined(USE_LOCKING) && defined(USE_THREADS) |
228 | MUTEX_LOCK(&accept_mutex); |
229 | #endif |
6ff77aff |
230 | acceptResult = FCGX_Accept_r(fcgx_req); |
b716743a |
231 | #if defined(USE_LOCKING) && defined(USE_THREADS) |
232 | MUTEX_UNLOCK(&accept_mutex); |
233 | #endif |
1b64d24d |
234 | if(acceptResult < 0) { |
235 | return acceptResult; |
236 | } |
d8cc97fb |
237 | |
6ff77aff |
238 | populate_env(fcgx_req->envp, request->hvEnv); |
d8cc97fb |
239 | |
1b64d24d |
240 | #ifdef USE_SFIO |
2c38ecd7 |
241 | for (i = 0; i < 3; ++i) { |
5baeeca7 |
242 | request->io[i] = GvIOn(request->gv[i]); |
243 | if (!(i == 0 ? IoIFP(request->io[i]) |
244 | : IoOFP(request->io[i]))) { |
245 | IoIFP(request->io[i]) = sftmp(0); |
246 | /*IoIFP(request->io[i]) = sfnew(NULL, NULL, SF_UNBOUND, 0, |
2c38ecd7 |
247 | SF_STRING | (i ? SF_WRITE : SF_READ));*/ |
5baeeca7 |
248 | if (i != 0) |
249 | IoOFP(request->io[i]) = IoIFP(request->io[i]); |
2c38ecd7 |
250 | request->sfcreated[i] = TRUE; |
251 | } |
252 | } |
1b64d24d |
253 | #else |
90a18d65 |
254 | if (!request->svout) { |
eede4b76 |
255 | newSVrv(request->svout = newSV(0), "FCGI::Stream"); |
eede4b76 |
256 | newSVrv(request->sverr = newSV(0), "FCGI::Stream"); |
eede4b76 |
257 | newSVrv(request->svin = newSV(0), "FCGI::Stream"); |
1b64d24d |
258 | } |
6ff77aff |
259 | sv_setiv(SvRV(request->svout), (IV) fcgx_req->out); |
260 | sv_setiv(SvRV(request->sverr), (IV) fcgx_req->err); |
261 | sv_setiv(SvRV(request->svin), (IV) fcgx_req->in); |
1b64d24d |
262 | #endif |
5baeeca7 |
263 | FCGI_Bind(request); |
264 | request->accepted = TRUE; |
1b64d24d |
265 | } |
1b64d24d |
266 | return 0; |
267 | } |
268 | |
269 | static void |
90a18d65 |
270 | FCGI_Finish(FCGP_Request* request) |
1b64d24d |
271 | { |
37a69de1 |
272 | #ifdef USE_SFIO |
273 | int i; |
274 | #endif |
b716743a |
275 | dTHX; |
276 | |
5baeeca7 |
277 | if(!request->accepted) { |
1b64d24d |
278 | return; |
279 | } |
5baeeca7 |
280 | |
281 | if (request->bound) { |
282 | FCGI_UndoBinding(request); |
283 | } |
284 | #ifdef USE_SFIO |
285 | for (i = 0; i < 3; ++i) { |
286 | if (request->sfcreated[i]) { |
287 | sfclose(IoIFP(request->io[i])); |
288 | IoIFP(request->io[i]) = IoOFP(request->io[i]) = Nullfp; |
289 | request->sfcreated[i] = FALSE; |
290 | } |
291 | } |
292 | #endif |
293 | FCGX_Finish_r(request->requestPtr); |
294 | request->accepted = FALSE; |
1b64d24d |
295 | } |
296 | |
297 | static int |
90a18d65 |
298 | FCGI_StartFilterData(FCGP_Request* request) |
299 | { |
6ff77aff |
300 | return request->requestPtr->in ? |
301 | FCGX_StartFilterData(request->requestPtr->in) : -1; |
90a18d65 |
302 | } |
303 | |
304 | static FCGP_Request * |
6ff77aff |
305 | FCGI_Request(in, out, err, env, socket, flags) |
306 | GV* in; |
307 | GV* out; |
308 | GV* err; |
309 | HV* env; |
310 | int socket; |
311 | int flags; |
1b64d24d |
312 | { |
90a18d65 |
313 | FCGX_Request* fcgx_req; |
314 | FCGP_Request* req; |
315 | |
316 | Newz(551, fcgx_req, 1, FCGX_Request); |
6ff77aff |
317 | FCGX_InitRequest(fcgx_req, socket, flags); |
90a18d65 |
318 | Newz(551, req, 1, FCGP_Request); |
319 | req->requestPtr = fcgx_req; |
6ff77aff |
320 | req->gv[0] = in; |
321 | req->gv[1] = out; |
322 | req->gv[2] = err; |
323 | req->hvEnv = env; |
90a18d65 |
324 | |
325 | return req; |
1b64d24d |
326 | } |
327 | |
328 | static void |
90a18d65 |
329 | FCGI_Release_Request(FCGP_Request *req) |
1b64d24d |
330 | { |
6ff77aff |
331 | FCGI_Finish(req); |
90a18d65 |
332 | Safefree(req->requestPtr); |
333 | Safefree(req); |
1b64d24d |
334 | } |
335 | |
34bfd355 |
336 | static void |
b716743a |
337 | FCGI_Init() |
34bfd355 |
338 | { |
b716743a |
339 | #if defined(USE_LOCKING) && defined(USE_THREADS) |
340 | dTHX; |
34bfd355 |
341 | |
b716743a |
342 | MUTEX_INIT(&accept_mutex); |
343 | #endif |
e40fb02c |
344 | |
345 | FCGX_Init(); |
34bfd355 |
346 | } |
347 | |
eede4b76 |
348 | typedef FCGX_Stream * FCGI__Stream; |
349 | typedef FCGP_Request * FCGI; |
d8cc97fb |
350 | typedef GV* GLOBREF; |
351 | typedef HV* HASHREF; |
1b64d24d |
352 | |
1d209997 |
353 | MODULE = FCGI PACKAGE = FCGI PREFIX = FCGI_ |
1b64d24d |
354 | |
b716743a |
355 | BOOT: |
356 | FCGI_Init(); |
eede4b76 |
357 | |
358 | SV * |
6ff77aff |
359 | RequestX(in, out, err, env, socket, flags) |
360 | GLOBREF in; |
361 | GLOBREF out; |
362 | GLOBREF err; |
363 | HASHREF env; |
364 | int socket; |
365 | int flags; |
eede4b76 |
366 | |
6ff77aff |
367 | PROTOTYPE: ***$$$ |
eede4b76 |
368 | CODE: |
6ff77aff |
369 | RETVAL = sv_setref_pv(newSV(0), "FCGI", |
370 | FCGI_Request(in, out, err, env, socket, flags)); |
eede4b76 |
371 | |
372 | OUTPUT: |
373 | RETVAL |
374 | |
6b312a77 |
375 | int |
376 | OpenSocket(path, backlog) |
377 | char* path; |
378 | int backlog; |
379 | |
380 | PROTOTYPE: $$ |
381 | CODE: |
382 | RETVAL = FCGX_OpenSocket(path, backlog); |
383 | OUTPUT: |
384 | RETVAL |
385 | |
386 | void |
387 | CloseSocket(socket) |
388 | int socket; |
389 | |
390 | PROTOTYPE: $ |
391 | CODE: |
392 | close(socket); |
eede4b76 |
393 | |
394 | int |
1d209997 |
395 | FCGI_Accept(request) |
eede4b76 |
396 | |
d8cc97fb |
397 | FCGI request; |
eede4b76 |
398 | |
6ff77aff |
399 | PROTOTYPE: $ |
eede4b76 |
400 | |
eede4b76 |
401 | void |
1d209997 |
402 | FCGI_Finish(request) |
d8cc97fb |
403 | FCGI request; |
eede4b76 |
404 | |
d8cc97fb |
405 | PROTOTYPE: $ |
eede4b76 |
406 | |
eede4b76 |
407 | void |
1d209997 |
408 | FCGI_Flush(request) |
d8cc97fb |
409 | FCGI request; |
eede4b76 |
410 | |
d8cc97fb |
411 | PROTOTYPE: $ |
eede4b76 |
412 | |
9915cd6d |
413 | HV * |
414 | GetEnvironment(request) |
415 | FCGI request; |
416 | |
417 | PROTOTYPE: $ |
418 | |
419 | CODE: |
420 | RETVAL = request->hvEnv; |
421 | |
422 | OUTPUT: |
423 | RETVAL |
424 | |
425 | void |
426 | GetHandles(request) |
427 | FCGI request; |
428 | |
429 | PROTOTYPE: $ |
430 | |
431 | PREINIT: |
432 | int i; |
433 | |
434 | PPCODE: |
435 | EXTEND(sp,3); |
436 | for (i = 0; i < 3; ++i) |
1d209997 |
437 | PUSHs(sv_2mortal(newRV((SV *) request->gv[i]))); |
438 | |
439 | int |
440 | FCGI_IsFastCGI(request) |
441 | FCGI request; |
442 | |
443 | PROTOTYPE: $ |
9915cd6d |
444 | |
5baeeca7 |
445 | void |
446 | Detach(request) |
447 | |
448 | FCGI request; |
449 | |
450 | PROTOTYPE: $ |
451 | |
452 | CODE: |
453 | if (request->accepted && request->bound) |
454 | FCGI_UndoBinding(request); |
455 | |
456 | void |
457 | Attach(request) |
458 | |
459 | FCGI request; |
460 | |
461 | PROTOTYPE: $ |
462 | |
463 | CODE: |
464 | if (request->accepted && !request->bound) |
465 | FCGI_Bind(request); |
466 | |
eede4b76 |
467 | |
468 | int |
1d209997 |
469 | FCGI_StartFilterData(request) |
eede4b76 |
470 | |
d8cc97fb |
471 | FCGI request; |
eede4b76 |
472 | |
d8cc97fb |
473 | PROTOTYPE: $ |
eede4b76 |
474 | |
eede4b76 |
475 | void |
476 | DESTROY(request) |
477 | FCGI request; |
478 | |
479 | CODE: |
480 | FCGI_Release_Request(request); |
481 | |
482 | |
483 | |
484 | MODULE = FCGI PACKAGE = FCGI::Stream |
90a18d65 |
485 | |
1b64d24d |
486 | #ifndef USE_SFIO |
1b64d24d |
487 | |
488 | void |
489 | PRINT(stream, ...) |
eede4b76 |
490 | FCGI::Stream stream; |
1b64d24d |
491 | |
492 | PREINIT: |
493 | int n; |
494 | |
495 | CODE: |
496 | for (n = 1; n < items; ++n) { |
497 | STRLEN len; |
498 | register char *tmps = (char *)SvPV(ST(n),len); |
499 | FCGX_PutStr(tmps, len, stream); |
500 | } |
501 | if (SvTRUEx(perl_get_sv("|", FALSE))) |
502 | FCGX_FFlush(stream); |
503 | |
504 | int |
505 | WRITE(stream, bufsv, len, ...) |
eede4b76 |
506 | FCGI::Stream stream; |
1b64d24d |
507 | SV * bufsv; |
508 | int len; |
509 | |
510 | PREINIT: |
511 | int offset; |
512 | char * buf; |
513 | STRLEN blen; |
514 | int n; |
515 | |
516 | CODE: |
517 | offset = (items == 4) ? (int)SvIV(ST(3)) : 0; |
518 | buf = SvPV(bufsv, blen); |
519 | if (offset < 0) offset += blen; |
520 | if (len > blen - offset) |
521 | len = blen - offset; |
522 | if (offset < 0 || offset >= blen || |
523 | (n = FCGX_PutStr(buf+offset, len, stream)) < 0) |
524 | ST(0) = &PL_sv_undef; |
525 | else { |
526 | ST(0) = sv_newmortal(); |
527 | sv_setpvf(ST(0), "%c", n); |
528 | } |
529 | |
530 | int |
531 | READ(stream, bufsv, len, ...) |
eede4b76 |
532 | FCGI::Stream stream; |
1b64d24d |
533 | SV * bufsv; |
534 | int len; |
535 | |
536 | PREINIT: |
537 | int offset; |
538 | char * buf; |
539 | |
540 | CODE: |
541 | offset = (items == 4) ? (int)SvIV(ST(3)) : 0; |
542 | if (! SvOK(bufsv)) |
543 | sv_setpvn(bufsv, "", 0); |
544 | buf = SvGROW(bufsv, len+offset+1); |
545 | len = FCGX_GetStr(buf+offset, len, stream); |
546 | SvCUR_set(bufsv, len+offset); |
547 | *SvEND(bufsv) = '\0'; |
548 | (void)SvPOK_only(bufsv); |
549 | SvSETMAGIC(bufsv); |
550 | RETVAL = len; |
551 | |
552 | OUTPUT: |
553 | RETVAL |
554 | |
555 | SV * |
556 | GETC(stream) |
eede4b76 |
557 | FCGI::Stream stream; |
1b64d24d |
558 | |
559 | PREINIT: |
560 | int retval; |
561 | |
562 | CODE: |
563 | if ((retval = FCGX_GetChar(stream)) != -1) { |
564 | ST(0) = sv_newmortal(); |
565 | sv_setpvf(ST(0), "%c", retval); |
566 | } else ST(0) = &PL_sv_undef; |
567 | |
568 | bool |
569 | CLOSE(stream) |
eede4b76 |
570 | FCGI::Stream stream; |
1b64d24d |
571 | |
5baeeca7 |
572 | # ALIAS: |
573 | # DESTROY = 1 |
1b64d24d |
574 | |
575 | CODE: |
576 | RETVAL = FCGX_FClose(stream) != -1; |
577 | |
578 | OUTPUT: |
579 | RETVAL |
580 | |
581 | #endif |