0.48 release
[catagits/fcgi2.git] / perl / FCGI.PL
1 use Config;
2
3 open OUT, ">FCGI.xs";
4
5 print "Generating FCGI.xs for Perl version $]\n";
6 #unless (exists $Config{apiversion} && $Config{apiversion} >= 5.005) 
7 unless ($] >= 5.005) {
8     for (qw(sv_undef diehook warnhook in_eval)) {
9         print OUT "#define PL_$_ $_\n" 
10     }
11 }
12 print OUT while <DATA>;
13 close OUT;
14 __END__
15 /* $Id: FCGI.PL,v 1.12 1999/08/27 13:28:47 skimo Exp $ */
16
17 #include "EXTERN.h"
18 #include "perl.h"
19 #include "XSUB.h"
20
21 #include "fcgi_config.h"
22 #include "fcgiapp.h"
23
24 #ifndef FALSE
25 #define FALSE (0)
26 #endif
27
28 #ifndef TRUE
29 #define TRUE  (1)
30 #endif
31
32 #ifndef dTHX
33 #define dTHX
34 #endif
35
36 #ifdef USE_SFIO
37 typedef struct
38 {
39     Sfdisc_t    disc;
40     FCGX_Stream *stream;
41 } FCGI_Disc;
42
43 static ssize_t
44 sffcgiread(f, buf, n, disc)
45 Sfio_t*         f;      /* stream involved */
46 Void_t*         buf;    /* buffer to read into */
47 size_t          n;      /* number of bytes to read */
48 Sfdisc_t*       disc;   /* discipline */
49 {
50     return FCGX_GetStr(buf, n, ((FCGI_Disc *)disc)->stream);
51 }
52
53 static ssize_t
54 sffcgiwrite(f, buf, n, disc)
55 Sfio_t*         f;      /* stream involved */
56 const Void_t*   buf;    /* buffer to read into */
57 size_t          n;      /* number of bytes to read */
58 Sfdisc_t*       disc;   /* discipline */
59 {
60     n = FCGX_PutStr(buf, n, ((FCGI_Disc *)disc)->stream);
61     FCGX_FFlush(((FCGI_Disc *)disc)->stream);
62     return n;
63 }
64
65 Sfdisc_t *
66 sfdcnewfcgi(stream)
67         FCGX_Stream *stream;
68 {
69     FCGI_Disc*  disc;
70
71     New(1000,disc,1,FCGI_Disc);
72     if (!disc) return (Sfdisc_t *)disc;
73
74     disc->disc.exceptf = (Sfexcept_f)NULL;
75     disc->disc.seekf = (Sfseek_f)NULL;
76     disc->disc.readf = sffcgiread;
77     disc->disc.writef = sffcgiwrite;
78     disc->stream = stream;
79     return (Sfdisc_t *)disc;
80 }
81
82 Sfdisc_t *
83 sfdcdelfcgi(disc)
84     Sfdisc_t*   disc;
85 {
86     Safefree(disc);
87     return 0;
88 }
89 #endif
90
91 static int isCGI = -1; /* -1: not checked; 0: FCGI; 1: FCGI */
92
93 #if defined(USE_LOCKING) && defined(USE_THREADS)
94 static perl_mutex   accept_mutex;
95 #endif
96
97 typedef struct FCGP_Request {
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 #endif
108 } FCGP_Request;
109
110 static int 
111 FCGI_Flush(FCGP_Request* request)
112 {
113     dTHX;
114
115     if(!request->bound) {
116         return;
117     }
118 #ifdef USE_SFIO
119     sfsync(IoOFP(GvIOp(request->gv[1])));
120     sfsync(IoOFP(GvIOp(request->gv[2])));
121 #else
122     FCGX_FFlush((FCGX_Stream *) SvIV((SV*) SvRV(request->svout)));
123     FCGX_FFlush((FCGX_Stream *) SvIV((SV*) SvRV(request->sverr)));
124 #endif
125 }
126
127 static void
128 FCGI_UndoBinding(FCGP_Request* request)
129 {
130 #ifdef USE_SFIO
131     IO *io[3];
132     int i;
133 #endif
134     dTHX;
135
136 #ifdef USE_SFIO
137     sfdcdelfcgi(sfdisc(IoIFP(io[0] = GvIOp(request->gv[0])), SF_POPDISC));
138     sfdcdelfcgi(sfdisc(IoOFP(io[1] = GvIOp(request->gv[1])), SF_POPDISC));
139     sfdcdelfcgi(sfdisc(IoOFP(io[2] = GvIOp(request->gv[2])), SF_POPDISC));
140     for (i = 0; i < 3; ++i) {
141         if (request->sfcreated[i]) {
142             sfclose(IoIFP(io[i]));
143             IoIFP(io[i]) = IoOFP(io[i]) = Nullfp;
144             request->sfcreated[i] = FALSE;
145         }
146     }
147 #else
148     FCGI_Flush(request);
149     sv_unmagic((SV *)request->gv[0], 'q');
150     sv_unmagic((SV *)request->gv[1], 'q');
151     sv_unmagic((SV *)request->gv[2], 'q');
152 #endif
153     FCGX_Finish_r(request->requestPtr);
154     request->bound = FALSE;
155 }
156
157 static void
158 populate_env(envp, hv)
159 char **envp;
160 HV *hv;
161 {
162     int i;
163     char *p, *p1;
164     SV   *sv;
165     dTHX;
166
167     hv_clear(hv);
168     for(i = 0; ; i++) {
169         if((p = envp[i]) == NULL) {
170             break;
171         }
172         p1 = strchr(p, '=');
173         assert(p1 != NULL);
174         sv = newSVpv(p1 + 1, 0);
175         /* call magic for this value ourselves */
176         hv_store(hv, p, p1 - p, sv, 0);
177         SvSETMAGIC(sv);
178     }
179 }
180
181 static int 
182 FCGI_Accept(FCGP_Request* request)
183 {
184     dTHX;
185
186     if(isCGI == -1) {
187         /*
188          * First call to FCGI_Accept.  Is application running
189          * as FastCGI or as CGI?
190          */
191         isCGI = FCGX_IsCGI();
192     } else if(isCGI) {
193         /*
194          * Not first call to FCGI_Accept and running as CGI means
195          * application is done.
196          */
197         return(EOF);
198     } 
199     if(!isCGI) {
200 #ifdef USE_SFIO
201         IO *io[3];
202         int i;
203 #endif
204         FCGX_Request *fcgx_req = request->requestPtr;
205         int acceptResult;
206
207         if(request->bound) {
208             FCGI_UndoBinding(request);
209         }
210 #if defined(USE_LOCKING) && defined(USE_THREADS)
211         MUTEX_LOCK(&accept_mutex);
212 #endif
213         acceptResult = FCGX_Accept_r(fcgx_req);
214 #if defined(USE_LOCKING) && defined(USE_THREADS)
215         MUTEX_UNLOCK(&accept_mutex);
216 #endif
217         if(acceptResult < 0) {
218             return acceptResult;
219         }
220
221         populate_env(fcgx_req->envp, request->hvEnv);
222
223 #ifdef USE_SFIO
224         for (i = 0; i < 3; ++i) {
225             io[i] = GvIOn(request->gv[i]);
226             if (!(i == 0 ? IoIFP(io[i]) : IoOFP(io[i]))) {
227                 IoIFP(io[i]) = sftmp(0);
228                 /*IoIFP(io[i]) = sfnew(NULL, NULL, SF_UNBOUND, 0, 
229                                      SF_STRING | (i ? SF_WRITE : SF_READ));*/
230                 if (i != 0) IoOFP(io[i]) = IoIFP(io[i]);
231                 request->sfcreated[i] = TRUE;
232             }
233         }
234         sfdisc(IoIFP(io[0]), sfdcnewfcgi(fcgx_req->in));
235         sfdisc(IoOFP(io[1]), sfdcnewfcgi(fcgx_req->out));
236         sfdisc(IoOFP(io[2]), sfdcnewfcgi(fcgx_req->err));
237 #else
238         if (!request->svout) {
239             newSVrv(request->svout = newSV(0), "FCGI::Stream");
240             newSVrv(request->sverr = newSV(0), "FCGI::Stream");
241             newSVrv(request->svin = newSV(0), "FCGI::Stream");
242         }
243         sv_magic((SV *)request->gv[1], request->svout, 'q', Nullch, 0);
244         sv_magic((SV *)request->gv[2], request->sverr, 'q', Nullch, 0);
245         sv_magic((SV *)request->gv[0], request->svin, 'q', Nullch, 0);
246         sv_setiv(SvRV(request->svout), (IV) fcgx_req->out);
247         sv_setiv(SvRV(request->sverr), (IV) fcgx_req->err);
248         sv_setiv(SvRV(request->svin), (IV) fcgx_req->in);
249 #endif
250         request->bound = TRUE;
251     }
252     return 0;
253 }
254
255 static void 
256 FCGI_Finish(FCGP_Request* request)
257 {
258     dTHX;
259
260     if(!request->bound) {
261         return;
262     }
263     FCGI_UndoBinding(request);
264 }
265
266 static int 
267 FCGI_StartFilterData(FCGP_Request* request)
268 {
269     return request->requestPtr->in ? 
270             FCGX_StartFilterData(request->requestPtr->in) : -1;
271 }
272
273 static FCGP_Request *
274 FCGI_Request(in, out, err, env, socket, flags)
275     GV*     in;
276     GV*     out;
277     GV*     err;
278     HV*     env;
279     int     socket;
280     int     flags;
281 {
282     FCGX_Request* fcgx_req;
283     FCGP_Request* req;
284
285     Newz(551, fcgx_req, 1, FCGX_Request);
286     FCGX_InitRequest(fcgx_req, socket, flags);
287     Newz(551, req, 1, FCGP_Request);
288     req->requestPtr = fcgx_req;
289     req->gv[0] = in;
290     req->gv[1] = out;
291     req->gv[2] = err;
292     req->hvEnv = env;
293
294     return req;
295 }
296
297 static void
298 FCGI_Release_Request(FCGP_Request *req)
299 {
300     FCGI_Finish(req);
301     Safefree(req->requestPtr);
302     Safefree(req);
303 }
304
305 static void
306 FCGI_Init()
307 {
308 #if defined(USE_LOCKING) && defined(USE_THREADS)
309     dTHX;
310
311     MUTEX_INIT(&accept_mutex);
312 #endif
313 }
314
315 typedef FCGX_Stream *   FCGI__Stream;
316 typedef FCGP_Request *  FCGI;
317 typedef GV*             GLOBREF;
318 typedef HV*             HASHREF;
319
320 MODULE = FCGI           PACKAGE = FCGI
321
322 BOOT:
323     FCGI_Init();
324
325 SV *
326 RequestX(in, out, err, env, socket, flags)
327     GLOBREF in;
328     GLOBREF out;
329     GLOBREF err;
330     HASHREF env;
331     int     socket;
332     int     flags;
333
334     PROTOTYPE: ***$$$
335     CODE:
336     RETVAL = sv_setref_pv(newSV(0), "FCGI", 
337                 FCGI_Request(in, out, err, env, socket, flags));
338
339     OUTPUT:
340     RETVAL
341
342 int
343 OpenSocket(path, backlog)
344     char* path;
345     int backlog;
346
347     PROTOTYPE: $$
348     CODE:
349     RETVAL = FCGX_OpenSocket(path, backlog);
350     OUTPUT:
351     RETVAL
352
353 void
354 CloseSocket(socket)
355     int socket;
356
357     PROTOTYPE: $
358     CODE:
359     close(socket);
360
361 int
362 Accept(request)
363
364     FCGI    request;
365
366     PROTOTYPE: $
367
368     CODE:
369     RETVAL = FCGI_Accept(request);
370
371     OUTPUT:
372     RETVAL
373
374
375 void
376 Finish(request)
377
378     FCGI    request;
379
380     PROTOTYPE: $
381
382     CODE:
383     {
384         /*
385          * Finish the request.
386          */
387         FCGI_Finish(request);
388     }
389
390
391 void
392 Flush(request)
393
394     FCGI    request;
395
396     PROTOTYPE: $
397
398     CODE:
399     FCGI_Flush(request);
400
401
402 int
403 StartFilterData(request)
404
405     FCGI    request;
406
407     PROTOTYPE: $
408
409     CODE:
410     RETVAL = FCGI_StartFilterData(request);
411
412     OUTPUT:
413     RETVAL
414
415 void
416 DESTROY(request)
417     FCGI    request;
418
419     CODE:
420     FCGI_Release_Request(request);
421
422
423
424 MODULE = FCGI           PACKAGE = FCGI::Stream
425
426 #ifndef USE_SFIO
427
428 void
429 PRINT(stream, ...)
430         FCGI::Stream    stream;
431
432         PREINIT:
433         int     n;
434
435         CODE:
436         for (n = 1; n < items; ++n) {
437             STRLEN len;
438             register char *tmps = (char *)SvPV(ST(n),len);
439             FCGX_PutStr(tmps, len, stream);
440         }
441         if (SvTRUEx(perl_get_sv("|", FALSE))) 
442             FCGX_FFlush(stream);
443
444 int
445 WRITE(stream, bufsv, len, ...)
446         FCGI::Stream    stream;
447         SV *    bufsv;
448         int     len;
449
450         PREINIT:
451         int     offset;
452         char *  buf;
453         STRLEN  blen;
454         int     n;
455
456         CODE:
457         offset = (items == 4) ? (int)SvIV(ST(3)) : 0;
458         buf = SvPV(bufsv, blen);
459         if (offset < 0) offset += blen;
460         if (len > blen - offset)
461             len = blen - offset;
462         if (offset < 0 || offset >= blen ||
463                 (n = FCGX_PutStr(buf+offset, len, stream)) < 0) 
464             ST(0) = &PL_sv_undef;
465         else {
466             ST(0) = sv_newmortal();
467             sv_setpvf(ST(0), "%c", n);
468         }
469
470 int
471 READ(stream, bufsv, len, ...)
472         FCGI::Stream    stream;
473         SV *    bufsv;
474         int     len;
475
476         PREINIT:
477         int     offset;
478         char *  buf;
479
480         CODE:
481         offset = (items == 4) ? (int)SvIV(ST(3)) : 0;
482         if (! SvOK(bufsv))
483             sv_setpvn(bufsv, "", 0);
484         buf = SvGROW(bufsv, len+offset+1);
485         len = FCGX_GetStr(buf+offset, len, stream);
486         SvCUR_set(bufsv, len+offset);
487         *SvEND(bufsv) = '\0';
488         (void)SvPOK_only(bufsv);
489         SvSETMAGIC(bufsv);
490         RETVAL = len;
491
492         OUTPUT:
493         RETVAL
494
495 SV *
496 GETC(stream)
497         FCGI::Stream    stream;
498
499         PREINIT:
500         int     retval;
501
502         CODE:
503         if ((retval = FCGX_GetChar(stream)) != -1) {
504             ST(0) = sv_newmortal();
505             sv_setpvf(ST(0), "%c", retval);
506         } else ST(0) = &PL_sv_undef;
507
508 bool
509 CLOSE(stream)
510         FCGI::Stream    stream;
511
512         ALIAS:
513         DESTROY = 1
514
515         CODE:
516         RETVAL = FCGX_FClose(stream) != -1;
517
518         OUTPUT:
519         RETVAL
520
521 #endif