Minor fixups
[catagits/fcgi2.git] / perl / FCGI.PL
CommitLineData
1b64d24d 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__
794c66be 15/* $Id: FCGI.PL,v 1.14 2000/04/21 18:10:53 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
38typedef struct
39{
40 Sfdisc_t disc;
41 FCGX_Stream *stream;
42} FCGI_Disc;
43
44static ssize_t
45sffcgiread(f, buf, n, disc)
46Sfio_t* f; /* stream involved */
47Void_t* buf; /* buffer to read into */
48size_t n; /* number of bytes to read */
49Sfdisc_t* disc; /* discipline */
50{
51 return FCGX_GetStr(buf, n, ((FCGI_Disc *)disc)->stream);
52}
53
54static ssize_t
55sffcgiwrite(f, buf, n, disc)
56Sfio_t* f; /* stream involved */
57const Void_t* buf; /* buffer to read into */
58size_t n; /* number of bytes to read */
59Sfdisc_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
66Sfdisc_t *
67sfdcnewfcgi(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
83Sfdisc_t *
84sfdcdelfcgi(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)
93static perl_mutex accept_mutex;
94#endif
95
90a18d65 96typedef 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 111static void FCGI_Finish(FCGP_Request* request);
112
1b64d24d 113static int
90a18d65 114FCGI_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 130static void
131FCGI_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
147static void
5baeeca7 148FCGI_Bind(FCGP_Request* request)
149{
150 dTHX;
151
152#ifdef USE_SFIO
153 sfdisc(IoIFP(request->io[0]), sfdcnewfcgi(fcgx_req->in));
154 sfdisc(IoOFP(request->io[1]), sfdcnewfcgi(fcgx_req->out));
155 sfdisc(IoOFP(request->io[2]), sfdcnewfcgi(fcgx_req->err));
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
164static void
b716743a 165populate_env(envp, hv)
166char **envp;
167HV *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
1b64d24d 188static int
cebfd7c4 189FCGI_Accept(FCGP_Request* request)
1b64d24d 190{
5baeeca7 191 static int isCGI = -1; /* -1: not checked; 0: FCGI; 1: FCGI */
192
193 int req_isCGI =
194 request->requestPtr->listen_sock == FCGI_LISTENSOCK_FILENO ?
195 isCGI : 0;
196
794c66be 197 dTHX;
198
5baeeca7 199 if(req_isCGI == -1) {
1b64d24d 200 /*
201 * First call to FCGI_Accept. Is application running
202 * as FastCGI or as CGI?
203 */
5baeeca7 204 req_isCGI = isCGI = FCGX_IsCGI();
205 } else if(req_isCGI) {
1b64d24d 206 /*
207 * Not first call to FCGI_Accept and running as CGI means
208 * application is done.
209 */
210 return(EOF);
eede4b76 211 }
5baeeca7 212 if(!req_isCGI) {
6ff77aff 213 FCGX_Request *fcgx_req = request->requestPtr;
b716743a 214 int acceptResult;
215
5baeeca7 216 FCGI_Finish(request);
b716743a 217#if defined(USE_LOCKING) && defined(USE_THREADS)
218 MUTEX_LOCK(&accept_mutex);
219#endif
6ff77aff 220 acceptResult = FCGX_Accept_r(fcgx_req);
b716743a 221#if defined(USE_LOCKING) && defined(USE_THREADS)
222 MUTEX_UNLOCK(&accept_mutex);
223#endif
1b64d24d 224 if(acceptResult < 0) {
225 return acceptResult;
226 }
d8cc97fb 227
6ff77aff 228 populate_env(fcgx_req->envp, request->hvEnv);
d8cc97fb 229
1b64d24d 230#ifdef USE_SFIO
2c38ecd7 231 for (i = 0; i < 3; ++i) {
5baeeca7 232 request->io[i] = GvIOn(request->gv[i]);
233 if (!(i == 0 ? IoIFP(request->io[i])
234 : IoOFP(request->io[i]))) {
235 IoIFP(request->io[i]) = sftmp(0);
236 /*IoIFP(request->io[i]) = sfnew(NULL, NULL, SF_UNBOUND, 0,
2c38ecd7 237 SF_STRING | (i ? SF_WRITE : SF_READ));*/
5baeeca7 238 if (i != 0)
239 IoOFP(request->io[i]) = IoIFP(request->io[i]);
2c38ecd7 240 request->sfcreated[i] = TRUE;
241 }
242 }
1b64d24d 243#else
90a18d65 244 if (!request->svout) {
eede4b76 245 newSVrv(request->svout = newSV(0), "FCGI::Stream");
eede4b76 246 newSVrv(request->sverr = newSV(0), "FCGI::Stream");
eede4b76 247 newSVrv(request->svin = newSV(0), "FCGI::Stream");
1b64d24d 248 }
6ff77aff 249 sv_setiv(SvRV(request->svout), (IV) fcgx_req->out);
250 sv_setiv(SvRV(request->sverr), (IV) fcgx_req->err);
251 sv_setiv(SvRV(request->svin), (IV) fcgx_req->in);
1b64d24d 252#endif
5baeeca7 253 FCGI_Bind(request);
254 request->accepted = TRUE;
1b64d24d 255 }
1b64d24d 256 return 0;
257}
258
259static void
90a18d65 260FCGI_Finish(FCGP_Request* request)
1b64d24d 261{
b716743a 262 dTHX;
263
5baeeca7 264 if(!request->accepted) {
1b64d24d 265 return;
266 }
5baeeca7 267
268 if (request->bound) {
269 FCGI_UndoBinding(request);
270 }
271#ifdef USE_SFIO
272 for (i = 0; i < 3; ++i) {
273 if (request->sfcreated[i]) {
274 sfclose(IoIFP(request->io[i]));
275 IoIFP(request->io[i]) = IoOFP(request->io[i]) = Nullfp;
276 request->sfcreated[i] = FALSE;
277 }
278 }
279#endif
280 FCGX_Finish_r(request->requestPtr);
281 request->accepted = FALSE;
1b64d24d 282}
283
284static int
90a18d65 285FCGI_StartFilterData(FCGP_Request* request)
286{
6ff77aff 287 return request->requestPtr->in ?
288 FCGX_StartFilterData(request->requestPtr->in) : -1;
90a18d65 289}
290
291static FCGP_Request *
6ff77aff 292FCGI_Request(in, out, err, env, socket, flags)
293 GV* in;
294 GV* out;
295 GV* err;
296 HV* env;
297 int socket;
298 int flags;
1b64d24d 299{
90a18d65 300 FCGX_Request* fcgx_req;
301 FCGP_Request* req;
302
303 Newz(551, fcgx_req, 1, FCGX_Request);
6ff77aff 304 FCGX_InitRequest(fcgx_req, socket, flags);
90a18d65 305 Newz(551, req, 1, FCGP_Request);
306 req->requestPtr = fcgx_req;
6ff77aff 307 req->gv[0] = in;
308 req->gv[1] = out;
309 req->gv[2] = err;
310 req->hvEnv = env;
90a18d65 311
312 return req;
1b64d24d 313}
314
315static void
90a18d65 316FCGI_Release_Request(FCGP_Request *req)
1b64d24d 317{
6ff77aff 318 FCGI_Finish(req);
90a18d65 319 Safefree(req->requestPtr);
320 Safefree(req);
1b64d24d 321}
322
34bfd355 323static void
b716743a 324FCGI_Init()
34bfd355 325{
b716743a 326#if defined(USE_LOCKING) && defined(USE_THREADS)
327 dTHX;
34bfd355 328
b716743a 329 MUTEX_INIT(&accept_mutex);
330#endif
34bfd355 331}
332
eede4b76 333typedef FCGX_Stream * FCGI__Stream;
334typedef FCGP_Request * FCGI;
d8cc97fb 335typedef GV* GLOBREF;
336typedef HV* HASHREF;
1b64d24d 337
338MODULE = FCGI PACKAGE = FCGI
339
b716743a 340BOOT:
341 FCGI_Init();
eede4b76 342
343SV *
6ff77aff 344RequestX(in, out, err, env, socket, flags)
345 GLOBREF in;
346 GLOBREF out;
347 GLOBREF err;
348 HASHREF env;
349 int socket;
350 int flags;
eede4b76 351
6ff77aff 352 PROTOTYPE: ***$$$
eede4b76 353 CODE:
6ff77aff 354 RETVAL = sv_setref_pv(newSV(0), "FCGI",
355 FCGI_Request(in, out, err, env, socket, flags));
eede4b76 356
357 OUTPUT:
358 RETVAL
359
6b312a77 360int
361OpenSocket(path, backlog)
362 char* path;
363 int backlog;
364
365 PROTOTYPE: $$
366 CODE:
367 RETVAL = FCGX_OpenSocket(path, backlog);
368 OUTPUT:
369 RETVAL
370
371void
372CloseSocket(socket)
373 int socket;
374
375 PROTOTYPE: $
376 CODE:
377 close(socket);
eede4b76 378
379int
6ff77aff 380Accept(request)
eede4b76 381
d8cc97fb 382 FCGI request;
eede4b76 383
6ff77aff 384 PROTOTYPE: $
eede4b76 385
386 CODE:
d8cc97fb 387 RETVAL = FCGI_Accept(request);
eede4b76 388
eede4b76 389 OUTPUT:
390 RETVAL
391
392
393void
d8cc97fb 394Finish(request)
eede4b76 395
d8cc97fb 396 FCGI request;
eede4b76 397
d8cc97fb 398 PROTOTYPE: $
eede4b76 399
400 CODE:
eede4b76 401 {
402 /*
eede4b76 403 * Finish the request.
404 */
405 FCGI_Finish(request);
406 }
407
408
409void
d8cc97fb 410Flush(request)
eede4b76 411
d8cc97fb 412 FCGI request;
eede4b76 413
d8cc97fb 414 PROTOTYPE: $
eede4b76 415
416 CODE:
eede4b76 417 FCGI_Flush(request);
418
5baeeca7 419void
420Detach(request)
421
422 FCGI request;
423
424 PROTOTYPE: $
425
426 CODE:
427 if (request->accepted && request->bound)
428 FCGI_UndoBinding(request);
429
430void
431Attach(request)
432
433 FCGI request;
434
435 PROTOTYPE: $
436
437 CODE:
438 if (request->accepted && !request->bound)
439 FCGI_Bind(request);
440
eede4b76 441
442int
d8cc97fb 443StartFilterData(request)
eede4b76 444
d8cc97fb 445 FCGI request;
eede4b76 446
d8cc97fb 447 PROTOTYPE: $
eede4b76 448
449 CODE:
eede4b76 450 RETVAL = FCGI_StartFilterData(request);
451
452 OUTPUT:
453 RETVAL
454
eede4b76 455void
456DESTROY(request)
457 FCGI request;
458
459 CODE:
460 FCGI_Release_Request(request);
461
462
463
464MODULE = FCGI PACKAGE = FCGI::Stream
90a18d65 465
1b64d24d 466#ifndef USE_SFIO
1b64d24d 467
468void
469PRINT(stream, ...)
eede4b76 470 FCGI::Stream stream;
1b64d24d 471
472 PREINIT:
473 int n;
474
475 CODE:
476 for (n = 1; n < items; ++n) {
477 STRLEN len;
478 register char *tmps = (char *)SvPV(ST(n),len);
479 FCGX_PutStr(tmps, len, stream);
480 }
481 if (SvTRUEx(perl_get_sv("|", FALSE)))
482 FCGX_FFlush(stream);
483
484int
485WRITE(stream, bufsv, len, ...)
eede4b76 486 FCGI::Stream stream;
1b64d24d 487 SV * bufsv;
488 int len;
489
490 PREINIT:
491 int offset;
492 char * buf;
493 STRLEN blen;
494 int n;
495
496 CODE:
497 offset = (items == 4) ? (int)SvIV(ST(3)) : 0;
498 buf = SvPV(bufsv, blen);
499 if (offset < 0) offset += blen;
500 if (len > blen - offset)
501 len = blen - offset;
502 if (offset < 0 || offset >= blen ||
503 (n = FCGX_PutStr(buf+offset, len, stream)) < 0)
504 ST(0) = &PL_sv_undef;
505 else {
506 ST(0) = sv_newmortal();
507 sv_setpvf(ST(0), "%c", n);
508 }
509
510int
511READ(stream, bufsv, len, ...)
eede4b76 512 FCGI::Stream stream;
1b64d24d 513 SV * bufsv;
514 int len;
515
516 PREINIT:
517 int offset;
518 char * buf;
519
520 CODE:
521 offset = (items == 4) ? (int)SvIV(ST(3)) : 0;
522 if (! SvOK(bufsv))
523 sv_setpvn(bufsv, "", 0);
524 buf = SvGROW(bufsv, len+offset+1);
525 len = FCGX_GetStr(buf+offset, len, stream);
526 SvCUR_set(bufsv, len+offset);
527 *SvEND(bufsv) = '\0';
528 (void)SvPOK_only(bufsv);
529 SvSETMAGIC(bufsv);
530 RETVAL = len;
531
532 OUTPUT:
533 RETVAL
534
535SV *
536GETC(stream)
eede4b76 537 FCGI::Stream stream;
1b64d24d 538
539 PREINIT:
540 int retval;
541
542 CODE:
543 if ((retval = FCGX_GetChar(stream)) != -1) {
544 ST(0) = sv_newmortal();
545 sv_setpvf(ST(0), "%c", retval);
546 } else ST(0) = &PL_sv_undef;
547
548bool
549CLOSE(stream)
eede4b76 550 FCGI::Stream stream;
1b64d24d 551
5baeeca7 552# ALIAS:
553# DESTROY = 1
1b64d24d 554
555 CODE:
556 RETVAL = FCGX_FClose(stream) != -1;
557
558 OUTPUT:
559 RETVAL
560
561#endif