use Config;
open OUT, ">FCGI.xs";
print "Generating FCGI.xs for Perl version $]\n";
#unless (exists $Config{apiversion} && $Config{apiversion} >= 5.005)
unless ($] >= 5.005) {
for (qw(sv_undef diehook warnhook in_eval)) {
print OUT "#define PL_$_ $_\n"
}
}
print OUT while <DATA>;
close OUT;
__END__
/* $Id: FCGI.XL,v 1.10 2003/06/22 00:24:11 robs Exp $ */
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "fcgi_config.h"
#include "fcgiapp.h"
#include "fastcgi.h"
#ifndef FALSE
#define FALSE (0)
#endif
#ifndef TRUE
#define TRUE (1)
#endif
#ifndef dTHX
#define dTHX
#endif
#ifndef INT2PTR
#define INT2PTR(a,b) ((a) (b))
#endif
#ifdef USE_SFIO
typedef struct
{
Sfdisc_t disc;
FCGX_Stream *stream;
} FCGI_Disc;
static ssize_t
sffcgiread(f, buf, n, disc)
Sfio_t* f; /* stream involved */
Void_t* buf; /* buffer to read into */
size_t n; /* number of bytes to read */
Sfdisc_t* disc; /* discipline */
{
return FCGX_GetStr(buf, n, ((FCGI_Disc *)disc)->stream);
}
static ssize_t
sffcgiwrite(f, buf, n, disc)
Sfio_t* f; /* stream involved */
const Void_t* buf; /* buffer to read into */
size_t n; /* number of bytes to read */
Sfdisc_t* disc; /* discipline */
{
n = FCGX_PutStr(buf, n, ((FCGI_Disc *)disc)->stream);
FCGX_FFlush(((FCGI_Disc *)disc)->stream);
return n;
}
Sfdisc_t *
sfdcnewfcgi(stream)
FCGX_Stream *stream;
{
FCGI_Disc* disc;
New(1000,disc,1,FCGI_Disc);
if (!disc) return (Sfdisc_t *)disc;
disc->disc.exceptf = (Sfexcept_f)NULL;
disc->disc.seekf = (Sfseek_f)NULL;
disc->disc.readf = sffcgiread;
disc->disc.writef = sffcgiwrite;
disc->stream = stream;
return (Sfdisc_t *)disc;
}
Sfdisc_t *
sfdcdelfcgi(disc)
Sfdisc_t* disc;
{
Safefree(disc);
return 0;
}
#endif
#if defined(USE_LOCKING) && defined(USE_THREADS)
static perl_mutex accept_mutex;
#endif
typedef struct FCGP_Request {
int accepted;
int bound;
SV* svin;
SV* svout;
SV* sverr;
GV* gv[3];
HV* hvEnv;
FCGX_Request* requestPtr;
#ifdef USE_SFIO
int sfcreated[3];
IO* io[3];
#endif
} FCGP_Request;
static void FCGI_Finish(FCGP_Request* request);
static void
FCGI_Flush(FCGP_Request* request)
{
dTHX;
if(!request->bound) {
return;
}
#ifdef USE_SFIO
sfsync(IoOFP(GvIOp(request->gv[1])));
sfsync(IoOFP(GvIOp(request->gv[2])));
#else
FCGX_FFlush(INT2PTR(FCGX_Stream *, SvIV((SV*) SvRV(request->svout))));
FCGX_FFlush(INT2PTR(FCGX_Stream *, SvIV((SV*) SvRV(request->sverr))));
#endif
}
static void
FCGI_UndoBinding(FCGP_Request* request)
{
dTHX;
#ifdef USE_SFIO
sfdcdelfcgi(sfdisc(IoIFP(request->io[0]), SF_POPDISC));
sfdcdelfcgi(sfdisc(IoOFP(request->io[1]), SF_POPDISC));
sfdcdelfcgi(sfdisc(IoOFP(request->io[2]), SF_POPDISC));
#else
# ifdef USE_PERLIO
sv_unmagic((SV *)GvIOp(request->gv[0]), 'q');
sv_unmagic((SV *)GvIOp(request->gv[1]), 'q');
sv_unmagic((SV *)GvIOp(request->gv[2]), 'q');
# else
sv_unmagic((SV *)request->gv[0], 'q');
sv_unmagic((SV *)request->gv[1], 'q');
sv_unmagic((SV *)request->gv[2], 'q');
# endif
#endif
request->bound = FALSE;
}
static void
FCGI_Bind(FCGP_Request* request)
{
dTHX;
#ifdef USE_SFIO
sfdisc(IoIFP(request->io[0]), sfdcnewfcgi(request->requestPtr->in));
sfdisc(IoOFP(request->io[1]), sfdcnewfcgi(request->requestPtr->out));
sfdisc(IoOFP(request->io[2]), sfdcnewfcgi(request->requestPtr->err));
#else
# ifdef USE_PERLIO
/* For tied filehandles, we apply tiedscalar magic to the IO
slot of the GP rather than the GV itself. */
if (!GvIOp(request->gv[1]))
GvIOp(request->gv[1]) = newIO();
if (!GvIOp(request->gv[2]))
GvIOp(request->gv[2]) = newIO();
if (!GvIOp(request->gv[0]))
GvIOp(request->gv[0]) = newIO();
sv_magic((SV *)GvIOp(request->gv[1]), request->svout, 'q', Nullch, 0);
sv_magic((SV *)GvIOp(request->gv[2]), request->sverr, 'q', Nullch, 0);
sv_magic((SV *)GvIOp(request->gv[0]), request->svin, 'q', Nullch, 0);
# else
sv_magic((SV *)request->gv[1], request->svout, 'q', Nullch, 0);
sv_magic((SV *)request->gv[2], request->sverr, 'q', Nullch, 0);
sv_magic((SV *)request->gv[0], request->svin, 'q', Nullch, 0);
# endif
#endif
request->bound = TRUE;
}
static void
populate_env(envp, hv)
char **envp;
HV *hv;
{
int i;
char *p, *p1;
SV *sv;
dTHX;
hv_clear(hv);
for(i = 0; ; i++) {
if((p = envp[i]) == NULL) {
break;
}
p1 = strchr(p, '=');
assert(p1 != NULL);
sv = newSVpv(p1 + 1, 0);
/* call magic for this value ourselves */
hv_store(hv, p, p1 - p, sv, 0);
SvSETMAGIC(sv);
}
}
static int
FCGI_IsFastCGI(FCGP_Request* request)
{
static int isCGI = -1; /* -1: not checked; 0: FCGI; 1: CGI */
if (request->requestPtr->listen_sock == FCGI_LISTENSOCK_FILENO) {
if (isCGI == -1)
isCGI = FCGX_IsCGI();
return !isCGI;
}
/* A explicit socket is being used -> assume FastCGI */
return 1;
}
static int
FCGI_Accept(FCGP_Request* request)
{
dTHX;
if (!FCGI_IsFastCGI(request)) {
static int been_here = 0;
/*
* Not first call to FCGI_Accept and running as CGI means
* application is done.
*/
if (been_here)
return EOF;
been_here = 1;
} else {
#ifdef USE_SFIO
int i;
#endif
FCGX_Request *fcgx_req = request->requestPtr;
int acceptResult;
FCGI_Finish(request);
#if defined(USE_LOCKING) && defined(USE_THREADS)
MUTEX_LOCK(&accept_mutex);
#endif
acceptResult = FCGX_Accept_r(fcgx_req);
#if defined(USE_LOCKING) && defined(USE_THREADS)
MUTEX_UNLOCK(&accept_mutex);
#endif
if(acceptResult < 0) {
return acceptResult;
}
populate_env(fcgx_req->envp, request->hvEnv);
#ifdef USE_SFIO
for (i = 0; i < 3; ++i) {
request->io[i] = GvIOn(request->gv[i]);
if (!(i == 0 ? IoIFP(request->io[i])
: IoOFP(request->io[i]))) {
IoIFP(request->io[i]) = sftmp(0);
/*IoIFP(request->io[i]) = sfnew(NULL, NULL, SF_UNBOUND, 0,
SF_STRING | (i ? SF_WRITE : SF_READ));*/
if (i != 0)
IoOFP(request->io[i]) = IoIFP(request->io[i]);
request->sfcreated[i] = TRUE;
}
}
#else
if (!request->svout) {
newSVrv(request->svout = newSV(0), "FCGI::Stream");
newSVrv(request->sverr = newSV(0), "FCGI::Stream");
newSVrv(request->svin = newSV(0), "FCGI::Stream");
}
sv_setiv(SvRV(request->svout), INT2PTR(IV, fcgx_req->out));
sv_setiv(SvRV(request->sverr), INT2PTR(IV, fcgx_req->err));
sv_setiv(SvRV(request->svin), INT2PTR(IV, fcgx_req->in));
#endif
FCGI_Bind(request);
request->accepted = TRUE;
}
return 0;
}
static void
FCGI_Finish(FCGP_Request* request)
{
#ifdef USE_SFIO
int i;
#endif
int was_bound;
dTHX;
if(!request->accepted) {
return;
}
if (was_bound = request->bound) {
FCGI_UndoBinding(request);
}
#ifdef USE_SFIO
for (i = 0; i < 3; ++i) {
if (request->sfcreated[i]) {
sfclose(IoIFP(request->io[i]));
IoIFP(request->io[i]) = IoOFP(request->io[i]) = Nullfp;
request->sfcreated[i] = FALSE;
}
}
#endif
if (was_bound)
FCGX_Finish_r(request->requestPtr);
else
FCGX_Free(request->requestPtr, 1);
request->accepted = FALSE;
}
static int
FCGI_StartFilterData(FCGP_Request* request)
{
return request->requestPtr->in ?
FCGX_StartFilterData(request->requestPtr->in) : -1;
}
static FCGP_Request *
FCGI_Request(in, out, err, env, socket, flags)
GV* in;
GV* out;
GV* err;
HV* env;
int socket;
int flags;
{
FCGX_Request* fcgx_req;
FCGP_Request* req;
Newz(551, fcgx_req, 1, FCGX_Request);
FCGX_InitRequest(fcgx_req, socket, flags);
Newz(551, req, 1, FCGP_Request);
req->requestPtr = fcgx_req;
SvREFCNT_inc(in);
req->gv[0] = in;
SvREFCNT_inc(out);
req->gv[1] = out;
SvREFCNT_inc(err);
req->gv[2] = err;
SvREFCNT_inc(env);
req->hvEnv = env;
return req;
}
static void
FCGI_Release_Request(FCGP_Request *req)
{
SvREFCNT_dec(req->gv[0]);
SvREFCNT_dec(req->gv[1]);
SvREFCNT_dec(req->gv[2]);
SvREFCNT_dec(req->hvEnv);
FCGI_Finish(req);
Safefree(req->requestPtr);
Safefree(req);
}
static void
FCGI_Init()
{
#if defined(USE_LOCKING) && defined(USE_THREADS)
dTHX;
MUTEX_INIT(&accept_mutex);
#endif
FCGX_Init();
}
typedef FCGX_Stream * FCGI__Stream;
typedef FCGP_Request * FCGI;
typedef GV* GLOBREF;
typedef HV* HASHREF;
MODULE = FCGI PACKAGE = FCGI PREFIX = FCGI_
BOOT:
FCGI_Init();
SV *
RequestX(in, out, err, env, socket, flags)
GLOBREF in;
GLOBREF out;
GLOBREF err;
HASHREF env;
int socket;
int flags;
PROTOTYPE: ***$$$
CODE:
RETVAL = sv_setref_pv(newSV(0), "FCGI",
FCGI_Request(in, out, err, env, socket, flags));
OUTPUT:
RETVAL
int
OpenSocket(path, backlog)
char* path;
int backlog;
PROTOTYPE: $$
CODE:
RETVAL = FCGX_OpenSocket(path, backlog);
OUTPUT:
RETVAL
void
CloseSocket(socket)
int socket;
PROTOTYPE: $
CODE:
close(socket);
int
FCGI_Accept(request)
FCGI request;
PROTOTYPE: $
void
FCGI_Finish(request)
FCGI request;
PROTOTYPE: $
void
FCGI_Flush(request)
FCGI request;
PROTOTYPE: $
HV *
GetEnvironment(request)
FCGI request;
PROTOTYPE: $
CODE:
RETVAL = request->hvEnv;
OUTPUT:
RETVAL
void
GetHandles(request)
FCGI request;
PROTOTYPE: $
PREINIT:
int i;
PPCODE:
EXTEND(sp,3);
for (i = 0; i < 3; ++i)
PUSHs(sv_2mortal(newRV((SV *) request->gv[i])));
int
FCGI_IsFastCGI(request)
FCGI request;
PROTOTYPE: $
void
Detach(request)
FCGI request;
PROTOTYPE: $
CODE:
if (request->accepted && request->bound) {
FCGI_UndoBinding(request);
FCGX_Detach(request->requestPtr);
}
void
Attach(request)
FCGI request;
PROTOTYPE: $
CODE:
if (request->accepted && !request->bound) {
FCGI_Bind(request);
FCGX_Attach(request->requestPtr);
}
void
LastCall(request)
FCGI request;
PROTOTYPE: $
CODE:
FCGX_ShutdownPending();
int
FCGI_StartFilterData(request)
FCGI request;
PROTOTYPE: $
void
DESTROY(request)
FCGI request;
CODE:
FCGI_Release_Request(request);
MODULE = FCGI PACKAGE = FCGI::Stream
#ifndef USE_SFIO
SV *
PRINT(stream, ...)
FCGI::Stream stream;
PREINIT:
int n;
STRLEN len;
register char *str;
bool ok = TRUE;
CODE:
for (n = 1; ok && n < items; ++n) {
#ifdef DO_UTF8
if (DO_UTF8(ST(n)) && !sv_utf8_downgrade(ST(n), 1))
croak("Wide character in FCGI::Stream::PRINT");
#endif
str = (char *)SvPV(ST(n),len);
if (FCGX_PutStr(str, len, stream) < 0)
ok = FALSE;
}
if (ok && SvTRUEx(perl_get_sv("|", FALSE)) && FCGX_FFlush(stream) < 0)
ok = FALSE;
RETVAL = ok ? &PL_sv_yes : &PL_sv_undef;
int
WRITE(stream, bufsv, len, ...)
FCGI::Stream stream;
SV * bufsv;
int len;
PREINIT:
int offset;
char * buf;
STRLEN blen;
int n;
CODE:
offset = (items == 4) ? (int)SvIV(ST(3)) : 0;
#ifdef DO_UTF8
if (DO_UTF8(bufsv) && !sv_utf8_downgrade(bufsv, 1))
croak("Wide character in FCGI::Stream::WRITE");
#endif
buf = SvPV(bufsv, blen);
if (offset < 0) offset += blen;
if (len > blen - offset)
len = blen - offset;
if (offset < 0 || offset >= blen ||
(n = FCGX_PutStr(buf+offset, len, stream)) < 0)
ST(0) = &PL_sv_undef;
else {
ST(0) = sv_newmortal();
sv_setiv(ST(0), n);
}
int
READ(stream, bufsv, len, ...)
FCGI::Stream stream;
SV * bufsv;
int len;
PREINIT:
int offset;
char * buf;
CODE:
offset = (items == 4) ? (int)SvIV(ST(3)) : 0;
#ifdef DO_UTF8
if (DO_UTF8(bufsv) && !sv_utf8_downgrade(bufsv, 1))
croak("Wide character in FCGI::Stream::READ");
#endif
if (! SvOK(bufsv))
sv_setpvn(bufsv, "", 0);
buf = SvGROW(bufsv, len+offset+1);
len = FCGX_GetStr(buf+offset, len, stream);
SvCUR_set(bufsv, len+offset);
*SvEND(bufsv) = '\0';
(void)SvPOK_only(bufsv);
SvSETMAGIC(bufsv);
RETVAL = len;
OUTPUT:
RETVAL
SV *
GETC(stream)
FCGI::Stream stream;
PREINIT:
int retval;
CODE:
if ((retval = FCGX_GetChar(stream)) != -1) {
ST(0) = sv_newmortal();
sv_setpvf(ST(0), "%c", retval);
} else ST(0) = &PL_sv_undef;
bool
CLOSE(stream)
FCGI::Stream stream;
# ALIAS:
# DESTROY = 1
CODE:
RETVAL = FCGX_FClose(stream) != -1;
OUTPUT:
RETVAL
#endif