5 print "Generating FCGI.xs for Perl version $]\n";
6 #unless (exists $Config{apiversion} && $Config{apiversion} >= 5.005)
8 for (qw(sv_undef diehook warnhook in_eval)) {
9 print OUT "#define PL_$_ $_\n"
12 print OUT while <DATA>;
15 /* $Id: FCGI.XL,v 1.10 2003/06/22 00:24:11 robs Exp $ */
21 #include "fcgi_config.h"
38 #define INT2PTR(a,b) ((a) (b))
49 sffcgiread(f, buf, n, disc)
50 Sfio_t* f; /* stream involved */
51 Void_t* buf; /* buffer to read into */
52 size_t n; /* number of bytes to read */
53 Sfdisc_t* disc; /* discipline */
55 return FCGX_GetStr(buf, n, ((FCGI_Disc *)disc)->stream);
59 sffcgiwrite(f, buf, n, disc)
60 Sfio_t* f; /* stream involved */
61 const Void_t* buf; /* buffer to read into */
62 size_t n; /* number of bytes to read */
63 Sfdisc_t* disc; /* discipline */
65 n = FCGX_PutStr(buf, n, ((FCGI_Disc *)disc)->stream);
66 FCGX_FFlush(((FCGI_Disc *)disc)->stream);
76 New(1000,disc,1,FCGI_Disc);
77 if (!disc) return (Sfdisc_t *)disc;
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;
96 #if defined(USE_LOCKING) && defined(USE_THREADS)
97 static perl_mutex accept_mutex;
100 typedef struct FCGP_Request {
108 FCGX_Request* requestPtr;
115 static void FCGI_Finish(FCGP_Request* request);
118 FCGI_Flush(FCGP_Request* request)
122 if(!request->bound) {
126 sfsync(IoOFP(GvIOp(request->gv[1])));
127 sfsync(IoOFP(GvIOp(request->gv[2])));
129 FCGX_FFlush(INT2PTR(FCGX_Stream *, SvIV((SV*) SvRV(request->svout))));
130 FCGX_FFlush(INT2PTR(FCGX_Stream *, SvIV((SV*) SvRV(request->sverr))));
135 FCGI_UndoBinding(FCGP_Request* request)
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));
145 sv_unmagic((SV *)GvIOp(request->gv[0]), 'q');
146 sv_unmagic((SV *)GvIOp(request->gv[1]), 'q');
147 sv_unmagic((SV *)GvIOp(request->gv[2]), 'q');
149 sv_unmagic((SV *)request->gv[0], 'q');
150 sv_unmagic((SV *)request->gv[1], 'q');
151 sv_unmagic((SV *)request->gv[2], 'q');
154 request->bound = FALSE;
158 FCGI_Bind(FCGP_Request* request)
163 sfdisc(IoIFP(request->io[0]), sfdcnewfcgi(request->requestPtr->in));
164 sfdisc(IoOFP(request->io[1]), sfdcnewfcgi(request->requestPtr->out));
165 sfdisc(IoOFP(request->io[2]), sfdcnewfcgi(request->requestPtr->err));
168 /* For tied filehandles, we apply tiedscalar magic to the IO
169 slot of the GP rather than the GV itself. */
171 if (!GvIOp(request->gv[1]))
172 GvIOp(request->gv[1]) = newIO();
173 if (!GvIOp(request->gv[2]))
174 GvIOp(request->gv[2]) = newIO();
175 if (!GvIOp(request->gv[0]))
176 GvIOp(request->gv[0]) = newIO();
178 sv_magic((SV *)GvIOp(request->gv[1]), request->svout, 'q', Nullch, 0);
179 sv_magic((SV *)GvIOp(request->gv[2]), request->sverr, 'q', Nullch, 0);
180 sv_magic((SV *)GvIOp(request->gv[0]), request->svin, 'q', Nullch, 0);
182 sv_magic((SV *)request->gv[1], request->svout, 'q', Nullch, 0);
183 sv_magic((SV *)request->gv[2], request->sverr, 'q', Nullch, 0);
184 sv_magic((SV *)request->gv[0], request->svin, 'q', Nullch, 0);
187 request->bound = TRUE;
191 populate_env(envp, hv)
202 if((p = envp[i]) == NULL) {
207 sv = newSVpv(p1 + 1, 0);
208 /* call magic for this value ourselves */
209 hv_store(hv, p, p1 - p, sv, 0);
215 FCGI_IsFastCGI(FCGP_Request* request)
217 static int isCGI = -1; /* -1: not checked; 0: FCGI; 1: CGI */
219 if (request->requestPtr->listen_sock == FCGI_LISTENSOCK_FILENO) {
221 isCGI = FCGX_IsCGI();
225 /* A explicit socket is being used -> assume FastCGI */
230 FCGI_Accept(FCGP_Request* request)
234 if (!FCGI_IsFastCGI(request)) {
235 static int been_here = 0;
238 * Not first call to FCGI_Accept and running as CGI means
239 * application is done.
249 FCGX_Request *fcgx_req = request->requestPtr;
252 FCGI_Finish(request);
253 #if defined(USE_LOCKING) && defined(USE_THREADS)
254 MUTEX_LOCK(&accept_mutex);
256 acceptResult = FCGX_Accept_r(fcgx_req);
257 #if defined(USE_LOCKING) && defined(USE_THREADS)
258 MUTEX_UNLOCK(&accept_mutex);
260 if(acceptResult < 0) {
264 populate_env(fcgx_req->envp, request->hvEnv);
267 for (i = 0; i < 3; ++i) {
268 request->io[i] = GvIOn(request->gv[i]);
269 if (!(i == 0 ? IoIFP(request->io[i])
270 : IoOFP(request->io[i]))) {
271 IoIFP(request->io[i]) = sftmp(0);
272 /*IoIFP(request->io[i]) = sfnew(NULL, NULL, SF_UNBOUND, 0,
273 SF_STRING | (i ? SF_WRITE : SF_READ));*/
275 IoOFP(request->io[i]) = IoIFP(request->io[i]);
276 request->sfcreated[i] = TRUE;
280 if (!request->svout) {
281 newSVrv(request->svout = newSV(0), "FCGI::Stream");
282 newSVrv(request->sverr = newSV(0), "FCGI::Stream");
283 newSVrv(request->svin = newSV(0), "FCGI::Stream");
285 sv_setiv(SvRV(request->svout), INT2PTR(IV, fcgx_req->out));
286 sv_setiv(SvRV(request->sverr), INT2PTR(IV, fcgx_req->err));
287 sv_setiv(SvRV(request->svin), INT2PTR(IV, fcgx_req->in));
290 request->accepted = TRUE;
296 FCGI_Finish(FCGP_Request* request)
304 if(!request->accepted) {
308 if (was_bound = request->bound) {
309 FCGI_UndoBinding(request);
312 for (i = 0; i < 3; ++i) {
313 if (request->sfcreated[i]) {
314 sfclose(IoIFP(request->io[i]));
315 IoIFP(request->io[i]) = IoOFP(request->io[i]) = Nullfp;
316 request->sfcreated[i] = FALSE;
321 FCGX_Finish_r(request->requestPtr);
323 FCGX_Free(request->requestPtr, 1);
324 request->accepted = FALSE;
328 FCGI_StartFilterData(FCGP_Request* request)
330 return request->requestPtr->in ?
331 FCGX_StartFilterData(request->requestPtr->in) : -1;
334 static FCGP_Request *
335 FCGI_Request(in, out, err, env, socket, flags)
343 FCGX_Request* fcgx_req;
346 Newz(551, fcgx_req, 1, FCGX_Request);
347 FCGX_InitRequest(fcgx_req, socket, flags);
348 Newz(551, req, 1, FCGP_Request);
349 req->requestPtr = fcgx_req;
363 FCGI_Release_Request(FCGP_Request *req)
365 SvREFCNT_dec(req->gv[0]);
366 SvREFCNT_dec(req->gv[1]);
367 SvREFCNT_dec(req->gv[2]);
368 SvREFCNT_dec(req->hvEnv);
370 Safefree(req->requestPtr);
377 #if defined(USE_LOCKING) && defined(USE_THREADS)
380 MUTEX_INIT(&accept_mutex);
386 typedef FCGX_Stream * FCGI__Stream;
387 typedef FCGP_Request * FCGI;
391 MODULE = FCGI PACKAGE = FCGI PREFIX = FCGI_
397 RequestX(in, out, err, env, socket, flags)
407 RETVAL = sv_setref_pv(newSV(0), "FCGI",
408 FCGI_Request(in, out, err, env, socket, flags));
414 OpenSocket(path, backlog)
420 RETVAL = FCGX_OpenSocket(path, backlog);
452 GetEnvironment(request)
458 RETVAL = request->hvEnv;
474 for (i = 0; i < 3; ++i)
475 PUSHs(sv_2mortal(newRV((SV *) request->gv[i])));
478 FCGI_IsFastCGI(request)
490 if (request->accepted && request->bound) {
491 FCGI_UndoBinding(request);
492 FCGX_Detach(request->requestPtr);
502 if (request->accepted && !request->bound) {
504 FCGX_Attach(request->requestPtr);
514 FCGX_ShutdownPending();
517 FCGI_StartFilterData(request)
528 FCGI_Release_Request(request);
532 MODULE = FCGI PACKAGE = FCGI::Stream
541 int n, sum = 0, ret = 0;
546 for (n = 1; n < items; ++n) {
548 if (DO_UTF8(ST(n)) && !sv_utf8_downgrade(ST(n), 1))
549 croak("Wide character in FCGI::Stream::PRINT");
551 str = (char *)SvPV(ST(n),len);
552 if ((ret = FCGX_PutStr(str, len, stream)) < 0)
558 if (sum == 0 && ret < 0)
562 if (SvTRUEx(perl_get_sv("|", FALSE)))
567 WRITE(stream, bufsv, len, ...)
579 offset = (items == 4) ? (int)SvIV(ST(3)) : 0;
581 if (DO_UTF8(bufsv) && !sv_utf8_downgrade(bufsv, 1))
582 croak("Wide character in FCGI::Stream::WRITE");
584 buf = SvPV(bufsv, blen);
585 if (offset < 0) offset += blen;
586 if (len > blen - offset)
588 if (offset < 0 || offset >= blen ||
589 (n = FCGX_PutStr(buf+offset, len, stream)) < 0)
590 ST(0) = &PL_sv_undef;
592 ST(0) = sv_newmortal();
597 READ(stream, bufsv, len, ...)
607 offset = (items == 4) ? (int)SvIV(ST(3)) : 0;
609 if (DO_UTF8(bufsv) && !sv_utf8_downgrade(bufsv, 1))
610 croak("Wide character in FCGI::Stream::READ");
613 sv_setpvn(bufsv, "", 0);
614 buf = SvGROW(bufsv, len+offset+1);
615 len = FCGX_GetStr(buf+offset, len, stream);
616 SvCUR_set(bufsv, len+offset);
617 *SvEND(bufsv) = '\0';
618 (void)SvPOK_only(bufsv);
633 if ((retval = FCGX_GetChar(stream)) != -1) {
634 ST(0) = sv_newmortal();
635 sv_setpvf(ST(0), "%c", retval);
636 } else ST(0) = &PL_sv_undef;
646 RETVAL = FCGX_FClose(stream) != -1;