GetHandle and GetEnvironment
[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__
9915cd6d 15/* $Id: FCGI.PL,v 1.17 2000/11/01 14:27:49 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
37a69de1 153 sfdisc(IoIFP(request->io[0]), sfdcnewfcgi(request->requestPtr->in));
154 sfdisc(IoOFP(request->io[1]), sfdcnewfcgi(request->requestPtr->out));
155 sfdisc(IoOFP(request->io[2]), sfdcnewfcgi(request->requestPtr->err));
5baeeca7 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{
e40fb02c 191 static int isCGI = -1; /* -1: not checked; 0: FCGI; 1: CGI */
5baeeca7 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) {
37a69de1 213#ifdef USE_SFIO
214 int i;
215#endif
6ff77aff 216 FCGX_Request *fcgx_req = request->requestPtr;
b716743a 217 int acceptResult;
218
5baeeca7 219 FCGI_Finish(request);
b716743a 220#if defined(USE_LOCKING) && defined(USE_THREADS)
221 MUTEX_LOCK(&accept_mutex);
222#endif
6ff77aff 223 acceptResult = FCGX_Accept_r(fcgx_req);
b716743a 224#if defined(USE_LOCKING) && defined(USE_THREADS)
225 MUTEX_UNLOCK(&accept_mutex);
226#endif
1b64d24d 227 if(acceptResult < 0) {
228 return acceptResult;
229 }
d8cc97fb 230
6ff77aff 231 populate_env(fcgx_req->envp, request->hvEnv);
d8cc97fb 232
1b64d24d 233#ifdef USE_SFIO
2c38ecd7 234 for (i = 0; i < 3; ++i) {
5baeeca7 235 request->io[i] = GvIOn(request->gv[i]);
236 if (!(i == 0 ? IoIFP(request->io[i])
237 : IoOFP(request->io[i]))) {
238 IoIFP(request->io[i]) = sftmp(0);
239 /*IoIFP(request->io[i]) = sfnew(NULL, NULL, SF_UNBOUND, 0,
2c38ecd7 240 SF_STRING | (i ? SF_WRITE : SF_READ));*/
5baeeca7 241 if (i != 0)
242 IoOFP(request->io[i]) = IoIFP(request->io[i]);
2c38ecd7 243 request->sfcreated[i] = TRUE;
244 }
245 }
1b64d24d 246#else
90a18d65 247 if (!request->svout) {
eede4b76 248 newSVrv(request->svout = newSV(0), "FCGI::Stream");
eede4b76 249 newSVrv(request->sverr = newSV(0), "FCGI::Stream");
eede4b76 250 newSVrv(request->svin = newSV(0), "FCGI::Stream");
1b64d24d 251 }
6ff77aff 252 sv_setiv(SvRV(request->svout), (IV) fcgx_req->out);
253 sv_setiv(SvRV(request->sverr), (IV) fcgx_req->err);
254 sv_setiv(SvRV(request->svin), (IV) fcgx_req->in);
1b64d24d 255#endif
5baeeca7 256 FCGI_Bind(request);
257 request->accepted = TRUE;
1b64d24d 258 }
1b64d24d 259 return 0;
260}
261
262static void
90a18d65 263FCGI_Finish(FCGP_Request* request)
1b64d24d 264{
37a69de1 265#ifdef USE_SFIO
266 int i;
267#endif
b716743a 268 dTHX;
269
5baeeca7 270 if(!request->accepted) {
1b64d24d 271 return;
272 }
5baeeca7 273
274 if (request->bound) {
275 FCGI_UndoBinding(request);
276 }
277#ifdef USE_SFIO
278 for (i = 0; i < 3; ++i) {
279 if (request->sfcreated[i]) {
280 sfclose(IoIFP(request->io[i]));
281 IoIFP(request->io[i]) = IoOFP(request->io[i]) = Nullfp;
282 request->sfcreated[i] = FALSE;
283 }
284 }
285#endif
286 FCGX_Finish_r(request->requestPtr);
287 request->accepted = FALSE;
1b64d24d 288}
289
290static int
90a18d65 291FCGI_StartFilterData(FCGP_Request* request)
292{
6ff77aff 293 return request->requestPtr->in ?
294 FCGX_StartFilterData(request->requestPtr->in) : -1;
90a18d65 295}
296
297static FCGP_Request *
6ff77aff 298FCGI_Request(in, out, err, env, socket, flags)
299 GV* in;
300 GV* out;
301 GV* err;
302 HV* env;
303 int socket;
304 int flags;
1b64d24d 305{
90a18d65 306 FCGX_Request* fcgx_req;
307 FCGP_Request* req;
308
309 Newz(551, fcgx_req, 1, FCGX_Request);
6ff77aff 310 FCGX_InitRequest(fcgx_req, socket, flags);
90a18d65 311 Newz(551, req, 1, FCGP_Request);
312 req->requestPtr = fcgx_req;
6ff77aff 313 req->gv[0] = in;
314 req->gv[1] = out;
315 req->gv[2] = err;
316 req->hvEnv = env;
90a18d65 317
318 return req;
1b64d24d 319}
320
321static void
90a18d65 322FCGI_Release_Request(FCGP_Request *req)
1b64d24d 323{
6ff77aff 324 FCGI_Finish(req);
90a18d65 325 Safefree(req->requestPtr);
326 Safefree(req);
1b64d24d 327}
328
34bfd355 329static void
b716743a 330FCGI_Init()
34bfd355 331{
b716743a 332#if defined(USE_LOCKING) && defined(USE_THREADS)
333 dTHX;
34bfd355 334
b716743a 335 MUTEX_INIT(&accept_mutex);
336#endif
e40fb02c 337
338 FCGX_Init();
34bfd355 339}
340
eede4b76 341typedef FCGX_Stream * FCGI__Stream;
342typedef FCGP_Request * FCGI;
d8cc97fb 343typedef GV* GLOBREF;
344typedef HV* HASHREF;
1b64d24d 345
346MODULE = FCGI PACKAGE = FCGI
347
b716743a 348BOOT:
349 FCGI_Init();
eede4b76 350
351SV *
6ff77aff 352RequestX(in, out, err, env, socket, flags)
353 GLOBREF in;
354 GLOBREF out;
355 GLOBREF err;
356 HASHREF env;
357 int socket;
358 int flags;
eede4b76 359
6ff77aff 360 PROTOTYPE: ***$$$
eede4b76 361 CODE:
6ff77aff 362 RETVAL = sv_setref_pv(newSV(0), "FCGI",
363 FCGI_Request(in, out, err, env, socket, flags));
eede4b76 364
365 OUTPUT:
366 RETVAL
367
6b312a77 368int
369OpenSocket(path, backlog)
370 char* path;
371 int backlog;
372
373 PROTOTYPE: $$
374 CODE:
375 RETVAL = FCGX_OpenSocket(path, backlog);
376 OUTPUT:
377 RETVAL
378
379void
380CloseSocket(socket)
381 int socket;
382
383 PROTOTYPE: $
384 CODE:
385 close(socket);
eede4b76 386
387int
6ff77aff 388Accept(request)
eede4b76 389
d8cc97fb 390 FCGI request;
eede4b76 391
6ff77aff 392 PROTOTYPE: $
eede4b76 393
394 CODE:
d8cc97fb 395 RETVAL = FCGI_Accept(request);
eede4b76 396
eede4b76 397 OUTPUT:
398 RETVAL
399
400
401void
d8cc97fb 402Finish(request)
eede4b76 403
d8cc97fb 404 FCGI request;
eede4b76 405
d8cc97fb 406 PROTOTYPE: $
eede4b76 407
408 CODE:
eede4b76 409 {
410 /*
eede4b76 411 * Finish the request.
412 */
413 FCGI_Finish(request);
414 }
415
416
417void
d8cc97fb 418Flush(request)
eede4b76 419
d8cc97fb 420 FCGI request;
eede4b76 421
d8cc97fb 422 PROTOTYPE: $
eede4b76 423
424 CODE:
eede4b76 425 FCGI_Flush(request);
426
9915cd6d 427HV *
428GetEnvironment(request)
429 FCGI request;
430
431 PROTOTYPE: $
432
433 CODE:
434 RETVAL = request->hvEnv;
435
436 OUTPUT:
437 RETVAL
438
439void
440GetHandles(request)
441 FCGI request;
442
443 PROTOTYPE: $
444
445 PREINIT:
446 int i;
447
448 PPCODE:
449 EXTEND(sp,3);
450 for (i = 0; i < 3; ++i)
451 PUSHs(sv_2mortal(newRV(request->gv[i])));
452
5baeeca7 453void
454Detach(request)
455
456 FCGI request;
457
458 PROTOTYPE: $
459
460 CODE:
461 if (request->accepted && request->bound)
462 FCGI_UndoBinding(request);
463
464void
465Attach(request)
466
467 FCGI request;
468
469 PROTOTYPE: $
470
471 CODE:
472 if (request->accepted && !request->bound)
473 FCGI_Bind(request);
474
eede4b76 475
476int
d8cc97fb 477StartFilterData(request)
eede4b76 478
d8cc97fb 479 FCGI request;
eede4b76 480
d8cc97fb 481 PROTOTYPE: $
eede4b76 482
483 CODE:
eede4b76 484 RETVAL = FCGI_StartFilterData(request);
485
486 OUTPUT:
487 RETVAL
488
eede4b76 489void
490DESTROY(request)
491 FCGI request;
492
493 CODE:
494 FCGI_Release_Request(request);
495
496
497
498MODULE = FCGI PACKAGE = FCGI::Stream
90a18d65 499
1b64d24d 500#ifndef USE_SFIO
1b64d24d 501
502void
503PRINT(stream, ...)
eede4b76 504 FCGI::Stream stream;
1b64d24d 505
506 PREINIT:
507 int n;
508
509 CODE:
510 for (n = 1; n < items; ++n) {
511 STRLEN len;
512 register char *tmps = (char *)SvPV(ST(n),len);
513 FCGX_PutStr(tmps, len, stream);
514 }
515 if (SvTRUEx(perl_get_sv("|", FALSE)))
516 FCGX_FFlush(stream);
517
518int
519WRITE(stream, bufsv, len, ...)
eede4b76 520 FCGI::Stream stream;
1b64d24d 521 SV * bufsv;
522 int len;
523
524 PREINIT:
525 int offset;
526 char * buf;
527 STRLEN blen;
528 int n;
529
530 CODE:
531 offset = (items == 4) ? (int)SvIV(ST(3)) : 0;
532 buf = SvPV(bufsv, blen);
533 if (offset < 0) offset += blen;
534 if (len > blen - offset)
535 len = blen - offset;
536 if (offset < 0 || offset >= blen ||
537 (n = FCGX_PutStr(buf+offset, len, stream)) < 0)
538 ST(0) = &PL_sv_undef;
539 else {
540 ST(0) = sv_newmortal();
541 sv_setpvf(ST(0), "%c", n);
542 }
543
544int
545READ(stream, bufsv, len, ...)
eede4b76 546 FCGI::Stream stream;
1b64d24d 547 SV * bufsv;
548 int len;
549
550 PREINIT:
551 int offset;
552 char * buf;
553
554 CODE:
555 offset = (items == 4) ? (int)SvIV(ST(3)) : 0;
556 if (! SvOK(bufsv))
557 sv_setpvn(bufsv, "", 0);
558 buf = SvGROW(bufsv, len+offset+1);
559 len = FCGX_GetStr(buf+offset, len, stream);
560 SvCUR_set(bufsv, len+offset);
561 *SvEND(bufsv) = '\0';
562 (void)SvPOK_only(bufsv);
563 SvSETMAGIC(bufsv);
564 RETVAL = len;
565
566 OUTPUT:
567 RETVAL
568
569SV *
570GETC(stream)
eede4b76 571 FCGI::Stream stream;
1b64d24d 572
573 PREINIT:
574 int retval;
575
576 CODE:
577 if ((retval = FCGX_GetChar(stream)) != -1) {
578 ST(0) = sv_newmortal();
579 sv_setpvf(ST(0), "%c", retval);
580 } else ST(0) = &PL_sv_undef;
581
582bool
583CLOSE(stream)
eede4b76 584 FCGI::Stream stream;
1b64d24d 585
5baeeca7 586# ALIAS:
587# DESTROY = 1
1b64d24d 588
589 CODE:
590 RETVAL = FCGX_FClose(stream) != -1;
591
592 OUTPUT:
593 RETVAL
594
595#endif