EV-Websockets
view release on metacpan or search on metacpan
Websockets.xs view on Meta::CPAN
MODULE = EV::Websockets PACKAGE = EV::Websockets
BOOT:
{
I_EV_API("EV::Websockets");
lws_set_log_level(LLL_ERR | LLL_WARN, NULL);
}
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;
if (ssl_init == -1)
ssl_init = ev_ws_ssl_inited ? 0 : 1;
info.options = ssl_init ? LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT : 0;
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");
}
if (ssl_init)
ev_ws_ssl_inited = 1;
ev_timer_init(&RETVAL->timer, timer_cb, 0.00001, 0.);
RETVAL->timer.data = (void*)RETVAL;
ev_idle_init(&RETVAL->idle, idle_cb);
RETVAL->idle.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);
ev_idle_stop(self->loop, &self->idle);
free_all_fd_watchers(self);
/* 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 */
}
self->connections = NULL;
if (self->lws_ctx) {
lws_context_destroy(self->lws_ctx);
self->lws_ctx = NULL;
}
Websockets.xs view on Meta::CPAN
headers_hv = val;
} else if (strcmp(key, "on_connect") == 0 && SvROK(val) && SvTYPE(SvRV(val)) == SVt_PVCV) {
on_connect = SvREFCNT_inc(val);
} else if (strcmp(key, "on_message") == 0 && SvROK(val) && SvTYPE(SvRV(val)) == SVt_PVCV) {
on_message = SvREFCNT_inc(val);
} else if (strcmp(key, "on_close") == 0 && SvROK(val) && SvTYPE(SvRV(val)) == SVt_PVCV) {
on_close = SvREFCNT_inc(val);
} else if (strcmp(key, "on_error") == 0 && SvROK(val) && SvTYPE(SvRV(val)) == SVt_PVCV) {
on_error = SvREFCNT_inc(val);
} else if (strcmp(key, "on_pong") == 0 && SvROK(val) && SvTYPE(SvRV(val)) == SVt_PVCV) {
on_pong = SvREFCNT_inc(val);
} 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);
}
}
if (strcmp(name, "default") == 0) {
if (on_connect) SvREFCNT_dec(on_connect);
if (on_message) SvREFCNT_dec(on_message);
if (on_close) SvREFCNT_dec(on_close);
if (on_error) SvREFCNT_dec(on_error);
if (on_pong) SvREFCNT_dec(on_pong);
if (on_drain) SvREFCNT_dec(on_drain);
if (on_handshake) SvREFCNT_dec(on_handshake);
croak("listen: vhost name 'default' is reserved");
}
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_key) {
info.ssl_cert_filepath = ssl_cert;
info.ssl_private_key_filepath = ssl_key;
if (ssl_ca)
info.ssl_ca_filepath = ssl_ca;
info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
}
vh = lws_create_vhost(self->lws_ctx, &info);
if (vh == NULL) {
if (on_connect) SvREFCNT_dec(on_connect);
if (on_message) SvREFCNT_dec(on_message);
if (on_close) SvREFCNT_dec(on_close);
if (on_error) SvREFCNT_dec(on_error);
if (on_pong) SvREFCNT_dec(on_pong);
if (on_drain) SvREFCNT_dec(on_drain);
if (on_handshake) SvREFCNT_dec(on_handshake);
if (srv->response_headers) SvREFCNT_dec((SV*)srv->response_headers);
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 SV refs now.
Do NOT Safefree(srv) â the vhost retains the pointer.
PROTOCOL_DESTROY will Safefree(srv) on context teardown;
SRV_FREED sentinel tells it to skip SvREFCNT_dec. */
if (srv->on_connect) { SvREFCNT_dec(srv->on_connect); srv->on_connect = NULL; }
if (srv->on_message) { SvREFCNT_dec(srv->on_message); srv->on_message = NULL; }
if (srv->on_close) { SvREFCNT_dec(srv->on_close); srv->on_close = NULL; }
if (srv->on_error) { SvREFCNT_dec(srv->on_error); srv->on_error = NULL; }
if (srv->on_pong) { SvREFCNT_dec(srv->on_pong); srv->on_pong = NULL; }
if (srv->on_drain) { SvREFCNT_dec(srv->on_drain); srv->on_drain = NULL; }
if (srv->on_handshake) { SvREFCNT_dec(srv->on_handshake); srv->on_handshake = NULL; }
if (srv->response_headers) { SvREFCNT_dec((SV*)srv->response_headers); srv->response_headers = NULL; }
if (srv->protocol_name) {
Safefree(srv->protocol_name); srv->protocol_name = NULL;
}
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:
( run in 2.295 seconds using v1.01-cache-2.11-cpan-0bb4e1dffa6 )