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