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