CGI-SpeedyCGI

 view release on metacpan or  search on metacpan

src/speedy_perl.c  view on Meta::CPAN

    return hv_fetch(hash, key, key_len, lval);
}

/* Find the SpeedyScript structure in the hash, using a devino key
 * Create a new one if not found.
 */
static SpeedyScript *find_scr(SpeedyDevIno devino, int *is_new) {
    SV *sv;
    SpeedyScript *retval;

    sv = find_devino(devino, scr_hash, 1)[0];

    if ((*is_new = !SvOK(sv))) {
	speedy_new(retval, 1, SpeedyScript);
	retval->handler = NULL;
	retval->last_cwd = NULL;
	sv_setiv(sv, (IV) retval);
    } else {
	retval = (SpeedyScript *) SvIV(sv);
    }

    return retval;
}

/* Get the directory that holds the filename */
static char *fname_dir(const char *p) {
    char *s;

    if (p && (s = strrchr(p, '/')))
	return speedy_util_strndup(p, max(1,s-p));
    else
	return NULL;
}

static void my_call_sv(SV *sv) {
    if (sv) {
	dSP;
	PUSHMARK(SP);
	call_sv(sv, G_DISCARD | G_NOARGS);
    }
}

static void cwd_refcnt_dec(SpeedyCwd *cwd) {
    if (!--(cwd->refcnt)) {
	char key[DEVINO_STR_SIZE];
	int key_len;

	key_len = devino_str(cwd->devino, key);
	hv_delete(cwd_hash, key, key_len, G_DISCARD);

	hv_delete_ent(cwd_hash, cwd->path, G_DISCARD, 0);
	SvREFCNT_dec(cwd->path);
	speedy_free(cwd);
    }
}

static int stat_cwd_fd(SpeedyDevIno *devino) {
    struct stat stbuf;

    if (cwd_fd != -1) {
	if (fstat(cwd_fd, &stbuf) != -1) {
	    *devino = speedy_util_stat_devino(&stbuf);
	    return 1;
	}
	close(cwd_fd);
	cwd_fd = -1;
    }
    return 0;
}

static int chdir_path(const char *path, SpeedyDevIno *devino) {
    int retval;

    if (!path || !path[0])
	return 0;

    if (cwd_fd != -1)
	close(cwd_fd);
    retval = path
	? (((path[0] == '.' && path[1] == '\0')) ? 0 : chdir(path))
	: -1;
    cwd_fd = retval != -1
	? speedy_util_pref_fd(open(".", O_RDONLY), PREF_FD_CWD)
	: -1;
    
    if (cwd_fd != -1)
	fcntl(cwd_fd, F_SETFD, FD_CLOEXEC);

    /* TEST - simulate unreadable "." directory */
    /* close(cwd_fd); cwd_fd = -1; */
    
    /* Get device/inode for "." */
    if (retval != -1 && devino && !stat_cwd_fd(devino)) {
	struct stat stbuf;

	if (cwd_fd == -1) {
	    if (stat(".", &stbuf) == -1) {
		devino->d = 0;
		devino->i = 0;
	    }
	} else {
	    *devino = speedy_util_stat_devino(&stbuf);
	}
    }
    return retval;
}

static int quick_cd(SpeedyDevIno dest) {
    SpeedyDevIno devino;

    /*
     * See if cwd_fd is the correct dir - if so fchdir there.
     */
    if (stat_cwd_fd(&devino) && DEVINO_SAME(dest, devino) &&
	fchdir(cwd_fd) != -1)
    {
	return 1;
    }

    /* Stat "." */
    chdir_path(".", &devino);

    /* See if "." is the right directory */
    return DEVINO_SAME(dest, devino);
}

static void *get_perlvar(SpeedyPerlVar *pv) {
    if (!pv->ptr) {
	switch(pv->type) {
	    case SVt_PVIO:
		pv->ptr = gv_fetchpv(pv->name, 1, SVt_PVIO);
		break;
	    case SVt_PVAV:
		pv->ptr = get_av(pv->name, 1);
		break;
	    case SVt_PVHV:
		pv->ptr = get_hv(pv->name, 1);
		break;
	    case SVt_PVCV:
		pv->ptr = get_cv(pv->name, 0);
		break;
	    default:
		pv->ptr = get_sv(pv->name, 1);
		break;
	}
	if (pv->type != SVt_PVCV && !pv->ptr)
	    DIE_QUIET("Cannot create perl variable %s", pv->name);
    }
    return pv->ptr;
}

/* Shutdown and exit. */
static void all_done(void) {
    speedy_file_set_state(FS_CLOSED);

    /* Destroy the interpreter */
    if (my_perl) {

src/speedy_perl.c  view on Meta::CPAN

    speedy_new(cwd, 1, SpeedyCwd);

    /* Chdir to the given path */
    if (!path || chdir_path(path, &(cwd->devino)) == -1) {
	speedy_free(cwd);
	return NULL;
    }

    /* Make a new cwd structure */
    cwd->refcnt = 0;
    cwd->path = newSVpv(path, 0);

    /* Store in the hash */
    sv = newSViv((IV)cwd);
    SvREFCNT_inc(sv);

    key_len = devino_str(cwd->devino, key);
    my_hv_store(cwd_hash, key, key_len, sv);

    if (!hv_store_ent(cwd_hash, cwd->path, sv, 0))
	SvREFCNT_dec(sv);

    return cwd;
}

static void store_last_cwd(SpeedyCwd **last_cwd, SpeedyCwd *cwd) {
    SpeedyCwd *prev_ptr = *last_cwd;

    cwd->refcnt++;
    *last_cwd = cwd;
    if (prev_ptr)
	cwd_refcnt_dec(prev_ptr);
}

#define PACKAGE_FMT	SPEEDY_PKG("_%s")
#define COLON_HANDLER	"::handler"
#define PACKAGE1      "package "
#define PACKAGE2      "; sub handler { "

static void load_script(
    SpeedyDevIno devino, SpeedyScript *scr, const char *scr_path
)
{
    SV *sv;
    char pkg[sizeof(PACKAGE_FMT)+DEVINO_STR_SIZE+sizeof(COLON_HANDLER)+5];

    /* Get package name */
    {
	char hex_str[DEVINO_STR_SIZE];
	devino_str(devino, hex_str);
	sprintf(pkg, PACKAGE_FMT, hex_str);
    }

    /* Create phony package in sv with the script code in the handler func */
    {
	struct stat stbuf;
	SpeedyMapInfo *mi = NULL;
	int fd;

	/* Grab the contents of the file */
	if ((fd = speedy_util_open_stat(scr_path, &stbuf)) != -1) {
	    mi = speedy_util_mapin(fd, -1, stbuf.st_size);
	    close(fd);
	}
	if (fd == -1 || mi == NULL)
	    speedy_util_die(scr_path);

	/* Create sv to eval */
        sv = newSVpvn(PACKAGE1, sizeof(PACKAGE1)-1);
        sv_catpv (sv, pkg);
        sv_catpvn(sv, PACKAGE2, sizeof(PACKAGE2)-1);
	sv_catpvn(sv, mi->addr, mi->maplen);
	sv_catpvn(sv, "; }", 3);

	/* Get rid of the file contents */
	speedy_util_mapout(mi);
    }

    /* Evaluate the sv to create the handler */
    {
	dSP;
	PUSHMARK(SP);
	eval_sv(sv, G_DISCARD | G_NOARGS | G_VOID | G_EVAL | G_KEEPERR);
    }
    SvREFCNT_dec(sv);

    /* If there were no eval errors, then store a reference to the handler  */
    scr->handler = NULL;
    if (!SvTRUE(PERLVAL_EVAL_ERROR)) {
	CV *cv;
	strcat(pkg, COLON_HANDLER);
	if ((cv = get_cv(pkg, 0)))
	    scr->handler = newRV_inc((SV*)cv);
    }

    /* Die if we couldn't create the handler for whatever reason */
    if (!scr->handler) {
	DIE_QUIET("Could not compile code for %s: %s",
	    scr_path, my_SvPV(PERLVAL_EVAL_ERROR));
    }
}

static void cleanup_after_perl(void) {

    /* Cached time is now invalid */
    speedy_util_time_invalidate();

    /* Cancel any alarms */
    alarm(0);

    /* Terminate if a forked child returned */
    if (getpid() != speedy_util_getpid()) {
	speedy_util_pid_invalidate();
	speedy_file_fork_child();
	all_done();
    }

    /* Tell our file code that its fd is suspect */
    speedy_file_fd_is_suspect();
}

src/speedy_perl.c  view on Meta::CPAN

    }
#endif

    return exit_val;
}


/* Called from xs_init */
void speedy_xs_init(void) {
    int i;
    SV *sv;

    /*
     * Put things here that have to be done in the perl interpreter before
     * a script runs its BEGIN block.
     */

    /* Find/create our perl vars in the interpreter */
    for (i = 0; i < PERLVAR_COUNT; ++i) {
	(void) get_perlvar(SpeedyPerlVars + i);
    }
    scr_hash = newHV();
    cwd_hash = newHV();

    /* Tell our module that we are speedycgi */
    sv_inc(PERLVAL_I_AM_SPEEDY);

    /* Avoid warnings about "used only once" */
    GvMULTI_on(
	gv_fetchpv(PERLVAR_I_AM_SPEEDY.name, 0, PERLVAR_I_AM_SPEEDY.type)
    );

    /*
     * Initialize options variables in our module.
     */
    for (i = 0; i < SPEEDY_NUMOPTS; ++i) {
	OptRec *o = speedy_optdefs + i;
	if (o->type == OTYPE_STR) {
	    if (!STR_OPTVAL(o))
		continue;
	    sv = newSVpv(STR_OPTVAL(o), 0);
	} else {
	    sv = newSViv(INT_OPTVAL(o));
	}
	my_hv_store(PERLVAL_OPTS, o->name, o->name_len, sv);
    }
}

void speedy_perl_init(void) {
    char **perl_argv;
    const char *temp_script_name;
    int use_devfd, is_new;
    char dev_fd_name[sizeof(DEVFD)+10];
    SpeedyScript *scr;
    int single_script = DOING_SINGLE_SCRIPT;

    /* If we're exec'ing a setuid script then we must use a temporary
     * script name of /dev/fd/N 
     */
    use_devfd = single_script &&
                speedy_script_getstat()->st_mode & (S_ISUID|S_ISGID);

    if (single_script) {
	if (use_devfd) {
	    sprintf(dev_fd_name, DEVFD, speedy_script_open());
	    temp_script_name = dev_fd_name;
	} else {
	    temp_script_name = NULL;
	}
    } else {
	temp_script_name = "-e&{$" SPEEDY_PKG("_sub") "}(@ARGV);";
    }

    /* Parse perl file. */
    perl_argv = speedy_opt_perl_argv(temp_script_name);
    if (perl_parse(my_perl, xs_init,
	speedy_util_argc((const char * const *)perl_argv), perl_argv, NULL))
    {
	DIE_QUIET("perl_parse error");
    }
    cleanup_after_perl();

    /* If we had to use /dev/fd/N, perl will close the file for us, so
     * make sure our code knows it's closed.  If we need it from here on out
     * it'll have to be re-opened.
     */
    if (use_devfd)
	speedy_script_close();

    /* Create a SpeedyScript entry for the standard script */
    scr = find_scr(speedy_util_stat_devino(speedy_script_getstat()), &is_new);

    /* If using groups, try pre-loading the script to save time later */
    if (!single_script && !speedy_script_open_failure()) {
	load_script(
	    speedy_util_stat_devino(speedy_script_getstat()),
	    scr, speedy_opt_script_fname()
	);
	cleanup_after_perl();
    }

    /* Time to close stderr */
    close(2);
}

void speedy_perl_run(slotnum_t gslotnum, slotnum_t bslotnum) {
    int numrun, exit_val;
    int single_script = DOING_SINGLE_SCRIPT;

    /* Start listening on our socket */
    speedy_ipc_listen(bslotnum);

    /* Main loop */
    for (numrun = 0; !OPTVAL_MAXRUNS || numrun < OPTVAL_MAXRUNS; ++numrun) {

	/* Lock/mmap our temp file.  If our group is invalid, exit quietly */
	if (getppid() == 1 || !speedy_group_lock(gslotnum))
	    all_done();

	/* Update our maturity level */
	FILE_SLOT(be_slot, bslotnum).maturity = numrun ? 2 : 1;

	/* Put ourself onto the be_wait list */
	speedy_backend_be_wait_put(gslotnum, bslotnum);

	/* If we were listed as starting, turn that off */
	if (FILE_SLOT(gr_slot, gslotnum).be_starting == speedy_util_getpid())
	    FILE_SLOT(gr_slot, gslotnum).be_starting = 0;

	/* Send out alarm signal to frontends */
	speedy_group_sendsigs(gslotnum);

	/* Fix our listener fd */
	speedy_ipc_listen_fixfd(bslotnum);

	/* Unlock file */
	speedy_file_set_state(FS_HAVESLOTS);

	/* Do an accept on our socket */
	backend_accept();

	/* Lock file.  If our group is invalid, exit quietly */
	if (!speedy_group_lock(gslotnum))
	    all_done();

	/* If we were listed as starting, turn that off */
	if (FILE_SLOT(gr_slot, gslotnum).be_starting == speedy_util_getpid())
	    FILE_SLOT(gr_slot, gslotnum).be_starting = 0;

	/* Wake up any waiting frontends */
	speedy_group_sendsigs(gslotnum);

	/* Unlock the file */
	speedy_file_set_state(FS_HAVESLOTS);

	/* Run the perl code once */



( run in 3.011 seconds using v1.01-cache-2.11-cpan-e1769b4cff6 )