remove bloody CRs and fix bufsize initialization
[catagits/fcgi2.git] / perl / FCGI.XL
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.XL,v 1.7 2001/10/11 19:36:04 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 #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 #ifndef INT2PTR
38 #define INT2PTR(a,b) ((a) (b))
39 #endif
40
41 #ifdef USE_SFIO
42 typedef struct
43 {
44     Sfdisc_t    disc;
45     FCGX_Stream *stream;
46 } FCGI_Disc;
47
48 static ssize_t
49 sffcgiread(f, buf, n, disc)
50 Sfio_t*         f;      /* stream involved */
51 Void_t*         buf;    /* buffer to read into */
52 size_t          n;      /* number of bytes to read */
53 Sfdisc_t*       disc;   /* discipline */
54 {
55     return FCGX_GetStr(buf, n, ((FCGI_Disc *)disc)->stream);
56 }
57
58 static ssize_t
59 sffcgiwrite(f, buf, n, disc)
60 Sfio_t*         f;      /* stream involved */
61 const Void_t*   buf;    /* buffer to read into */
62 size_t          n;      /* number of bytes to read */
63 Sfdisc_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
70 Sfdisc_t *
71 sfdcnewfcgi(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
87 Sfdisc_t *
88 sfdcdelfcgi(disc)
89     Sfdisc_t*   disc;
90 {
91     Safefree(disc);
92     return 0;
93 }
94 #endif
95
96 #if defined(USE_LOCKING) && defined(USE_THREADS)
97 static perl_mutex   accept_mutex;
98 #endif
99
100 typedef 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
115 static void FCGI_Finish(FCGP_Request* request);
116
117 static void 
118 FCGI_Flush(FCGP_Request* request)
119 {
120     dTHX;
121
122     if(!request->bound) {
123         return;
124         }
125 #ifdef USE_SFIO
126     sfsync(IoOFP(GvIOp(request->gv[1])));
127     sfsync(IoOFP(GvIOp(request->gv[2])));
128 #else
129     FCGX_FFlush(INT2PTR(FCGX_Stream *, SvIV((SV*) SvRV(request->svout))));
130     FCGX_FFlush(INT2PTR(FCGX_Stream *, SvIV((SV*) SvRV(request->sverr))));
131 #endif
132 }
133
134 static void
135 FCGI_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
151 static void
152 FCGI_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
168 static void
169 populate_env(envp, hv)
170 char **envp;
171 HV *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
192 static int
193 FCGI_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
207 static int 
208 FCGI_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         }
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));
266 #endif
267         FCGI_Bind(request);
268         request->accepted = TRUE;
269     }
270     return 0;
271 }
272
273 static void 
274 FCGI_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
301         FCGX_Free(request->requestPtr, 1);
302     request->accepted = FALSE;
303 }
304
305 static int 
306 FCGI_StartFilterData(FCGP_Request* request)
307 {
308     return request->requestPtr->in ? 
309             FCGX_StartFilterData(request->requestPtr->in) : -1;
310 }
311
312 static FCGP_Request *
313 FCGI_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;
328     SvREFCNT_inc(in);
329     req->gv[0] = in;
330     SvREFCNT_inc(out);
331     req->gv[1] = out;
332     SvREFCNT_inc(err);
333     req->gv[2] = err;
334     SvREFCNT_inc(env);
335     req->hvEnv = env;
336
337     return req;
338 }
339
340 static void
341 FCGI_Release_Request(FCGP_Request *req)
342 {
343     SvREFCNT_dec(req->gv[0]);
344     SvREFCNT_dec(req->gv[1]);
345     SvREFCNT_dec(req->gv[2]);
346     SvREFCNT_dec(req->hvEnv);
347     FCGI_Finish(req);
348     Safefree(req->requestPtr);
349     Safefree(req);
350 }
351
352 static void
353 FCGI_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
364 typedef FCGX_Stream *   FCGI__Stream;
365 typedef FCGP_Request *  FCGI;
366 typedef GV*             GLOBREF;
367 typedef HV*             HASHREF;
368
369 MODULE = FCGI           PACKAGE = FCGI      PREFIX = FCGI_
370
371 BOOT:
372     FCGI_Init();
373
374 SV *
375 RequestX(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
391 int
392 OpenSocket(path, backlog)
393     char* path;
394     int backlog;
395
396     PROTOTYPE: $$
397     CODE:
398     RETVAL = FCGX_OpenSocket(path, backlog);
399     OUTPUT:
400     RETVAL
401
402 void
403 CloseSocket(socket)
404     int socket;
405
406     PROTOTYPE: $
407     CODE:
408     close(socket);
409
410 int
411 FCGI_Accept(request)
412
413     FCGI    request;
414
415     PROTOTYPE: $
416
417 void
418 FCGI_Finish(request)
419     FCGI    request;
420
421     PROTOTYPE: $
422
423 void
424 FCGI_Flush(request)
425     FCGI    request;
426
427     PROTOTYPE: $
428
429 HV *
430 GetEnvironment(request)
431     FCGI    request;
432
433     PROTOTYPE: $
434
435     CODE:
436     RETVAL = request->hvEnv;
437
438     OUTPUT: 
439     RETVAL
440
441 void
442 GetHandles(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
455 int
456 FCGI_IsFastCGI(request)
457     FCGI    request;
458
459     PROTOTYPE: $
460
461 void
462 Detach(request)
463     FCGI    request;
464
465     PROTOTYPE: $
466
467     CODE:
468     if (request->accepted && request->bound)
469         FCGI_UndoBinding(request);
470
471 void
472 Attach(request)
473     FCGI    request;
474
475     PROTOTYPE: $
476
477     CODE:
478     if (request->accepted && !request->bound)
479         FCGI_Bind(request);
480
481 void
482 LastCall(request)
483     FCGI    request;
484
485     PROTOTYPE: $
486
487     CODE:
488     FCGX_ShutdownPending();
489
490 int
491 FCGI_StartFilterData(request)
492
493     FCGI    request;
494
495     PROTOTYPE: $
496
497 void
498 DESTROY(request)
499     FCGI    request;
500
501     CODE:
502     FCGI_Release_Request(request);
503
504
505
506 MODULE = FCGI           PACKAGE = FCGI::Stream
507
508 #ifndef USE_SFIO
509
510 void
511 PRINT(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
526 int
527 WRITE(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
552 int
553 READ(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
577 SV *
578 GETC(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
590 bool
591 CLOSE(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