EV-Websockets
view release on metacpan or search on metacpan
Websockets.xs view on Meta::CPAN
}
pending_adoption = RETVAL;
if (initial_data_sv && SvOK(initial_data_sv)) {
STRLEN rdlen;
const char *rdbuf = SvPV(initial_data_sv, rdlen);
RETVAL->wsi = lws_adopt_socket_vhost_readbuf(vh,
(lws_sockfd_type)fd, rdbuf, rdlen);
} else {
RETVAL->wsi = lws_adopt_socket_vhost(vh, (lws_sockfd_type)fd);
}
pending_adoption = NULL;
}
if (RETVAL->wsi == NULL) {
unlink_conn(RETVAL);
if (RETVAL->perl_self == NULL) {
free_conn_resources(RETVAL);
RETVAL->magic = EV_WS_CONN_FREED;
Safefree(RETVAL);
} else {
conn_unref(RETVAL);
}
croak("Failed to adopt socket");
}
conn_unref(RETVAL); /* drop sentinel */
/* Kick lws to process the adopted socket's readbuf (needed for lws 4.5+).
* Use the same non-blocking forced-service call as do_lws_service: the
* readbuf is pending work, so lws_service_tsi(ctx, -1, 0) drains it without
* blocking. A plain lws_service(ctx, 0) would block the EV loop here when a
* socket is adopted with no immediately-pending data.
* Guard with extra refs: the service call may synchronously fire
* error/destroy callbacks that would free RETVAL or ctx. */
{
int rejected, alive = 1;
int* prev_flag = self->alive_flag;
conn_ref(RETVAL);
ctx_ref(self);
self->alive_flag = &alive;
lws_service_tsi(self->lws_ctx, -1, 0);
if (alive) {
self->alive_flag = prev_flag;
schedule_timeout(self);
} else if (prev_flag) {
/* Context destroyed during inner lws_service.
Propagate destruction up the alive_flag chain. */
*prev_flag = 0;
}
rejected = (RETVAL->wsi == NULL);
conn_unref(RETVAL);
ctx_unref(self);
if (rejected)
croak("Failed to adopt socket");
}
}
OUTPUT:
RETVAL
void
connections(EV::Websockets::Context self);
PPCODE:
{
ev_ws_conn_t* conn;
if (self->magic != EV_WS_CTX_MAGIC) XSRETURN_EMPTY;
for (conn = self->connections; conn != NULL; conn = conn->next) {
/* "connected" stays set during the "closing" drain (close() never
clears it), and is cleared together with wsi on teardown â so this
single predicate covers both the "connected" and "closing" states. */
if (conn->magic == EV_WS_CONN_MAGIC && conn->connected) {
XPUSHs(sv_2mortal(get_conn_sv(conn)));
}
}
}
MODULE = EV::Websockets PACKAGE = EV::Websockets::Connection
void
DESTROY(EV::Websockets::Connection self);
CODE:
{
if (self->magic != EV_WS_CONN_MAGIC) return;
DEBUG_LOG("Perl object DESTROY: self=%p wsi=%p", self, self->wsi);
/* Clear the cached Perl object pointer in the C struct */
self->perl_self = NULL;
conn_unref(self); /* drop Perl ref */
}
void
send(EV::Websockets::Connection self, SV* data);
CODE:
{
STRLEN len;
const char* buf;
CHECK_CONN_OPEN(self);
CHECK_NOT_FRAGMENTING(self);
buf = SvPV(data, len);
queue_send(self, buf, len, LWS_WRITE_TEXT);
}
void
send_binary(EV::Websockets::Connection self, SV* data);
CODE:
{
STRLEN len;
const char* buf;
CHECK_CONN_OPEN(self);
CHECK_NOT_FRAGMENTING(self);
buf = SvPV(data, len);
queue_send(self, buf, len, LWS_WRITE_BINARY);
}
void
send_ping(EV::Websockets::Connection self, SV* data = NULL);
CODE:
( run in 1.908 second using v1.01-cache-2.11-cpan-5511b514fd6 )