EV-Websockets
view release on metacpan or search on metacpan
Websockets.xs view on Meta::CPAN
void
_set_debug(int enable);
CODE:
{
ev_ws_debug = enable;
if (enable)
lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_INFO | LLL_DEBUG, NULL);
else
lws_set_log_level(LLL_ERR | LLL_WARN, NULL);
}
MODULE = EV::Websockets PACKAGE = EV::Websockets::Context
EV::Websockets::Context
_new(char* class, EV::Loop loop, const char* proxy = NULL, int proxy_port = 0, const char* ssl_cert = NULL, const char* ssl_key = NULL, const char* ssl_ca = NULL, int ssl_init = -1);
CODE:
{
struct lws_context_creation_info info;
void* foreign_loops[1];
PERL_UNUSED_VAR(class);
Newxz(RETVAL, 1, ev_ws_ctx_t);
RETVAL->magic = EV_WS_CTX_MAGIC;
RETVAL->refcnt = 1; /* Perl owns the context */
RETVAL->loop = loop;
foreign_loops[0] = loop;
memset(&info, 0, sizeof(info));
info.port = CONTEXT_PORT_NO_LISTEN;
info.protocols = protocols;
#ifdef LWS_HAS_EXTENSIONS
info.extensions = extensions;
#endif
info.gid = -1;
info.uid = -1;
/* ssl_init: -1 = manage OpenSSL init (default); 1 = force; 0 = coexist
(leave it to another TLS library). When we manage it, flag this context
so its own TLS works, and also pin the global init in a process-lifetime
keepalive so destroying this context can't drop lws's TLS refcount to
zero (which would run OPENSSL_cleanup() and break later TLS use). */
info.options = 0;
if (ssl_init != 0) {
info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
ensure_ssl_keepalive();
}
info.user = RETVAL;
info.foreign_loops = foreign_loops;
info.vhost_name = "default";
if (proxy && strlen(proxy) > 0) {
DEBUG_LOG("Context using proxy: %s:%d", proxy, proxy_port);
info.http_proxy_address = proxy;
info.http_proxy_port = proxy_port;
}
if (ssl_cert && strlen(ssl_cert) > 0) {
info.ssl_cert_filepath = ssl_cert;
info.ssl_private_key_filepath = ssl_key;
if (ssl_ca && strlen(ssl_ca) > 0)
info.ssl_ca_filepath = ssl_ca;
}
DEBUG_LOG("Creating context (manual integration)");
RETVAL->lws_ctx = lws_create_context(&info);
if (RETVAL->lws_ctx == NULL) {
Safefree(RETVAL);
croak("Failed to create libwebsockets context");
}
ev_timer_init(&RETVAL->timer, timer_cb, 0.00001, 0.);
RETVAL->timer.data = (void*)RETVAL;
schedule_timeout(RETVAL);
DEBUG_LOG("Context created successfully");
}
OUTPUT:
RETVAL
void
DESTROY(EV::Websockets::Context self);
CODE:
{
ev_ws_conn_t* conn;
ev_ws_conn_t* next;
if (self->magic != EV_WS_CTX_MAGIC) return;
self->magic = EV_WS_CTX_FREED;
ev_timer_stop(self->loop, &self->timer);
free_all_fd_watchers(self);
/* Release connections still queued for message delivery (no delivery during
teardown); each holds a flush-list ref. They remain in self->connections
and are torn down by the loop below. */
while (self->flush_head) {
conn = self->flush_head;
self->flush_head = conn->flush_next;
conn->on_flush = 0;
conn->flush_next = NULL;
conn_unref(conn); /* release the flush-list ref */
}
self->flush_tail = NULL;
/* Close all connections */
for (conn = self->connections; conn != NULL; conn = next) {
next = conn->next;
conn->ctx = NULL;
conn->prev = NULL;
conn->next = NULL;
if (conn->wsi) {
lws_set_wsi_user(conn->wsi, NULL);
conn->wsi = NULL;
}
conn_unref(conn); /* drop wsi ref â may free conn */
}
Websockets.xs view on Meta::CPAN
} else if (strcmp(key, "on_drain") == 0 && SvROK(val) && SvTYPE(SvRV(val)) == SVt_PVCV) {
on_drain = SvREFCNT_inc(val);
} else if (strcmp(key, "on_handshake") == 0 && SvROK(val) && SvTYPE(SvRV(val)) == SVt_PVCV) {
on_handshake = SvREFCNT_inc(val);
}
}
/* An undef string option used to stringify to "" (with an "uninitialized
value" warning), e.g. name => undef silently created a vhost named "". */
if (undef_opt) {
free_cb_svs(on_connect, on_message, on_close, on_error, on_pong, on_drain, on_handshake);
croak("listen: option '%s' must be a defined string", undef_opt);
}
if (strcmp(name, "default") == 0) {
free_cb_svs(on_connect, on_message, on_close, on_error, on_pong, on_drain, on_handshake);
croak("listen: vhost name 'default' is reserved");
}
/* TLS needs both halves. Accepting just one used to silently create a
PLAINTEXT listener, serving cleartext on a port the caller believes is
encrypted -- fail loudly instead. */
if ((ssl_cert && *ssl_cert) != (ssl_key && *ssl_key)) {
int have_cert = ssl_cert && *ssl_cert;
free_cb_svs(on_connect, on_message, on_close, on_error, on_pong, on_drain, on_handshake);
croak("listen: ssl_cert and ssl_key must both be set for TLS (only %s was given)",
have_cert ? "ssl_cert" : "ssl_key");
}
Newxz(srv, 1, ev_ws_server_t);
srv->magic = EV_WS_SRV_MAGIC;
srv->on_connect = on_connect;
srv->on_message = on_message;
srv->on_close = on_close;
srv->on_error = on_error;
srv->on_pong = on_pong;
srv->on_drain = on_drain;
srv->on_handshake = on_handshake;
srv->max_message_size = max_message_size;
if (headers_hv)
srv->response_headers = (HV*)SvREFCNT_inc(SvRV(headers_hv));
if (protocol_name) {
STRLEN pnlen = strlen(protocol_name);
Newx(srv->protocol_name, pnlen + 1, char);
memcpy(srv->protocol_name, protocol_name, pnlen + 1);
srv->vhost_protocols[0] = protocols[0];
srv->vhost_protocols[0].name = srv->protocol_name;
srv->vhost_protocols[1] = protocols[1];
}
memset(&info, 0, sizeof(info));
info.port = port;
info.protocols = srv->protocol_name ? srv->vhost_protocols : protocols;
info.vhost_name = name;
info.user = srv;
info.options = 0;
if (ssl_cert && *ssl_cert && ssl_key && *ssl_key) {
info.ssl_cert_filepath = ssl_cert;
info.ssl_private_key_filepath = ssl_key;
if (ssl_ca && *ssl_ca)
info.ssl_ca_filepath = ssl_ca;
info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
ensure_ssl_keepalive(); /* pin global init so vhost/context teardown won't OPENSSL_cleanup */
}
vh = lws_create_vhost(self->lws_ctx, &info);
if (vh == NULL) {
free_server_svs(srv);
if (srv->protocol_name) Safefree(srv->protocol_name);
Safefree(srv);
croak("Failed to create vhost for listening");
}
RETVAL = lws_get_vhost_listen_port(vh);
if (RETVAL <= 0) {
/* Vhost created but port bind failed. Release the SV refs now, but
leave protocol_name alive â the live vhost still points at it via
vhost_protocols[0].name, so freeing it here would dangle. Do NOT
Safefree(srv): the vhost retains the pointer. PROTOCOL_DESTROY frees
protocol_name and srv at context teardown; the SRV_FREED sentinel
tells it to skip the (already-released) SV refs. */
free_server_svs(srv);
srv->magic = EV_WS_SRV_FREED;
croak("listen: failed to bind port");
}
DEBUG_LOG("Server listening on port %d", RETVAL);
}
OUTPUT:
RETVAL
EV::Websockets::Connection
adopt(EV::Websockets::Context self, ...);
PREINIT:
int fd = -1;
SV* fh_sv = NULL;
SV* initial_data_sv = NULL;
SV* on_connect = NULL;
SV* on_message = NULL;
SV* on_close = NULL;
SV* on_error = NULL;
SV* on_pong = NULL;
SV* on_drain = NULL;
size_t max_message_size = 0;
int i;
CODE:
{
if (self->magic != EV_WS_CTX_MAGIC) {
croak("Context has been destroyed");
}
/* Options are key => value pairs. A dangling key used to be silently
ignored, hiding typos and truncated argument lists. Checked before any
callback SV is retained, so croaking here leaks nothing. */
if (((items - 1) % 2) != 0) {
croak("odd number of options: key '%s' has no value",
SvPV_nolen(ST(items - 1)));
}
for (i = 1; i < items; i += 2) {
( run in 2.736 seconds using v1.01-cache-2.11-cpan-8dfa8b56332 )