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