add $(EXEEXT) to threaded
[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__
7fa2de73 15/* $Id: FCGI.XL,v 1.6 2001/09/20 12:00:24 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
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
92#if defined(USE_LOCKING) && defined(USE_THREADS)
93static perl_mutex accept_mutex;
94#endif
95
96typedef struct FCGP_Request {
97 int accepted;
98 int bound;
99 SV* svin;
100 SV* svout;
101 SV* sverr;
102 GV* gv[3];
103 HV* hvEnv;
104 FCGX_Request* requestPtr;
105#ifdef USE_SFIO
106 int sfcreated[3];
107 IO* io[3];
108#endif
109} FCGP_Request;
110
111static void FCGI_Finish(FCGP_Request* request);
112
9b60732b 113static void
0833402a 114FCGI_Flush(FCGP_Request* request)
115{
116 dTHX;
117
118 if(!request->bound) {
119 return;
9b60732b 120 }
0833402a 121#ifdef USE_SFIO
122 sfsync(IoOFP(GvIOp(request->gv[1])));
123 sfsync(IoOFP(GvIOp(request->gv[2])));
124#else
9c31872c 125 FCGX_FFlush(INT2PTR(FCGX_Stream *, SvIV((SV*) SvRV(request->svout))));
126 FCGX_FFlush(INT2PTR(FCGX_Stream *, SvIV((SV*) SvRV(request->sverr))));
0833402a 127#endif
128}
129
130static void
131FCGI_UndoBinding(FCGP_Request* request)
132{
133 dTHX;
134
135#ifdef USE_SFIO
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));
139#else
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
144 request->bound = FALSE;
145}
146
147static void
148FCGI_Bind(FCGP_Request* request)
149{
150 dTHX;
151
152#ifdef USE_SFIO
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));
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
165populate_env(envp, hv)
166char **envp;
167HV *hv;
168{
169 int i;
170 char *p, *p1;
171 SV *sv;
172 dTHX;
173
174 hv_clear(hv);
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 }
186}
187
188static int
189FCGI_IsFastCGI(FCGP_Request* request)
190{
191 static int isCGI = -1; /* -1: not checked; 0: FCGI; 1: CGI */
192
193 if (request->requestPtr->listen_sock == FCGI_LISTENSOCK_FILENO) {
194 if (isCGI == -1)
195 isCGI = FCGX_IsCGI();
196 return !isCGI;
197 }
198
199 /* A explicit socket is being used -> assume FastCGI */
200 return 1;
201}
202
203static int
204FCGI_Accept(FCGP_Request* request)
205{
206 dTHX;
207
208 if (!FCGI_IsFastCGI(request)) {
209 static int been_here = 0;
210
211 /*
212 * Not first call to FCGI_Accept and running as CGI means
213 * application is done.
214 */
215 if (been_here)
216 return EOF;
217
218 been_here = 1;
219 } else {
220#ifdef USE_SFIO
221 int i;
222#endif
223 FCGX_Request *fcgx_req = request->requestPtr;
224 int acceptResult;
225
226 FCGI_Finish(request);
227#if defined(USE_LOCKING) && defined(USE_THREADS)
228 MUTEX_LOCK(&accept_mutex);
229#endif
230 acceptResult = FCGX_Accept_r(fcgx_req);
231#if defined(USE_LOCKING) && defined(USE_THREADS)
232 MUTEX_UNLOCK(&accept_mutex);
233#endif
234 if(acceptResult < 0) {
235 return acceptResult;
236 }
237
238 populate_env(fcgx_req->envp, request->hvEnv);
239
240#ifdef USE_SFIO
241 for (i = 0; i < 3; ++i) {
242 request->io[i] = GvIOn(request->gv[i]);
243 if (!(i == 0 ? IoIFP(request->io[i])
244 : IoOFP(request->io[i]))) {
245 IoIFP(request->io[i]) = sftmp(0);
246 /*IoIFP(request->io[i]) = sfnew(NULL, NULL, SF_UNBOUND, 0,
247 SF_STRING | (i ? SF_WRITE : SF_READ));*/
248 if (i != 0)
249 IoOFP(request->io[i]) = IoIFP(request->io[i]);
250 request->sfcreated[i] = TRUE;
251 }
252 }
253#else
254 if (!request->svout) {
255 newSVrv(request->svout = newSV(0), "FCGI::Stream");
256 newSVrv(request->sverr = newSV(0), "FCGI::Stream");
257 newSVrv(request->svin = newSV(0), "FCGI::Stream");
258 }
9c31872c 259 sv_setiv(SvRV(request->svout), INT2PTR(IV, fcgx_req->out));
260 sv_setiv(SvRV(request->sverr), INT2PTR(IV, fcgx_req->err));
261 sv_setiv(SvRV(request->svin), INT2PTR(IV, fcgx_req->in));
0833402a 262#endif
263 FCGI_Bind(request);
264 request->accepted = TRUE;
265 }
266 return 0;
267}
268
269static void
270FCGI_Finish(FCGP_Request* request)
271{
272#ifdef USE_SFIO
273 int i;
274#endif
275 int was_bound;
276 dTHX;
277
278 if(!request->accepted) {
279 return;
280 }
281
282 if (was_bound = request->bound) {
283 FCGI_UndoBinding(request);
284 }
285#ifdef USE_SFIO
286 for (i = 0; i < 3; ++i) {
287 if (request->sfcreated[i]) {
288 sfclose(IoIFP(request->io[i]));
289 IoIFP(request->io[i]) = IoOFP(request->io[i]) = Nullfp;
290 request->sfcreated[i] = FALSE;
291 }
292 }
293#endif
294 if (was_bound)
295 FCGX_Finish_r(request->requestPtr);
296 else
bef7e0fc 297 FCGX_Free(request->requestPtr, 1);
0833402a 298 request->accepted = FALSE;
299}
300
301static int
302FCGI_StartFilterData(FCGP_Request* request)
303{
304 return request->requestPtr->in ?
305 FCGX_StartFilterData(request->requestPtr->in) : -1;
306}
307
308static FCGP_Request *
309FCGI_Request(in, out, err, env, socket, flags)
310 GV* in;
311 GV* out;
312 GV* err;
313 HV* env;
314 int socket;
315 int flags;
316{
317 FCGX_Request* fcgx_req;
318 FCGP_Request* req;
319
320 Newz(551, fcgx_req, 1, FCGX_Request);
321 FCGX_InitRequest(fcgx_req, socket, flags);
322 Newz(551, req, 1, FCGP_Request);
323 req->requestPtr = fcgx_req;
a6b22a6e 324 SvREFCNT_inc(in);
0833402a 325 req->gv[0] = in;
a6b22a6e 326 SvREFCNT_inc(out);
0833402a 327 req->gv[1] = out;
a6b22a6e 328 SvREFCNT_inc(err);
0833402a 329 req->gv[2] = err;
a6b22a6e 330 SvREFCNT_inc(env);
0833402a 331 req->hvEnv = env;
332
333 return req;
334}
335
336static void
337FCGI_Release_Request(FCGP_Request *req)
338{
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
349FCGI_Init()
350{
351#if defined(USE_LOCKING) && defined(USE_THREADS)
352 dTHX;
353
354 MUTEX_INIT(&accept_mutex);
355#endif
356
357 FCGX_Init();
358}
359
360typedef FCGX_Stream * FCGI__Stream;
361typedef FCGP_Request * FCGI;
362typedef GV* GLOBREF;
363typedef HV* HASHREF;
364
365MODULE = FCGI PACKAGE = FCGI PREFIX = FCGI_
366
367BOOT:
368 FCGI_Init();
369
370SV *
371RequestX(in, out, err, env, socket, flags)
372 GLOBREF in;
373 GLOBREF out;
374 GLOBREF err;
375 HASHREF env;
376 int socket;
377 int flags;
378
379 PROTOTYPE: ***$$$
380 CODE:
381 RETVAL = sv_setref_pv(newSV(0), "FCGI",
382 FCGI_Request(in, out, err, env, socket, flags));
383
384 OUTPUT:
385 RETVAL
386
387int
388OpenSocket(path, backlog)
389 char* path;
390 int backlog;
391
392 PROTOTYPE: $$
393 CODE:
394 RETVAL = FCGX_OpenSocket(path, backlog);
395 OUTPUT:
396 RETVAL
397
398void
399CloseSocket(socket)
400 int socket;
401
402 PROTOTYPE: $
403 CODE:
404 close(socket);
405
406int
407FCGI_Accept(request)
408
409 FCGI request;
410
411 PROTOTYPE: $
412
413void
414FCGI_Finish(request)
415 FCGI request;
416
417 PROTOTYPE: $
418
419void
420FCGI_Flush(request)
421 FCGI request;
422
423 PROTOTYPE: $
424
425HV *
426GetEnvironment(request)
427 FCGI request;
428
429 PROTOTYPE: $
430
431 CODE:
432 RETVAL = request->hvEnv;
433
434 OUTPUT:
435 RETVAL
436
437void
438GetHandles(request)
439 FCGI request;
440
441 PROTOTYPE: $
442
443 PREINIT:
444 int i;
445
446 PPCODE:
447 EXTEND(sp,3);
448 for (i = 0; i < 3; ++i)
449 PUSHs(sv_2mortal(newRV((SV *) request->gv[i])));
450
451int
452FCGI_IsFastCGI(request)
453 FCGI request;
454
455 PROTOTYPE: $
456
457void
458Detach(request)
0833402a 459 FCGI request;
460
461 PROTOTYPE: $
462
463 CODE:
464 if (request->accepted && request->bound)
465 FCGI_UndoBinding(request);
466
467void
468Attach(request)
0833402a 469 FCGI request;
470
471 PROTOTYPE: $
472
473 CODE:
474 if (request->accepted && !request->bound)
475 FCGI_Bind(request);
476
7fa2de73 477void
478LastCall(request)
479 FCGI request;
480
481 PROTOTYPE: $
482
483 CODE:
484 FCGX_ShutdownPending();
0833402a 485
486int
487FCGI_StartFilterData(request)
488
489 FCGI request;
490
491 PROTOTYPE: $
492
493void
494DESTROY(request)
495 FCGI request;
496
497 CODE:
498 FCGI_Release_Request(request);
499
500
501
502MODULE = FCGI PACKAGE = FCGI::Stream
503
504#ifndef USE_SFIO
505
506void
507PRINT(stream, ...)
508 FCGI::Stream stream;
509
510 PREINIT:
511 int n;
512
513 CODE:
514 for (n = 1; n < items; ++n) {
515 STRLEN len;
516 register char *tmps = (char *)SvPV(ST(n),len);
517 FCGX_PutStr(tmps, len, stream);
518 }
519 if (SvTRUEx(perl_get_sv("|", FALSE)))
520 FCGX_FFlush(stream);
521
522int
523WRITE(stream, bufsv, len, ...)
524 FCGI::Stream stream;
525 SV * bufsv;
526 int len;
527
528 PREINIT:
529 int offset;
530 char * buf;
531 STRLEN blen;
532 int n;
533
534 CODE:
535 offset = (items == 4) ? (int)SvIV(ST(3)) : 0;
536 buf = SvPV(bufsv, blen);
537 if (offset < 0) offset += blen;
538 if (len > blen - offset)
539 len = blen - offset;
540 if (offset < 0 || offset >= blen ||
541 (n = FCGX_PutStr(buf+offset, len, stream)) < 0)
542 ST(0) = &PL_sv_undef;
543 else {
544 ST(0) = sv_newmortal();
545 sv_setpvf(ST(0), "%c", n);
546 }
547
548int
549READ(stream, bufsv, len, ...)
550 FCGI::Stream stream;
551 SV * bufsv;
552 int len;
553
554 PREINIT:
555 int offset;
556 char * buf;
557
558 CODE:
559 offset = (items == 4) ? (int)SvIV(ST(3)) : 0;
560 if (! SvOK(bufsv))
561 sv_setpvn(bufsv, "", 0);
562 buf = SvGROW(bufsv, len+offset+1);
563 len = FCGX_GetStr(buf+offset, len, stream);
564 SvCUR_set(bufsv, len+offset);
565 *SvEND(bufsv) = '\0';
566 (void)SvPOK_only(bufsv);
567 SvSETMAGIC(bufsv);
568 RETVAL = len;
569
570 OUTPUT:
571 RETVAL
572
573SV *
574GETC(stream)
575 FCGI::Stream stream;
576
577 PREINIT:
578 int retval;
579
580 CODE:
581 if ((retval = FCGX_GetChar(stream)) != -1) {
582 ST(0) = sv_newmortal();
583 sv_setpvf(ST(0), "%c", retval);
584 } else ST(0) = &PL_sv_undef;
585
586bool
587CLOSE(stream)
588 FCGI::Stream stream;
589
590# ALIAS:
591# DESTROY = 1
592
593 CODE:
594 RETVAL = FCGX_FClose(stream) != -1;
595
596 OUTPUT:
597 RETVAL
598
599#endif