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__ |
6ff77aff |
15 | /* $Id: FCGI.PL,v 1.11 1999/08/10 11:06:37 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" |
23 | |
24 | #ifndef FALSE |
25 | #define FALSE (0) |
26 | #endif |
27 | |
28 | #ifndef TRUE |
29 | #define TRUE (1) |
30 | #endif |
31 | |
b716743a |
32 | #ifndef dTHX |
33 | #define dTHX |
34 | #endif |
35 | |
1b64d24d |
36 | #ifdef USE_SFIO |
37 | typedef struct |
38 | { |
39 | Sfdisc_t disc; |
40 | FCGX_Stream *stream; |
41 | } FCGI_Disc; |
42 | |
43 | static ssize_t |
44 | sffcgiread(f, buf, n, disc) |
45 | Sfio_t* f; /* stream involved */ |
46 | Void_t* buf; /* buffer to read into */ |
47 | size_t n; /* number of bytes to read */ |
48 | Sfdisc_t* disc; /* discipline */ |
49 | { |
50 | return FCGX_GetStr(buf, n, ((FCGI_Disc *)disc)->stream); |
51 | } |
52 | |
53 | static ssize_t |
54 | sffcgiwrite(f, buf, n, disc) |
55 | Sfio_t* f; /* stream involved */ |
56 | const Void_t* buf; /* buffer to read into */ |
57 | size_t n; /* number of bytes to read */ |
58 | Sfdisc_t* disc; /* discipline */ |
59 | { |
60 | n = FCGX_PutStr(buf, n, ((FCGI_Disc *)disc)->stream); |
61 | FCGX_FFlush(((FCGI_Disc *)disc)->stream); |
62 | return n; |
63 | } |
64 | |
65 | Sfdisc_t * |
66 | sfdcnewfcgi(stream) |
67 | FCGX_Stream *stream; |
68 | { |
69 | FCGI_Disc* disc; |
70 | |
71 | New(1000,disc,1,FCGI_Disc); |
72 | if (!disc) return (Sfdisc_t *)disc; |
73 | |
74 | disc->disc.exceptf = (Sfexcept_f)NULL; |
75 | disc->disc.seekf = (Sfseek_f)NULL; |
76 | disc->disc.readf = sffcgiread; |
77 | disc->disc.writef = sffcgiwrite; |
78 | disc->stream = stream; |
79 | return (Sfdisc_t *)disc; |
80 | } |
81 | |
82 | Sfdisc_t * |
83 | sfdcdelfcgi(disc) |
84 | Sfdisc_t* disc; |
85 | { |
86 | Safefree(disc); |
87 | return 0; |
88 | } |
89 | #endif |
90 | |
90a18d65 |
91 | static int isCGI = -1; /* -1: not checked; 0: FCGI; 1: FCGI */ |
92 | |
b716743a |
93 | #if defined(USE_LOCKING) && defined(USE_THREADS) |
94 | static perl_mutex accept_mutex; |
95 | #endif |
96 | |
90a18d65 |
97 | typedef struct FCGP_Request { |
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]; |
107 | #endif |
90a18d65 |
108 | } FCGP_Request; |
109 | |
1b64d24d |
110 | static int |
90a18d65 |
111 | FCGI_Flush(FCGP_Request* request) |
1b64d24d |
112 | { |
b716743a |
113 | dTHX; |
114 | |
115 | if(!request->bound) { |
1b64d24d |
116 | return; |
117 | } |
118 | #ifdef USE_SFIO |
2c38ecd7 |
119 | sfsync(IoOFP(GvIOp(request->gv[1]))); |
120 | sfsync(IoOFP(GvIOp(request->gv[2]))); |
1b64d24d |
121 | #else |
90a18d65 |
122 | FCGX_FFlush((FCGX_Stream *) SvIV((SV*) SvRV(request->svout))); |
123 | FCGX_FFlush((FCGX_Stream *) SvIV((SV*) SvRV(request->sverr))); |
1b64d24d |
124 | #endif |
125 | } |
126 | |
34bfd355 |
127 | static void |
128 | FCGI_UndoBinding(FCGP_Request* request) |
129 | { |
130 | #ifdef USE_SFIO |
2c38ecd7 |
131 | IO *io[3]; |
132 | int i; |
133 | #endif |
b716743a |
134 | dTHX; |
2c38ecd7 |
135 | |
136 | #ifdef USE_SFIO |
137 | sfdcdelfcgi(sfdisc(IoIFP(io[0] = GvIOp(request->gv[0])), SF_POPDISC)); |
138 | sfdcdelfcgi(sfdisc(IoOFP(io[1] = GvIOp(request->gv[1])), SF_POPDISC)); |
139 | sfdcdelfcgi(sfdisc(IoOFP(io[2] = GvIOp(request->gv[2])), SF_POPDISC)); |
140 | for (i = 0; i < 3; ++i) { |
141 | if (request->sfcreated[i]) { |
142 | sfclose(IoIFP(io[i])); |
143 | IoIFP(io[i]) = IoOFP(io[i]) = Nullfp; |
144 | request->sfcreated[i] = FALSE; |
145 | } |
146 | } |
34bfd355 |
147 | #else |
148 | FCGI_Flush(request); |
149 | sv_unmagic((SV *)request->gv[0], 'q'); |
150 | sv_unmagic((SV *)request->gv[1], 'q'); |
151 | sv_unmagic((SV *)request->gv[2], 'q'); |
152 | #endif |
b716743a |
153 | FCGX_Finish_r(request->requestPtr); |
154 | request->bound = FALSE; |
155 | } |
156 | |
157 | static void |
158 | populate_env(envp, hv) |
159 | char **envp; |
160 | HV *hv; |
161 | { |
162 | int i; |
163 | char *p, *p1; |
164 | SV *sv; |
165 | dTHX; |
166 | |
6ff77aff |
167 | hv_clear(hv); |
b716743a |
168 | for(i = 0; ; i++) { |
169 | if((p = envp[i]) == NULL) { |
170 | break; |
171 | } |
172 | p1 = strchr(p, '='); |
173 | assert(p1 != NULL); |
174 | sv = newSVpv(p1 + 1, 0); |
175 | /* call magic for this value ourselves */ |
176 | hv_store(hv, p, p1 - p, sv, 0); |
177 | SvSETMAGIC(sv); |
178 | } |
34bfd355 |
179 | } |
180 | |
1b64d24d |
181 | static int |
cebfd7c4 |
182 | FCGI_Accept(FCGP_Request* request) |
1b64d24d |
183 | { |
b716743a |
184 | dTHX; |
185 | |
90a18d65 |
186 | if(isCGI == -1) { |
1b64d24d |
187 | /* |
188 | * First call to FCGI_Accept. Is application running |
189 | * as FastCGI or as CGI? |
190 | */ |
191 | isCGI = FCGX_IsCGI(); |
192 | } else if(isCGI) { |
193 | /* |
194 | * Not first call to FCGI_Accept and running as CGI means |
195 | * application is done. |
196 | */ |
197 | return(EOF); |
eede4b76 |
198 | } |
1b64d24d |
199 | if(!isCGI) { |
2c38ecd7 |
200 | #ifdef USE_SFIO |
201 | IO *io[3]; |
202 | int i; |
203 | #endif |
6ff77aff |
204 | FCGX_Request *fcgx_req = request->requestPtr; |
b716743a |
205 | int acceptResult; |
206 | |
207 | if(request->bound) { |
208 | FCGI_UndoBinding(request); |
209 | } |
210 | #if defined(USE_LOCKING) && defined(USE_THREADS) |
211 | MUTEX_LOCK(&accept_mutex); |
212 | #endif |
6ff77aff |
213 | acceptResult = FCGX_Accept_r(fcgx_req); |
b716743a |
214 | #if defined(USE_LOCKING) && defined(USE_THREADS) |
215 | MUTEX_UNLOCK(&accept_mutex); |
216 | #endif |
1b64d24d |
217 | if(acceptResult < 0) { |
218 | return acceptResult; |
219 | } |
d8cc97fb |
220 | |
6ff77aff |
221 | populate_env(fcgx_req->envp, request->hvEnv); |
d8cc97fb |
222 | |
1b64d24d |
223 | #ifdef USE_SFIO |
2c38ecd7 |
224 | for (i = 0; i < 3; ++i) { |
6ff77aff |
225 | io[i] = GvIOn(request->gv[i]); |
2c38ecd7 |
226 | if (!(i == 0 ? IoIFP(io[i]) : IoOFP(io[i]))) { |
227 | IoIFP(io[i]) = sftmp(0); |
228 | /*IoIFP(io[i]) = sfnew(NULL, NULL, SF_UNBOUND, 0, |
229 | SF_STRING | (i ? SF_WRITE : SF_READ));*/ |
230 | if (i != 0) IoOFP(io[i]) = IoIFP(io[i]); |
231 | request->sfcreated[i] = TRUE; |
232 | } |
233 | } |
6ff77aff |
234 | sfdisc(IoIFP(io[0]), sfdcnewfcgi(fcgx_req->in)); |
235 | sfdisc(IoOFP(io[1]), sfdcnewfcgi(fcgx_req->out)); |
236 | sfdisc(IoOFP(io[2]), sfdcnewfcgi(fcgx_req->err)); |
1b64d24d |
237 | #else |
90a18d65 |
238 | if (!request->svout) { |
eede4b76 |
239 | newSVrv(request->svout = newSV(0), "FCGI::Stream"); |
eede4b76 |
240 | newSVrv(request->sverr = newSV(0), "FCGI::Stream"); |
eede4b76 |
241 | newSVrv(request->svin = newSV(0), "FCGI::Stream"); |
1b64d24d |
242 | } |
6ff77aff |
243 | sv_magic((SV *)request->gv[1], request->svout, 'q', Nullch, 0); |
244 | sv_magic((SV *)request->gv[2], request->sverr, 'q', Nullch, 0); |
245 | sv_magic((SV *)request->gv[0], request->svin, 'q', Nullch, 0); |
246 | sv_setiv(SvRV(request->svout), (IV) fcgx_req->out); |
247 | sv_setiv(SvRV(request->sverr), (IV) fcgx_req->err); |
248 | sv_setiv(SvRV(request->svin), (IV) fcgx_req->in); |
1b64d24d |
249 | #endif |
b716743a |
250 | request->bound = TRUE; |
1b64d24d |
251 | } |
1b64d24d |
252 | return 0; |
253 | } |
254 | |
255 | static void |
90a18d65 |
256 | FCGI_Finish(FCGP_Request* request) |
1b64d24d |
257 | { |
b716743a |
258 | dTHX; |
259 | |
260 | if(!request->bound) { |
1b64d24d |
261 | return; |
262 | } |
34bfd355 |
263 | FCGI_UndoBinding(request); |
1b64d24d |
264 | } |
265 | |
266 | static int |
90a18d65 |
267 | FCGI_StartFilterData(FCGP_Request* request) |
268 | { |
6ff77aff |
269 | return request->requestPtr->in ? |
270 | FCGX_StartFilterData(request->requestPtr->in) : -1; |
90a18d65 |
271 | } |
272 | |
273 | static FCGP_Request * |
6ff77aff |
274 | FCGI_Request(in, out, err, env, socket, flags) |
275 | GV* in; |
276 | GV* out; |
277 | GV* err; |
278 | HV* env; |
279 | int socket; |
280 | int flags; |
1b64d24d |
281 | { |
90a18d65 |
282 | FCGX_Request* fcgx_req; |
283 | FCGP_Request* req; |
284 | |
285 | Newz(551, fcgx_req, 1, FCGX_Request); |
6ff77aff |
286 | FCGX_InitRequest(fcgx_req, socket, flags); |
90a18d65 |
287 | Newz(551, req, 1, FCGP_Request); |
288 | req->requestPtr = fcgx_req; |
6ff77aff |
289 | req->gv[0] = in; |
290 | req->gv[1] = out; |
291 | req->gv[2] = err; |
292 | req->hvEnv = env; |
90a18d65 |
293 | |
294 | return req; |
1b64d24d |
295 | } |
296 | |
297 | static void |
90a18d65 |
298 | FCGI_Release_Request(FCGP_Request *req) |
1b64d24d |
299 | { |
6ff77aff |
300 | FCGI_Finish(req); |
90a18d65 |
301 | Safefree(req->requestPtr); |
302 | Safefree(req); |
1b64d24d |
303 | } |
304 | |
34bfd355 |
305 | static void |
b716743a |
306 | FCGI_Init() |
34bfd355 |
307 | { |
b716743a |
308 | #if defined(USE_LOCKING) && defined(USE_THREADS) |
309 | dTHX; |
34bfd355 |
310 | |
b716743a |
311 | MUTEX_INIT(&accept_mutex); |
312 | #endif |
34bfd355 |
313 | } |
314 | |
eede4b76 |
315 | typedef FCGX_Stream * FCGI__Stream; |
316 | typedef FCGP_Request * FCGI; |
d8cc97fb |
317 | typedef GV* GLOBREF; |
318 | typedef HV* HASHREF; |
1b64d24d |
319 | |
320 | MODULE = FCGI PACKAGE = FCGI |
321 | |
b716743a |
322 | BOOT: |
323 | FCGI_Init(); |
eede4b76 |
324 | |
325 | SV * |
6ff77aff |
326 | RequestX(in, out, err, env, socket, flags) |
327 | GLOBREF in; |
328 | GLOBREF out; |
329 | GLOBREF err; |
330 | HASHREF env; |
331 | int socket; |
332 | int flags; |
eede4b76 |
333 | |
6ff77aff |
334 | PROTOTYPE: ***$$$ |
eede4b76 |
335 | CODE: |
6ff77aff |
336 | RETVAL = sv_setref_pv(newSV(0), "FCGI", |
337 | FCGI_Request(in, out, err, env, socket, flags)); |
eede4b76 |
338 | |
339 | OUTPUT: |
340 | RETVAL |
341 | |
342 | |
343 | int |
6ff77aff |
344 | Accept(request) |
eede4b76 |
345 | |
d8cc97fb |
346 | FCGI request; |
eede4b76 |
347 | |
6ff77aff |
348 | PROTOTYPE: $ |
eede4b76 |
349 | |
350 | CODE: |
d8cc97fb |
351 | RETVAL = FCGI_Accept(request); |
eede4b76 |
352 | |
eede4b76 |
353 | OUTPUT: |
354 | RETVAL |
355 | |
356 | |
357 | void |
d8cc97fb |
358 | Finish(request) |
eede4b76 |
359 | |
d8cc97fb |
360 | FCGI request; |
eede4b76 |
361 | |
d8cc97fb |
362 | PROTOTYPE: $ |
eede4b76 |
363 | |
364 | CODE: |
eede4b76 |
365 | { |
366 | /* |
eede4b76 |
367 | * Finish the request. |
368 | */ |
369 | FCGI_Finish(request); |
370 | } |
371 | |
372 | |
373 | void |
d8cc97fb |
374 | Flush(request) |
eede4b76 |
375 | |
d8cc97fb |
376 | FCGI request; |
eede4b76 |
377 | |
d8cc97fb |
378 | PROTOTYPE: $ |
eede4b76 |
379 | |
380 | CODE: |
eede4b76 |
381 | FCGI_Flush(request); |
382 | |
eede4b76 |
383 | |
384 | int |
d8cc97fb |
385 | StartFilterData(request) |
eede4b76 |
386 | |
d8cc97fb |
387 | FCGI request; |
eede4b76 |
388 | |
d8cc97fb |
389 | PROTOTYPE: $ |
eede4b76 |
390 | |
391 | CODE: |
eede4b76 |
392 | RETVAL = FCGI_StartFilterData(request); |
393 | |
394 | OUTPUT: |
395 | RETVAL |
396 | |
eede4b76 |
397 | void |
398 | DESTROY(request) |
399 | FCGI request; |
400 | |
401 | CODE: |
402 | FCGI_Release_Request(request); |
403 | |
404 | |
405 | |
406 | MODULE = FCGI PACKAGE = FCGI::Stream |
90a18d65 |
407 | |
1b64d24d |
408 | #ifndef USE_SFIO |
1b64d24d |
409 | |
410 | void |
411 | PRINT(stream, ...) |
eede4b76 |
412 | FCGI::Stream stream; |
1b64d24d |
413 | |
414 | PREINIT: |
415 | int n; |
416 | |
417 | CODE: |
418 | for (n = 1; n < items; ++n) { |
419 | STRLEN len; |
420 | register char *tmps = (char *)SvPV(ST(n),len); |
421 | FCGX_PutStr(tmps, len, stream); |
422 | } |
423 | if (SvTRUEx(perl_get_sv("|", FALSE))) |
424 | FCGX_FFlush(stream); |
425 | |
426 | int |
427 | WRITE(stream, bufsv, len, ...) |
eede4b76 |
428 | FCGI::Stream stream; |
1b64d24d |
429 | SV * bufsv; |
430 | int len; |
431 | |
432 | PREINIT: |
433 | int offset; |
434 | char * buf; |
435 | STRLEN blen; |
436 | int n; |
437 | |
438 | CODE: |
439 | offset = (items == 4) ? (int)SvIV(ST(3)) : 0; |
440 | buf = SvPV(bufsv, blen); |
441 | if (offset < 0) offset += blen; |
442 | if (len > blen - offset) |
443 | len = blen - offset; |
444 | if (offset < 0 || offset >= blen || |
445 | (n = FCGX_PutStr(buf+offset, len, stream)) < 0) |
446 | ST(0) = &PL_sv_undef; |
447 | else { |
448 | ST(0) = sv_newmortal(); |
449 | sv_setpvf(ST(0), "%c", n); |
450 | } |
451 | |
452 | int |
453 | READ(stream, bufsv, len, ...) |
eede4b76 |
454 | FCGI::Stream stream; |
1b64d24d |
455 | SV * bufsv; |
456 | int len; |
457 | |
458 | PREINIT: |
459 | int offset; |
460 | char * buf; |
461 | |
462 | CODE: |
463 | offset = (items == 4) ? (int)SvIV(ST(3)) : 0; |
464 | if (! SvOK(bufsv)) |
465 | sv_setpvn(bufsv, "", 0); |
466 | buf = SvGROW(bufsv, len+offset+1); |
467 | len = FCGX_GetStr(buf+offset, len, stream); |
468 | SvCUR_set(bufsv, len+offset); |
469 | *SvEND(bufsv) = '\0'; |
470 | (void)SvPOK_only(bufsv); |
471 | SvSETMAGIC(bufsv); |
472 | RETVAL = len; |
473 | |
474 | OUTPUT: |
475 | RETVAL |
476 | |
477 | SV * |
478 | GETC(stream) |
eede4b76 |
479 | FCGI::Stream stream; |
1b64d24d |
480 | |
481 | PREINIT: |
482 | int retval; |
483 | |
484 | CODE: |
485 | if ((retval = FCGX_GetChar(stream)) != -1) { |
486 | ST(0) = sv_newmortal(); |
487 | sv_setpvf(ST(0), "%c", retval); |
488 | } else ST(0) = &PL_sv_undef; |
489 | |
490 | bool |
491 | CLOSE(stream) |
eede4b76 |
492 | FCGI::Stream stream; |
1b64d24d |
493 | |
494 | ALIAS: |
495 | DESTROY = 1 |
496 | |
497 | CODE: |
498 | RETVAL = FCGX_FClose(stream) != -1; |
499 | |
500 | OUTPUT: |
501 | RETVAL |
502 | |
503 | #endif |