[ANN] nginx-perl
Alexandr Gomoliako
zzz на zzz.org.ua
Вт Ноя 1 17:50:59 UTC 2011
> На всякий случай прикладываю и в виде патча.
Патч.
-------------- next part --------------
diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm
--- a/src/http/modules/perl/nginx.pm
+++ b/src/http/modules/perl/nginx.pm
@@ -1,14 +1,37 @@
package nginx;
-use 5.006001;
use strict;
use warnings;
require Exporter;
+our @ISA = qw(Exporter);
+our @EXPORT = qw(
-our @ISA = qw(Exporter);
+ ngx_timer
+ ngx_connector
+ ngx_reader
+ ngx_writer
+ ngx_read
+ ngx_write
+ ngx_close
+ ngx_noop
-our @EXPORT = qw(
+ NGX_READ
+ NGX_WRITE
+ NGX_CLOSE
+ NGX_NOOP
+ NGX_EOF
+ NGX_EINVAL
+ NGX_ENOMEM
+ NGX_ETIMEDOUT
+ NGX_EBADE
+ NGX_EBADF
+
+ NGX_DONE
+ NGX_OK
+ NGX_HTTP_LAST
+
+
OK
DECLINED
@@ -53,54 +76,6 @@
require XSLoader;
XSLoader::load('nginx', $VERSION);
-# Preloaded methods go here.
-
-use constant OK => 0;
-use constant DECLINED => -5;
-
-use constant HTTP_OK => 200;
-use constant HTTP_CREATED => 201;
-use constant HTTP_ACCEPTED => 202;
-use constant HTTP_NO_CONTENT => 204;
-use constant HTTP_PARTIAL_CONTENT => 206;
-
-use constant HTTP_MOVED_PERMANENTLY => 301;
-use constant HTTP_MOVED_TEMPORARILY => 302;
-use constant HTTP_REDIRECT => 302;
-use constant HTTP_NOT_MODIFIED => 304;
-
-use constant HTTP_BAD_REQUEST => 400;
-use constant HTTP_UNAUTHORIZED => 401;
-use constant HTTP_PAYMENT_REQUIRED => 402;
-use constant HTTP_FORBIDDEN => 403;
-use constant HTTP_NOT_FOUND => 404;
-use constant HTTP_NOT_ALLOWED => 405;
-use constant HTTP_NOT_ACCEPTABLE => 406;
-use constant HTTP_REQUEST_TIME_OUT => 408;
-use constant HTTP_CONFLICT => 409;
-use constant HTTP_GONE => 410;
-use constant HTTP_LENGTH_REQUIRED => 411;
-use constant HTTP_REQUEST_ENTITY_TOO_LARGE => 413;
-use constant HTTP_REQUEST_URI_TOO_LARGE => 414;
-use constant HTTP_UNSUPPORTED_MEDIA_TYPE => 415;
-use constant HTTP_RANGE_NOT_SATISFIABLE => 416;
-
-use constant HTTP_INTERNAL_SERVER_ERROR => 500;
-use constant HTTP_SERVER_ERROR => 500;
-use constant HTTP_NOT_IMPLEMENTED => 501;
-use constant HTTP_BAD_GATEWAY => 502;
-use constant HTTP_SERVICE_UNAVAILABLE => 503;
-use constant HTTP_GATEWAY_TIME_OUT => 504;
-use constant HTTP_INSUFFICIENT_STORAGE => 507;
-
-
-sub rflush {
- my $r = shift;
-
- $r->flush;
-}
-
-
1;
__END__
diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs
--- a/src/http/modules/perl/nginx.xs
+++ b/src/http/modules/perl/nginx.xs
@@ -93,9 +93,62 @@
return ngx_http_output_filter(r, &out);
}
+#define ci(stash, a, b) newCONSTSUB (stash, a, newSViv(b))
MODULE = nginx PACKAGE = nginx
+BOOT:
+ HV *stash = gv_stashpv ("nginx", 1);
+ ci (stash, "NGX_DONE", NGX_DONE);
+ ci (stash, "NGX_HTTP_LAST", NGX_HTTP_LAST);
+ ci (stash, "NGX_OK", NGX_OK);
+ ci (stash, "NGX_DECLINED", NGX_DECLINED);
+ ci (stash, "NGX_NOOP", NGX_PERL_NOOP);
+ ci (stash, "NGX_READ", NGX_PERL_READ);
+ ci (stash, "NGX_WRITE", NGX_PERL_WRITE);
+ ci (stash, "NGX_CLOSE", NGX_PERL_CLOSE);
+ ci (stash, "NGX_EOF", NGX_PERL_EOF);
+ ci (stash, "NGX_EINVAL", NGX_PERL_EINVAL);
+ ci (stash, "NGX_ENOMEM", NGX_PERL_ENOMEM);
+ ci (stash, "NGX_EBADF", NGX_PERL_EBADF);
+ ci (stash, "NGX_EBADE", NGX_PERL_EBADE);
+ ci (stash, "NGX_ETIMEDOUT", NGX_PERL_ETIMEDOUT);
+ ci (stash, "OK", 0);
+ ci (stash, "DECLINED", -5);
+ ci (stash, "HTTP_OK", 200);
+ ci (stash, "HTTP_CREATED", 201);
+ ci (stash, "HTTP_ACCEPTED", 202);
+ ci (stash, "HTTP_NO_CONTENT", 204);
+ ci (stash, "HTTP_PARTIAL_CONTENT", 206);
+ ci (stash, "HTTP_MOVED_PERMANENTLY", 301);
+ ci (stash, "HTTP_MOVED_TEMPORARILY", 302);
+ ci (stash, "HTTP_REDIRECT", 302);
+ ci (stash, "HTTP_NOT_MODIFIED", 304);
+ ci (stash, "HTTP_BAD_REQUEST", 400);
+ ci (stash, "HTTP_UNAUTHORIZED", 401);
+ ci (stash, "HTTP_PAYMENT_REQUIRED", 402);
+ ci (stash, "HTTP_FORBIDDEN", 403);
+ ci (stash, "HTTP_NOT_FOUND", 404);
+ ci (stash, "HTTP_NOT_ALLOWED", 405);
+ ci (stash, "HTTP_NOT_ACCEPTABLE", 406);
+ ci (stash, "HTTP_REQUEST_TIME_OUT", 408);
+ ci (stash, "HTTP_CONFLICT", 409);
+ ci (stash, "HTTP_GONE", 410);
+ ci (stash, "HTTP_LENGTH_REQUIRED", 411);
+ ci (stash, "HTTP_REQUEST_ENTITY_TOO_LARGE", 413);
+ ci (stash, "HTTP_REQUEST_URI_TOO_LARGE", 414);
+ ci (stash, "HTTP_UNSUPPORTED_MEDIA_TYPE", 415);
+ ci (stash, "HTTP_RANGE_NOT_SATISFIABLE", 416);
+ ci (stash, "HTTP_INTERNAL_SERVER_ERROR", 500);
+ ci (stash, "HTTP_SERVER_ERROR", 500);
+ ci (stash, "HTTP_NOT_IMPLEMENTED", 501);
+ ci (stash, "HTTP_BAD_GATEWAY", 502);
+ ci (stash, "HTTP_SERVICE_UNAVAILABLE", 503);
+ ci (stash, "HTTP_GATEWAY_TIME_OUT", 504);
+ ci (stash, "HTTP_INSUFFICIENT_STORAGE", 507);
+
+PROTOTYPES: DISABLE
+
void
status(r, code)
@@ -696,6 +749,9 @@
void
flush(r)
+ ALIAS:
+ rflush = 1
+
CODE:
ngx_http_request_t *r;
@@ -983,3 +1039,147 @@
p = (u_char *) SvPV(msg, len);
ngx_log_error(NGX_LOG_ERR, r->connection->log, e, "perl: %s", p);
+
+
+void
+main_count_inc(r)
+ CODE:
+
+ ngx_http_request_t *r;
+
+ ngx_http_perl_set_request(r);
+
+ r->main->count++;
+
+
+void
+finalize_request(r, rc)
+ ALIAS:
+ send_special = 1
+ CODE:
+
+ ngx_http_request_t *r;
+
+ ngx_http_perl_set_request(r);
+
+ switch (ix) {
+ case 1:
+ ngx_http_send_special(r, SvIV(ST(1)));
+ break;
+ default:
+ ngx_http_finalize_request(r, SvIV(ST(1)));
+ break;
+ }
+
+
+SV *
+ngx_timer(after, repeat, cb)
+ PROTOTYPE: $$&
+ CODE:
+
+ ngx_connection_t *c;
+
+ c = ngx_perl_timer((ngx_int_t)SvIV(ST(0)), ST(1), ST(2));
+ if (c == NULL) {
+ croak("ngx_perl_timer returned NULL");
+ }
+
+ RETVAL = newSViv(PTR2IV(c));
+
+ OUTPUT:
+ RETVAL
+
+
+void
+ngx_timer_clear(timer)
+ CODE:
+
+ ngx_connection_t *c;
+
+ c = INT2PTR(ngx_connection_t *, SvIV(ST(0)));
+ ngx_perl_timer_clear(c);
+
+
+void
+ngx_connector(address, port, timeout, cb)
+ PROTOTYPE: $$$&
+ CODE:
+
+ ngx_perl_connector(ST(0), ST(1), ST(2), ST(3));
+
+
+void
+ngx_reader(c, buf, min, max, timeout, cb)
+ PROTOTYPE: $$$$$&
+ CODE:
+
+ ngx_connection_t *c;
+
+ c = INT2PTR(ngx_connection_t *, SvIV(ST(0)));
+
+ ngx_perl_reader(c, ST(1), ST(2), ST(3), ST(4), ST(5));
+
+
+void
+ngx_writer(c, buf, timeout, cb)
+ PROTOTYPE: $$$&
+ CODE:
+
+ ngx_connection_t *c;
+
+ c = INT2PTR(ngx_connection_t *, SvIV(ST(0)));
+
+ ngx_perl_writer(c, ST(1), ST(2), ST(3));
+
+
+void
+ngx_close(c)
+ PROTOTYPE: $
+ CODE:
+
+ ngx_connection_t *c;
+
+ c = INT2PTR(ngx_connection_t *, SvIV(ST(0)));
+
+ ngx_perl_close(c);
+
+
+void
+ngx_read(c)
+ PROTOTYPE: $
+ CODE:
+
+ ngx_connection_t *c;
+
+ c = INT2PTR(ngx_connection_t *, SvIV(ST(0)));
+
+ ngx_perl_read(c);
+
+
+void
+ngx_write(c)
+ PROTOTYPE: $
+ CODE:
+
+ ngx_connection_t *c;
+
+ c = INT2PTR(ngx_connection_t *, SvIV(ST(0)));
+
+ ngx_perl_write(c);
+ if (c->write->ready) {
+ c->write->handler(c->write);
+ }
+
+
+void
+ngx_noop(c)
+ PROTOTYPE: $
+ CODE:
+
+ ngx_connection_t *c;
+
+ c = INT2PTR(ngx_connection_t *, SvIV(ST(0)));
+
+ ngx_perl_noop(c);
+
+
diff --git a/src/http/modules/perl/ngx_http_perl_module.c b/src/http/modules/perl/ngx_http_perl_module.c
--- a/src/http/modules/perl/ngx_http_perl_module.c
+++ b/src/http/modules/perl/ngx_http_perl_module.c
@@ -11,8 +11,6 @@
typedef struct {
- PerlInterpreter *perl;
- HV *nginx;
ngx_array_t *modules;
ngx_array_t *requires;
} ngx_http_perl_main_conf_t;
@@ -42,7 +40,7 @@
static ngx_int_t ngx_http_perl_run_requires(pTHX_ ngx_array_t *requires,
ngx_log_t *log);
static ngx_int_t ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r,
- HV *nginx, SV *sub, SV **args, ngx_str_t *handler, ngx_str_t *rv);
+ SV *sub, SV **args, ngx_str_t *handler, ngx_str_t *rv);
static void ngx_http_perl_eval_anon_sub(pTHX_ ngx_str_t *handler, SV **sv);
static ngx_int_t ngx_http_perl_preconfiguration(ngx_conf_t *cf);
@@ -54,13 +52,16 @@
static char *ngx_http_perl(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static char *ngx_http_perl_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
-#if (NGX_HAVE_PERL_MULTIPLICITY)
-static void ngx_http_perl_cleanup_perl(void *data);
-#endif
-
static ngx_int_t ngx_http_perl_init_worker(ngx_cycle_t *cycle);
static void ngx_http_perl_exit(ngx_cycle_t *cycle);
+static void ngx_perl_timer_callback(ngx_event_t *ev);
+static void ngx_perl_connection_cleanup(void *data);
+static void ngx_perl_connect_handler(ngx_event_t *ev);
+static void ngx_perl_dummy_handler(ngx_event_t *ev);
+static void ngx_perl_read_handler(ngx_event_t *ev);
+static void ngx_perl_write_handler(ngx_event_t *ev);
+
static ngx_command_t ngx_http_perl_commands[] = {
@@ -148,12 +149,9 @@
static ngx_str_t ngx_null_name = ngx_null_string;
static HV *nginx_stash;
-
-#if (NGX_HAVE_PERL_MULTIPLICITY)
-static ngx_uint_t ngx_perl_term;
-#else
-static PerlInterpreter *perl;
-#endif
+static PerlInterpreter *my_perl;
+
+static ngx_log_t *ngx_perl_log;
static void
@@ -170,8 +168,12 @@
{
r->main->count++;
+ /* ngx_perl_log = r->connection->log; */
+
ngx_http_perl_handle_request(r);
+ /* ngx_perl_log = ngx_cycle->log; */
+
return NGX_DONE;
}
@@ -184,7 +186,6 @@
ngx_str_t uri, args, *handler;
ngx_http_perl_ctx_t *ctx;
ngx_http_perl_loc_conf_t *plcf;
- ngx_http_perl_main_conf_t *pmcf;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "perl handler");
@@ -200,28 +201,18 @@
ngx_http_set_ctx(r, ctx, ngx_http_perl_module);
}
- pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module);
-
- {
-
- dTHXa(pmcf->perl);
- PERL_SET_CONTEXT(pmcf->perl);
if (ctx->next == NULL) {
plcf = ngx_http_get_module_loc_conf(r, ngx_http_perl_module);
sub = plcf->sub;
handler = &plcf->handler;
-
} else {
sub = ctx->next;
handler = &ngx_null_name;
ctx->next = NULL;
}
- rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, sub, NULL, handler,
- NULL);
-
- }
+ rc = ngx_http_perl_call_handler(aTHX_ r, sub, NULL, handler, NULL);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"perl handler done: %i", rc);
@@ -297,7 +288,6 @@
ngx_int_t rc;
ngx_str_t value;
ngx_http_perl_ctx_t *ctx;
- ngx_http_perl_main_conf_t *pmcf;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"perl variable handler");
@@ -313,20 +303,11 @@
ngx_http_set_ctx(r, ctx, ngx_http_perl_module);
}
- pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module);
-
value.data = NULL;
- {
-
- dTHXa(pmcf->perl);
- PERL_SET_CONTEXT(pmcf->perl);
-
- rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, pv->sub, NULL,
+ rc = ngx_http_perl_call_handler(aTHX_ r, pv->sub, NULL,
&pv->handler, &value);
- }
-
if (value.data) {
v->len = value.len;
v->valid = 1;
@@ -359,7 +340,6 @@
ngx_str_t *handler, **args;
ngx_uint_t i;
ngx_http_perl_ctx_t *ctx;
- ngx_http_perl_main_conf_t *pmcf;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"perl ssi handler");
@@ -375,18 +355,11 @@
ngx_http_set_ctx(r, ctx, ngx_http_perl_module);
}
- pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module);
-
ctx->ssi = ssi_ctx;
handler = params[NGX_HTTP_PERL_SSI_SUB];
handler->data[handler->len] = '\0';
- {
-
- dTHXa(pmcf->perl);
- PERL_SET_CONTEXT(pmcf->perl);
-
#if 0
/* the code is disabled to force the precompiled perl code using only */
@@ -430,13 +403,11 @@
asv = NULL;
}
- rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, sv, asv, handler,
+ rc = ngx_http_perl_call_handler(aTHX_ r, sv, asv, handler,
NULL);
SvREFCNT_dec(sv);
- }
-
ctx->filename.data = NULL;
ctx->redirect_uri.len = 0;
ctx->ssi = NULL;
@@ -454,15 +425,6 @@
{
ngx_str_t *m;
ngx_uint_t i;
-#if (NGX_HAVE_PERL_MULTIPLICITY)
- ngx_pool_cleanup_t *cln;
-
- cln = ngx_pool_cleanup_add(cf->pool, 0);
- if (cln == NULL) {
- return NGX_CONF_ERROR;
- }
-
-#endif
#ifdef NGX_PERL_MODULES
if (pmcf->modules == NGX_CONF_UNSET_PTR) {
@@ -490,9 +452,7 @@
}
}
-#if !(NGX_HAVE_PERL_MULTIPLICITY)
-
- if (perl) {
+ if (my_perl) {
if (ngx_set_environment(cf->cycle, NULL) == NULL) {
return NGX_CONF_ERROR;
@@ -504,37 +464,20 @@
return NGX_CONF_ERROR;
}
- pmcf->perl = perl;
- pmcf->nginx = nginx_stash;
-
return NGX_CONF_OK;
}
-#endif
if (nginx_stash == NULL) {
PERL_SYS_INIT(&ngx_argc, &ngx_argv);
}
- pmcf->perl = ngx_http_perl_create_interpreter(cf, pmcf);
-
- if (pmcf->perl == NULL) {
+ my_perl = ngx_http_perl_create_interpreter(cf, pmcf);
+
+ if (my_perl == NULL) {
return NGX_CONF_ERROR;
}
- pmcf->nginx = nginx_stash;
-
-#if (NGX_HAVE_PERL_MULTIPLICITY)
-
- cln->handler = ngx_http_perl_cleanup_perl;
- cln->data = pmcf->perl;
-
-#else
-
- perl = pmcf->perl;
-
-#endif
-
return NGX_CONF_OK;
}
@@ -549,7 +492,6 @@
char *ver, **embedding;
ngx_str_t *m;
ngx_uint_t i;
- PerlInterpreter *perl;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "create perl interpreter");
@@ -557,18 +499,17 @@
return NULL;
}
- perl = perl_alloc();
- if (perl == NULL) {
+ my_perl = perl_alloc();
+ if (my_perl == NULL) {
ngx_log_error(NGX_LOG_ALERT, cf->log, 0, "perl_alloc() failed");
return NULL;
}
{
- dTHXa(perl);
- PERL_SET_CONTEXT(perl);
-
- perl_construct(perl);
+ perl_construct(my_perl);
+
+ PL_origalen = 1;
#ifdef PERL_EXIT_DESTRUCT_END
PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
@@ -595,7 +536,7 @@
embedding[n++] = "-e";
embedding[n++] = "0";
- n = perl_parse(perl, ngx_http_perl_xs_init, n, embedding, NULL);
+ n = perl_parse(my_perl, ngx_http_perl_xs_init, n, embedding, NULL);
if (n != 0) {
ngx_log_error(NGX_LOG_ALERT, cf->log, 0, "perl_parse() failed: %d", n);
@@ -618,13 +559,13 @@
}
- return perl;
+ return my_perl;
fail:
- (void) perl_destruct(perl);
-
- perl_free(perl);
+ (void) perl_destruct(my_perl);
+
+ perl_free(my_perl);
return NULL;
}
@@ -665,7 +606,7 @@
static ngx_int_t
-ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, HV *nginx, SV *sub,
+ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, SV *sub,
SV **args, ngx_str_t *handler, ngx_str_t *rv)
{
SV *sv;
@@ -685,7 +626,7 @@
PUSHMARK(sp);
- sv = sv_2mortal(sv_bless(newRV_noinc(newSViv(PTR2IV(r))), nginx));
+ sv = sv_2mortal(sv_bless(newRV_noinc(newSViv(PTR2IV(r))), nginx_stash));
XPUSHs(sv);
if (args) {
@@ -808,7 +749,7 @@
{
ngx_http_perl_main_conf_t *pmcf = conf;
- if (pmcf->perl == NULL) {
+ if (my_perl == NULL) {
if (ngx_http_perl_init_interpreter(cf, pmcf) != NGX_CONF_OK) {
return NGX_CONF_ERROR;
}
@@ -818,28 +759,6 @@
}
-#if (NGX_HAVE_PERL_MULTIPLICITY)
-
-static void
-ngx_http_perl_cleanup_perl(void *data)
-{
- PerlInterpreter *perl = data;
-
- PERL_SET_CONTEXT(perl);
-
- (void) perl_destruct(perl);
-
- perl_free(perl);
-
- if (ngx_perl_term) {
- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "perl term");
-
- PERL_SYS_TERM();
- }
-}
-
-#endif
-
static ngx_int_t
ngx_http_perl_preconfiguration(ngx_conf_t *cf)
@@ -922,7 +841,7 @@
pmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_perl_module);
- if (pmcf->perl == NULL) {
+ if (my_perl == NULL) {
if (ngx_http_perl_init_interpreter(cf, pmcf) != NGX_CONF_OK) {
return NGX_CONF_ERROR;
}
@@ -930,11 +849,6 @@
plcf->handler = value[1];
- {
-
- dTHXa(pmcf->perl);
- PERL_SET_CONTEXT(pmcf->perl);
-
ngx_http_perl_eval_anon_sub(aTHX_ &value[1], &plcf->sub);
if (plcf->sub == &PL_sv_undef) {
@@ -947,8 +861,6 @@
plcf->sub = newSVpvn((char *) value[1].data, value[1].len);
}
- }
-
clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
clcf->handler = ngx_http_perl_handler;
@@ -993,7 +905,7 @@
pmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_perl_module);
- if (pmcf->perl == NULL) {
+ if (my_perl == NULL) {
if (ngx_http_perl_init_interpreter(cf, pmcf) != NGX_CONF_OK) {
return NGX_CONF_ERROR;
}
@@ -1003,9 +915,6 @@
{
- dTHXa(pmcf->perl);
- PERL_SET_CONTEXT(pmcf->perl);
-
ngx_http_perl_eval_anon_sub(aTHX_ &value[2], &pv->sub);
if (pv->sub == &PL_sv_undef) {
@@ -1035,14 +944,14 @@
pmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_perl_module);
if (pmcf) {
- dTHXa(pmcf->perl);
- PERL_SET_CONTEXT(pmcf->perl);
/* set worker's $$ */
sv_setiv(GvSV(gv_fetchpv("$", TRUE, SVt_PV)), (I32) ngx_pid);
}
+ ngx_perl_log = ngx_cycle->log;
+
return NGX_OK;
}
@@ -1050,26 +959,977 @@
static void
ngx_http_perl_exit(ngx_cycle_t *cycle)
{
-#if (NGX_HAVE_PERL_MULTIPLICITY)
-
- /*
- * the master exit hook is run before global pool cleanup,
- * therefore just set flag here
- */
-
- ngx_perl_term = 1;
-
-#else
if (nginx_stash) {
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cycle->log, 0, "perl term");
- (void) perl_destruct(perl);
-
- perl_free(perl);
+ (void) perl_destruct(my_perl);
+
+ perl_free(my_perl);
PERL_SYS_TERM();
}
-
-#endif
}
+
+
+ngx_connection_t *
+ngx_perl_timer(ngx_int_t after, SV *repeat, SV *cb)
+{
+ ngx_connection_t *c;
+ ngx_perl_timer_t *t;
+
+ c = ngx_get_connection((ngx_socket_t) 0, ngx_cycle->log);
+ if (c == NULL) {
+ return NULL;
+ }
+
+ Newz(0, t, 1, ngx_perl_timer_t);
+ if (t == NULL) {
+ return NULL;
+ }
+
+ c->read->handler = ngx_perl_timer_callback;
+ c->read->active = 1;
+ c->read->log = ngx_cycle->log;
+
+ c->data = (void *) t;
+
+ t->after = after;
+ t->repeat = repeat;
+ t->cb = cb;
+
+ SvREFCNT_inc(t->repeat);
+ SvREFCNT_inc(t->cb);
+
+ ngx_add_timer(c->read, t->after * 1000);
+
+ return c;
+}
+
+
+void
+ngx_perl_timer_clear(ngx_connection_t *c)
+{
+ ngx_perl_timer_t *t;
+
+ if (c->destroyed) {
+ ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
+ "ngx_perl_timer_clear: connection already destroyed");
+ return;
+ }
+
+ t = (ngx_perl_timer_t *) c->data;
+
+ SvREFCNT_dec(t->repeat);
+ SvREFCNT_dec(t->cb);
+
+ if (c->read->timer_set) {
+ ngx_del_timer(c->read);
+ }
+
+ safefree(t);
+ ngx_free_connection(c);
+
+ return;
+}
+
+
+static void
+ngx_perl_timer_callback(ngx_event_t *ev)
+{
+ ngx_connection_t *c;
+ ngx_perl_timer_t *t;
+ dSP;
+
+ c = (ngx_connection_t *) ev->data;
+ t = (ngx_perl_timer_t *) c->data;
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(SP);
+ XPUSHs(sv_2mortal(newSViv(PTR2IV(c))));
+ PUTBACK;
+
+ call_sv(t->cb, G_VOID|G_DISCARD);
+
+ FREETMPS;
+ LEAVE;
+
+ if (SvIV(t->repeat) > 0) {
+ ngx_add_timer(ev, SvIV(t->repeat) * 1000);
+ } else {
+ ngx_perl_timer_clear(c);
+ }
+
+ return;
+}
+
+
+void
+ngx_perl_connector(SV *address, SV *port, SV *timeout, SV *cb)
+{
+ in_addr_t inaddr;
+ in_port_t inport;
+ ngx_pool_t *pool;
+ struct sockaddr_in *sin;
+ ngx_peer_connection_t *peer;
+ ngx_perl_connection_t *plc;
+ ngx_pool_cleanup_t *plccln;
+ ngx_connection_t *c;
+ ngx_int_t rc;
+ dSP;
+
+ if (!SvOK(address) || !SvOK(port) || !SvOK(timeout)) {
+ ngx_log_error(NGX_LOG_ERR, ngx_perl_log, 0,
+ "ngx_perl_connector: incorrect argument(s)");
+ errno = NGX_PERL_EINVAL;
+ goto FATAL;
+ }
+
+ inport = (in_port_t) SvIV(port);
+
+ inaddr = ngx_inet_addr((u_char *) SvPV_nolen(address), SvCUR(address));
+
+ if (inaddr == INADDR_NONE) {
+ ngx_log_error(NGX_LOG_ERR, ngx_perl_log, 0,
+ "ngx_perl_connector: incorrect address");
+ errno = NGX_PERL_EINVAL;
+ goto FATAL;
+ }
+
+ pool = ngx_create_pool(1024, ngx_perl_log);
+
+ if (pool == NULL) {
+ errno = NGX_PERL_ENOMEM;
+ goto FATAL;
+ }
+
+ sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in));
+
+ if (sin == NULL) {
+ ngx_log_error(NGX_LOG_ERR, pool->log, 0,
+ "ngx_perl_connector: ngx_pcalloc() failed");
+ ngx_destroy_pool(pool);
+ errno = NGX_PERL_ENOMEM;
+ goto FATAL;
+ }
+
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = inaddr;
+ sin->sin_port = htons(inport);
+
+
+
+ plc = ngx_pcalloc(pool, sizeof(ngx_perl_connection_t));
+
+ if (plc == NULL) {
+ ngx_log_error(NGX_LOG_ERR, pool->log, 0,
+ "ngx_perl_connector: ngx_pcalloc() failed");
+ ngx_destroy_pool(pool);
+ errno = NGX_PERL_ENOMEM;
+ goto FATAL;
+ }
+
+ plccln = ngx_pool_cleanup_add(pool, 0);
+
+ if (plccln == NULL) {
+ ngx_log_error(NGX_LOG_ERR, pool->log, 0,
+ "ngx_perl_connector: ngx_pool_cleanup_add() failed");
+ ngx_destroy_pool(pool);
+ errno = NGX_PERL_ENOMEM;
+ goto FATAL;
+ }
+
+ plccln->data = (void *) plc;
+ plccln->handler = ngx_perl_connection_cleanup;
+
+
+
+ peer = ngx_pcalloc(pool, sizeof(ngx_peer_connection_t));
+
+ if (peer == NULL) {
+ ngx_log_error(NGX_LOG_ERR, pool->log, 0,
+ "ngx_perl_connector: ngx_pcalloc() failed");
+ ngx_destroy_pool(pool);
+ errno = NGX_PERL_ENOMEM;
+ goto FATAL;
+ }
+
+ peer->sockaddr = (struct sockaddr *) sin;
+ peer->socklen = sizeof(struct sockaddr_in);
+ peer->get = ngx_event_get_peer;
+ peer->log = pool->log;
+ peer->log_error = NGX_ERROR_ERR;
+
+
+ peer->name = ngx_pcalloc(pool, sizeof(ngx_str_t));
+
+ if (peer->name == NULL) {
+ ngx_log_error(NGX_LOG_ERR, peer->log, 0,
+ "ngx_perl_connector: ngx_pcalloc() failed");
+ ngx_destroy_pool(pool);
+ errno = NGX_PERL_ENOMEM;
+ goto FATAL;
+ }
+
+ peer->name->data = ngx_pcalloc(pool, SvCUR(address));
+
+ if (peer->name->data == NULL) {
+ ngx_log_error(NGX_LOG_ERR, peer->log, 0,
+ "ngx_perl_connector: ngx_pcalloc() failed");
+ ngx_destroy_pool(pool);
+ errno = NGX_PERL_ENOMEM;
+ goto FATAL;
+ }
+
+ ngx_memcpy(peer->name->data, SvPVX(address), SvCUR(address));
+ peer->name->len = SvCUR(address);
+
+
+
+ rc = ngx_event_connect_peer(peer);
+
+ if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) {
+ ngx_log_error(NGX_LOG_ERR, peer->log, 0,
+ "ngx_perl_connector: ngx_event_connect_peer() failed");
+
+ if (peer->connection)
+ ngx_close_connection(peer->connection);
+
+ ngx_destroy_pool(pool);
+
+ errno = NGX_PERL_EBADF;
+ goto FATAL;
+ }
+
+
+ c = peer->connection;
+
+ if (c == NULL) {
+ ngx_log_error(NGX_LOG_ERR, pool->log, 0,
+ "ngx_perl_connector: no peer->connection");
+ ngx_destroy_pool(pool);
+ errno = NGX_PERL_EBADF;
+ goto FATAL;
+ }
+
+ c->pool = pool;
+ c->log = pool->log;
+ c->data = (void *) plc;
+
+ plc->connect_cb = cb;
+ SvREFCNT_inc(cb);
+
+ c->write->handler = ngx_perl_connect_handler;
+ c->read->handler = ngx_perl_connect_handler;
+
+ ngx_add_timer(c->write, SvOK(timeout) && SvIV(timeout)
+ ? SvIV(timeout) * 1000 : 15000);
+
+ if (rc == NGX_OK) {
+ c->write->handler(c->write);
+ return;
+ }
+
+ return;
+
+FATAL:
+
+ SvREFCNT_inc(cb);
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(SP);
+ PUTBACK;
+
+ call_sv(cb, G_VOID|G_DISCARD);
+
+ FREETMPS;
+ LEAVE;
+
+ SvREFCNT_dec(cb);
+ errno = 0;
+
+ return;
+}
+
+
+void
+ngx_perl_reader(ngx_connection_t *c, SV *buf, SV *min, SV *max,
+ SV *timeout, SV *cb)
+{
+ ngx_perl_connection_t *plc;
+
+ plc = (ngx_perl_connection_t *) c->data;
+
+ if (plc->read_min) {
+ SvREFCNT_dec(plc->read_min);
+ plc->read_min = NULL;
+ }
+
+ if (plc->read_max) {
+ SvREFCNT_dec(plc->read_max);
+ plc->read_max = NULL;
+ }
+
+ if (plc->read_timeout) {
+ SvREFCNT_dec(plc->read_timeout);
+ plc->read_timeout = NULL;
+ }
+
+ if (plc->read_buffer) {
+ SvREFCNT_dec(plc->read_buffer);
+ plc->read_buffer = NULL;
+ }
+
+ if (plc->read_cb) {
+ SvREFCNT_dec(plc->read_cb);
+ plc->read_cb = NULL;
+ }
+
+ plc->read_min = min;
+ plc->read_max = max;
+ plc->read_buffer = buf;
+ plc->read_timeout = timeout;
+ plc->read_cb = cb;
+
+ SvREFCNT_inc(min);
+ SvREFCNT_inc(max);
+ SvREFCNT_inc(buf);
+ SvREFCNT_inc(timeout);
+ SvREFCNT_inc(cb);
+
+ return;
+}
+
+
+void
+ngx_perl_writer(ngx_connection_t *c, SV *buf, SV *timeout, SV *cb)
+{
+ ngx_perl_connection_t *plc;
+
+ plc = (ngx_perl_connection_t *) c->data;
+
+ if (plc->write_timeout) {
+ SvREFCNT_dec(plc->write_timeout);
+ plc->write_timeout = NULL;
+ }
+
+ if (plc->write_buffer) {
+ SvREFCNT_dec(plc->write_buffer);
+ plc->write_buffer = NULL;
+ }
+
+ if (plc->write_cb) {
+ SvREFCNT_dec(plc->write_cb);
+ plc->write_cb = NULL;
+ }
+
+ plc->write_buffer = buf;
+ plc->write_timeout = timeout;
+ plc->write_cb = cb;
+
+ SvREFCNT_inc(buf);
+ SvREFCNT_inc(timeout);
+ SvREFCNT_inc(cb);
+
+ return;
+}
+
+static void
+ngx_perl_connection_cleanup(void *data)
+{
+ ngx_perl_connection_t *plc;
+
+ plc = (ngx_perl_connection_t *) data;
+
+
+ if (plc->connect_cb) {
+ SvREFCNT_dec(plc->connect_cb);
+ plc->connect_cb = NULL;
+ }
+
+
+ if (plc->read_min) {
+ SvREFCNT_dec(plc->read_min);
+ plc->read_min = NULL;
+ }
+
+ if (plc->read_max) {
+ SvREFCNT_dec(plc->read_max);
+ plc->read_max = NULL;
+ }
+
+ if (plc->read_timeout) {
+ SvREFCNT_dec(plc->read_timeout);
+ plc->read_timeout = NULL;
+ }
+
+ if (plc->read_buffer) {
+ SvREFCNT_dec(plc->read_buffer);
+ plc->read_buffer = NULL;
+ }
+
+ if (plc->read_cb) {
+ SvREFCNT_dec(plc->read_cb);
+ plc->read_cb = NULL;
+ }
+
+
+ if (plc->write_timeout) {
+ SvREFCNT_dec(plc->write_timeout);
+ plc->write_timeout = NULL;
+ }
+
+ if (plc->write_buffer) {
+ SvREFCNT_dec(plc->write_buffer);
+ plc->write_buffer = NULL;
+ }
+
+ if (plc->write_cb) {
+ SvREFCNT_dec(plc->write_cb);
+ plc->write_cb = NULL;
+ }
+
+
+ return;
+}
+
+
+void
+ngx_perl_close(ngx_connection_t *c)
+{
+ ngx_pool_t *pool;
+
+ if (c->destroyed) {
+ ngx_log_error(NGX_LOG_ERR, c->log, 0,
+ "ngx_perl_close: "
+ "connection already destroyed");
+ return;
+ }
+
+ pool = c->pool;
+
+ ngx_close_connection(c);
+ ngx_destroy_pool(pool);
+
+ return;
+}
+
+
+void
+ngx_perl_read(ngx_connection_t *c)
+{
+ ngx_perl_connection_t *plc;
+
+ plc = (ngx_perl_connection_t *) c->data;
+
+ if (c->read->timer_set) {
+ ngx_del_timer(c->read);
+ }
+
+ c->read->handler = ngx_perl_read_handler;
+ c->write->handler = ngx_perl_dummy_handler;
+
+ if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
+
+ if (c->read->error == 0)
+ c->read->error = 1;
+
+ c->read->handler(c->read);
+ return;
+ }
+
+ if (!c->read->timer_set) {
+
+ if (plc->read_timeout != NULL &&
+ SvOK (plc->read_timeout) &&
+ SvIV (plc->read_timeout) >= 0)
+ {
+ ngx_add_timer(c->read, SvIV(plc->read_timeout) * 1000);
+
+ } else {
+
+ ngx_log_error(NGX_LOG_ERR, c->log, 0,
+ "ngx_perl_read: "
+ "incorrent read timeout, using 15 s instead");
+
+ ngx_add_timer(c->read, 15000);
+ }
+ }
+
+ return;
+}
+
+
+void
+ngx_perl_write(ngx_connection_t *c)
+{
+ ngx_perl_connection_t *plc;
+
+ plc = (ngx_perl_connection_t *) c->data;
+
+ plc->write_offset = 0;
+
+ if (c->write->timer_set) {
+ ngx_del_timer(c->write);
+ }
+
+ c->read->handler = ngx_perl_read_handler;
+ c->write->handler = ngx_perl_write_handler;
+
+ if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
+
+ if (c->write->error == 0)
+ c->write->error = 1;
+
+ c->write->handler(c->write);
+ return;
+ }
+
+ if (!c->write->timer_set) {
+
+ if (plc->write_timeout != NULL &&
+ SvOK (plc->write_timeout) &&
+ SvIV (plc->write_timeout) >= 0)
+ {
+ ngx_add_timer(c->write, SvIV(plc->write_timeout) * 1000);
+
+ } else {
+
+ ngx_log_error(NGX_LOG_ERR, c->log, 0,
+ "ngx_perl_write: "
+ "incorrent write timeout, using 15 s instead");
+
+ ngx_add_timer(c->write, 15000);
+ }
+ }
+
+ return;
+}
+
+
+void
+ngx_perl_noop(ngx_connection_t *c)
+{
+
+ c->read->handler = ngx_perl_dummy_handler;
+ c->write->handler = ngx_perl_dummy_handler;
+
+ return;
+}
+
+
+static void
+ngx_perl_dummy_handler(ngx_event_t *ev)
+{
+ ngx_connection_t *c;
+
+ c = (ngx_connection_t *) ev->data;
+
+ ngx_log_debug(NGX_LOG_DEBUG, c->log, 0,
+ "ngx_perl_dummy_handler called");
+
+ return;
+}
+
+
+static void
+ngx_perl_connect_handler(ngx_event_t *ev)
+{
+ ngx_connection_t *c;
+ ngx_perl_connection_t *plc;
+ ngx_int_t cmd, count;
+ dSP;
+
+ c = (ngx_connection_t *) ev->data;
+ plc = (ngx_perl_connection_t *) c->data;
+
+ c->read->handler = ngx_perl_dummy_handler;
+ c->write->handler = ngx_perl_dummy_handler;
+
+ if (ev->timer_set) {
+ ngx_del_timer(ev);
+ }
+
+ if (ev->timedout) {
+ errno = NGX_PERL_ETIMEDOUT;
+ goto CALLBACK;
+ }
+
+ if (ev->error || c->error) {
+ errno = NGX_PERL_EBADE;
+ goto CALLBACK;
+ }
+
+ errno = 0;
+
+CALLBACK:
+
+ SvREFCNT_inc(plc->connect_cb);
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(SP);
+ XPUSHs(sv_2mortal(newSViv(PTR2IV(c))));
+ PUTBACK;
+
+ count = call_sv(plc->connect_cb, G_VOID|G_SCALAR);
+
+ if (count != 1) {
+ ngx_log_error(NGX_LOG_ERR, c->log, 0,
+ "ngx_perl_connect_handler: "
+ "call_sv returned wrong count = %i",
+ count);
+ }
+
+ SPAGAIN;
+ cmd = POPi;
+ PUTBACK;
+
+ FREETMPS;
+ LEAVE;
+
+ SvREFCNT_dec(plc->connect_cb);
+ errno = 0;
+
+ if ((ev->error || c->error) && cmd != NGX_PERL_CLOSE) {
+ ngx_log_error(NGX_LOG_ERR, c->log, 0,
+ "ngx_perl_connect_handler: "
+ "NGX_CLOSE required on error, forcing");
+ ngx_perl_close(c);
+ return;
+ }
+
+ switch (cmd) {
+ case NGX_PERL_CLOSE:
+ ngx_perl_close(c);
+ break;
+ case NGX_PERL_READ:
+ ngx_perl_read(c);
+ if (c->read->ready) {
+ c->read->handler(c->read);
+ }
+ break;
+ case NGX_PERL_WRITE:
+ ngx_perl_write(c);
+ if (c->write->ready) {
+ c->write->handler(c->write);
+ }
+ break;
+ case NGX_PERL_NOOP:
+ ngx_perl_noop(c);
+ break;
+ }
+
+ return;
+}
+
+
+static void
+ngx_perl_read_handler(ngx_event_t *ev)
+{
+ ssize_t n;
+ ngx_connection_t *c;
+ ngx_perl_connection_t *plc;
+ SV *sv, *cb;
+ U32 min, max;
+ ngx_int_t cmd, count;
+ dSP;
+
+ c = (ngx_connection_t *) ev->data;
+ plc = (ngx_perl_connection_t *) c->data;
+
+ if (ev->timer_set) {
+ ngx_del_timer(ev);
+ }
+
+ if (ev->timedout) {
+ errno = NGX_PERL_ETIMEDOUT;
+ goto CALLBACK;
+ }
+
+AGAIN:
+
+ if (ev->error || c->error) {
+ errno = NGX_PERL_EBADE;
+ goto CALLBACK;
+ }
+
+
+ min = 0;
+ max = 0;
+
+ if ( SvOK ( plc->read_min ) &&
+ SvIV ( plc->read_min ) )
+ min = SvIV ( plc->read_min );
+
+ if ( SvOK ( plc->read_max ) &&
+ SvIV ( plc->read_max ) )
+ max = SvIV ( plc->read_max );
+
+
+ sv = plc->read_buffer;
+
+ SvPOK_on(sv);
+
+ if ( SvLEN(sv) - SvCUR(sv) < 1500) {
+ if ( max ) {
+ if ( SvLEN(sv) < max + 1 ) {
+ SvGROW(sv, ( SvCUR(sv) * 2 ) + 1500);
+ } else {
+ if ( SvCUR(sv) >= max ) {
+ goto CALLBACK;
+ }
+ }
+ } else {
+ SvGROW(sv, ( SvCUR(sv) * 2 ) + 1500);
+ }
+ }
+
+
+ for ( ;; ) {
+
+ ngx_socket_errno = 0;
+
+ n = c->recv(c, (u_char *) SvPVX (sv) + SvCUR (sv),
+ ( max && SvLEN (sv) > max
+ ? max + 1 : SvLEN (sv) ) - SvCUR (sv) - 1);
+
+ if (n == NGX_AGAIN) {
+
+ if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
+ errno = NGX_PERL_EBADE;
+ goto CALLBACK;
+ }
+
+ return;
+ }
+
+ if (n == 0) {
+ errno = NGX_PERL_EOF;
+ goto CALLBACK;
+ }
+
+ if (n == NGX_ERROR) {
+ errno = ngx_socket_errno ? ngx_socket_errno : NGX_PERL_EBADE;
+ goto CALLBACK;
+ }
+
+ SvCUR_set (sv, SvCUR (sv) + n);
+
+ if ( SvCUR (sv) < min ) {
+ continue;
+ }
+
+ break;
+ }
+
+ errno = 0;
+
+CALLBACK:
+
+ cb = plc->read_cb;
+
+ SvREFCNT_inc(cb);
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(SP);
+ XPUSHs(sv_2mortal(newSViv(PTR2IV(c))));
+ PUTBACK;
+
+ ngx_log_debug(NGX_LOG_DEBUG, c->log, 0,
+ "ngx_perl_read_handler: "
+ "ev->eof = %i, ev->error = %i, c->error = %i",
+ ev->eof, ev->error, c->error);
+
+ count = call_sv(cb, G_VOID|G_SCALAR);
+
+ if (count != 1) {
+ ngx_log_error(NGX_LOG_ERR, c->log, 0,
+ "ngx_perl_read_handler: "
+ "call_sv returned wrong count = %i",
+ count);
+ }
+
+ SPAGAIN;
+ cmd = POPi;
+ PUTBACK;
+
+ FREETMPS;
+ LEAVE;
+
+ SvREFCNT_dec(cb);
+ errno = 0;
+
+ if ((ev->error || c->error) && cmd != NGX_PERL_CLOSE) {
+ ngx_log_error(NGX_LOG_ERR, c->log, 0,
+ "ngx_perl_read_handler: "
+ "NGX_CLOSE required on error, forcing");
+ ngx_perl_close(c);
+ return;
+ }
+
+ switch (cmd) {
+ case NGX_PERL_CLOSE:
+ ngx_perl_close(c);
+ break;
+ case NGX_PERL_READ:
+ ngx_perl_read(c);
+ if (c->read->ready) {
+ goto AGAIN;
+ }
+ break;
+ case NGX_PERL_WRITE:
+ ngx_perl_write(c);
+ if (c->write->ready) {
+ c->write->handler(c->write);
+ }
+ break;
+ case NGX_PERL_NOOP:
+ ngx_perl_noop(c);
+ break;
+ }
+
+ return;
+}
+
+
+static void
+ngx_perl_write_handler(ngx_event_t *ev)
+{
+ ssize_t n;
+ ngx_connection_t *c;
+ ngx_perl_connection_t *plc;
+ SV *sv, *cb;
+ ngx_int_t cmd, count;
+ dSP;
+
+ c = (ngx_connection_t *) ev->data;
+ plc = (ngx_perl_connection_t *) c->data;
+
+ if (ev->timer_set) {
+ ngx_del_timer(ev);
+ }
+
+ if (ev->timedout) {
+ errno = NGX_PERL_ETIMEDOUT;
+ goto CALLBACK;
+ }
+
+AGAIN:
+
+ if (ev->error || c->error) {
+ errno = NGX_PERL_EBADE;
+ goto CALLBACK;
+ }
+
+ sv = plc->write_buffer;
+
+ for ( ;; ) {
+
+ ngx_socket_errno = 0;
+
+ n = c->send(c, (u_char *) SvPV_nolen (sv) + plc->write_offset,
+ SvCUR (sv) - plc->write_offset);
+
+ if (n == NGX_AGAIN) {
+
+ if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
+ errno = NGX_PERL_EBADE;
+ goto CALLBACK;
+ }
+
+ return;
+ }
+
+ if (n == 0) {
+ errno = NGX_PERL_EOF;
+ goto CALLBACK;
+ }
+
+ if (n == NGX_ERROR) {
+ errno = ngx_socket_errno ? ngx_socket_errno : NGX_PERL_EBADE;
+ goto CALLBACK;
+ }
+
+ plc->write_offset += n;
+
+ if (SvCUR(sv) - plc->write_offset > 0) {
+ continue;
+ }
+
+ break;
+ }
+
+ errno = 0;
+
+CALLBACK:
+
+ plc->write_offset = 0;
+
+ cb = plc->write_cb;
+
+ SvREFCNT_inc(cb);
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK(SP);
+ XPUSHs(sv_2mortal(newSViv(PTR2IV(c))));
+ PUTBACK;
+
+ count = call_sv(cb, G_VOID|G_SCALAR);
+
+ if (count != 1) {
+ ngx_log_error(NGX_LOG_ERR, c->log, 0,
+ "ngx_perl_write_handler: "
+ "call_sv returned wrong count = %i",
+ count);
+ }
+
+ SPAGAIN;
+ cmd = POPi;
+ PUTBACK;
+
+ FREETMPS;
+ LEAVE;
+
+ SvREFCNT_dec(cb);
+ errno = 0;
+
+ if ((ev->error || c->error) && cmd != NGX_PERL_CLOSE) {
+ ngx_log_error(NGX_LOG_ERR, c->log, 0,
+ "ngx_perl_write_handler: "
+ "NGX_CLOSE required on error, forcing");
+ ngx_perl_close(c);
+ return;
+ }
+
+ switch (cmd) {
+ case NGX_PERL_CLOSE:
+ ngx_perl_close(c);
+ break;
+ case NGX_PERL_READ:
+ ngx_perl_read(c);
+ break;
+ case NGX_PERL_WRITE:
+ ngx_perl_write(c);
+ if (c->write->ready) {
+ goto AGAIN;
+ }
+ break;
+ case NGX_PERL_NOOP:
+ ngx_perl_noop(c);
+ break;
+ }
+
+ return;
+}
+
+
diff --git a/src/http/modules/perl/ngx_http_perl_module.h b/src/http/modules/perl/ngx_http_perl_module.h
--- a/src/http/modules/perl/ngx_http_perl_module.h
+++ b/src/http/modules/perl/ngx_http_perl_module.h
@@ -51,8 +51,8 @@
* when building with perl 5.6.1
*/
#ifndef PERL_IMPLICIT_CONTEXT
-#undef dTHXa
-#define dTHXa(a)
+# undef dTHXa
+# define dTHXa(a)
#endif
@@ -63,4 +63,55 @@
void ngx_http_perl_sleep_handler(ngx_http_request_t *r);
+
+typedef struct {
+ ngx_int_t after;
+ SV *repeat;
+ SV *cb;
+} ngx_perl_timer_t;
+
+ngx_connection_t *ngx_perl_timer(ngx_int_t after, SV *repeat, SV *cb);
+void ngx_perl_timer_clear(ngx_connection_t *c);
+
+
+#define NGX_PERL_NOOP 0
+#define NGX_PERL_READ 1
+#define NGX_PERL_WRITE 2
+#define NGX_PERL_CONNECT 4
+#define NGX_PERL_CLOSE 8
+
+#ifndef EBADE
+# define EBADE 52
+#endif
+
+#define NGX_PERL_EOF 42 /* ENOMSG */
+#define NGX_PERL_EINVAL EINVAL
+#define NGX_PERL_ENOMEM ENOMEM
+#define NGX_PERL_EBADE EBADE
+#define NGX_PERL_EBADF EBADF
+#define NGX_PERL_ETIMEDOUT ETIMEDOUT
+
+typedef struct {
+ SV *connect_cb;
+ SV *read_buffer;
+ SV *read_min;
+ SV *read_max;
+ SV *read_timeout;
+ SV *read_cb;
+ SV *write_buffer;
+ ssize_t write_offset;
+ SV *write_timeout;
+ SV *write_cb;
+} ngx_perl_connection_t;
+
+void ngx_perl_connector(SV *address, SV *port, SV *timeout, SV *cb);
+void ngx_perl_writer(ngx_connection_t *c, SV *buf, SV *timeout, SV *cb);
+void ngx_perl_reader(ngx_connection_t *c, SV *buf, SV *min, SV *max,
+ SV *timeout, SV *cb);
+void ngx_perl_close(ngx_connection_t *c);
+void ngx_perl_read(ngx_connection_t *c);
+void ngx_perl_write(ngx_connection_t *c);
+void ngx_perl_noop(ngx_connection_t *c);
+
+
#endif /* _NGX_HTTP_PERL_MODULE_H_INCLUDED_ */
Подробная информация о списке рассылки nginx-ru