Chandra
view release on metacpan or search on metacpan
xs/socket_connection.xs view on Meta::CPAN
SvREFCNT_dec(json_sv);
}
OUTPUT:
RETVAL
void
decode_frames(class, data_sv)
SV *class
SV *data_sv
PPCODE:
{
AV *result = newAV();
I32 ri, result_count;
if (SvOK(data_sv)) {
const char *buf;
STRLEN buf_len;
STRLEN consumed = 0;
buf = SvPV(data_sv, buf_len);
while (buf_len - consumed >= 4) {
const unsigned char *p =
(const unsigned char *)(buf + consumed);
UV frame_len = ((UV)p[0] << 24) | ((UV)p[1] << 16) |
((UV)p[2] << 8) | (UV)p[3];
if (buf_len - consumed < 4 + frame_len) break;
/* JSON decode payload */
{
SV *msg_sv = NULL;
dSP;
int count;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSVpvn(
buf + consumed + 4, frame_len)));
PUTBACK;
count = call_pv(
"Chandra::Socket::Connection::_xs_json_decode",
G_SCALAR);
SPAGAIN;
if (count > 0) msg_sv = newSVsv(POPs);
PUTBACK;
FREETMPS;
LEAVE;
if (msg_sv && SvOK(msg_sv)) {
av_push(result, msg_sv);
} else {
if (msg_sv) SvREFCNT_dec(msg_sv);
}
}
consumed += 4 + frame_len;
}
}
/* Push all decoded messages onto Perl stack */
result_count = av_len(result) + 1;
for (ri = 0; ri < result_count; ri++) {
SV **svp = av_fetch(result, ri, 0);
if (svp) XPUSHs(sv_2mortal(SvREFCNT_inc(*svp)));
}
SvREFCNT_dec((SV *)result);
}
int
_xs_do_send(socket_sv, msg_sv)
SV *socket_sv
SV *msg_sv
CODE:
{
SV *json_enc = get_sv("Chandra::Socket::Connection::_xs_json", 0);
SV *payload = NULL;
STRLEN payload_len, frame_len;
unsigned char len_buf[4];
SV *frame;
/* $payload = $_xs_json->encode($msg) */
{
dSP;
int count;
ENTER; SAVETMPS;
PUSHMARK(SP);
XPUSHs(json_enc);
XPUSHs(msg_sv);
PUTBACK;
count = call_method("encode", G_SCALAR);
SPAGAIN;
payload = (count > 0) ? newSVsv(POPs) : newSVpvs("");
PUTBACK;
FREETMPS; LEAVE;
}
payload_len = SvCUR(payload);
/* pack('N', length) . payload - build frame in C */
len_buf[0] = (payload_len >> 24) & 0xFF;
len_buf[1] = (payload_len >> 16) & 0xFF;
len_buf[2] = (payload_len >> 8) & 0xFF;
len_buf[3] = payload_len & 0xFF;
frame = newSVpvn((char *)len_buf, 4);
sv_catsv(frame, payload);
SvREFCNT_dec(payload);
frame_len = SvCUR(frame);
/* Ignore SIGPIPE during syswrite - portable across OS */
{
SigpipeGuard spg;
SV *written_sv;
sigpipe_ignore(&spg);
/* $socket->syswrite($frame) */
{
dSP;
int count;
ENTER; SAVETMPS;
xs/socket_connection.xs view on Meta::CPAN
}
} else if (!SvOK(read_result)) {
/* Check errno for EAGAIN/EWOULDBLOCK */
int err_no = errno;
#ifdef EAGAIN
if (err_no == EAGAIN) { PUTBACK; FREETMPS; LEAVE; SvREFCNT_dec(read_buf); goto parse_frames; }
#endif
#ifdef EWOULDBLOCK
if (err_no == EWOULDBLOCK) { PUTBACK; FREETMPS; LEAVE; SvREFCNT_dec(read_buf); goto parse_frames; }
#endif
(void)hv_stores(hv, "_connected", newSViv(0));
SvREFCNT_dec(read_buf);
PUTBACK; FREETMPS; LEAVE;
goto return_messages;
} else if (SvIV(read_result) == 0) {
(void)hv_stores(hv, "_connected", newSViv(0));
SvREFCNT_dec(read_buf);
PUTBACK; FREETMPS; LEAVE;
goto return_messages;
}
PUTBACK; FREETMPS; LEAVE;
}
SvREFCNT_dec(read_buf);
}
parse_frames:
/* Parse length-prefixed frames from buffer */
buf_svp = hv_fetchs(hv, "_buf", 0);
if (buf_svp && SvOK(*buf_svp)) {
SV *json_enc = get_sv("Chandra::Socket::Connection::_xs_json", 0);
while (SvCUR(*buf_svp) >= 4) {
const unsigned char *p = (const unsigned char *)SvPVX(*buf_svp);
UV frame_len = ((UV)p[0] << 24) | ((UV)p[1] << 16) |
((UV)p[2] << 8) | (UV)p[3];
if (frame_len > 16 * 1024 * 1024) {
warn("Chandra::Socket::Connection: frame too large (%" UVuf " bytes), disconnecting\n", frame_len);
(void)hv_stores(hv, "_connected", newSViv(0));
(void)hv_stores(hv, "_buf", newSVpvs(""));
goto return_messages;
}
if (SvCUR(*buf_svp) < 4 + frame_len) break;
/* Extract payload and advance buffer */
{
SV *payload = newSVpvn(SvPVX(*buf_svp) + 4, (STRLEN)frame_len);
SV *remaining = newSVpvn(
SvPVX(*buf_svp) + 4 + frame_len,
SvCUR(*buf_svp) - 4 - (STRLEN)frame_len);
sv_setsv(*buf_svp, remaining);
SvREFCNT_dec(remaining);
/* JSON decode */
{
dSP;
int count;
SV *decoded;
ENTER; SAVETMPS;
PUSHMARK(SP);
XPUSHs(json_enc);
XPUSHs(payload);
PUTBACK;
count = call_method("decode", G_SCALAR | G_EVAL);
SPAGAIN;
if (count > 0 && !SvTRUE(ERRSV)) {
decoded = newSVsv(POPs);
av_push(messages, decoded);
} else {
warn("Chandra::Socket::Connection: malformed JSON frame\n");
if (SvTRUE(ERRSV)) sv_setpvs(ERRSV, "");
}
PUTBACK;
FREETMPS; LEAVE;
}
SvREFCNT_dec(payload);
}
}
}
return_messages:
msg_count = av_len(messages) + 1;
for (mi = 0; mi < msg_count; mi++) {
SV **svp = av_fetch(messages, mi, 0);
if (svp) XPUSHs(sv_2mortal(SvREFCNT_inc(*svp)));
}
SvREFCNT_dec((SV *)messages);
}
SV *
_xs_json_encode(data_sv)
SV *data_sv
CODE:
{
SV *json_enc = get_sv("Chandra::Socket::Connection::_xs_json", 0);
dSP;
int count;
ENTER; SAVETMPS;
PUSHMARK(SP);
XPUSHs(json_enc);
XPUSHs(data_sv);
PUTBACK;
count = call_method("encode", G_SCALAR);
SPAGAIN;
RETVAL = (count > 0) ? newSVsv(POPs) : newSVpvs("");
PUTBACK;
FREETMPS; LEAVE;
}
OUTPUT:
RETVAL
SV *
_xs_json_decode(str_sv)
SV *str_sv
CODE:
{
SV *json_enc = get_sv("Chandra::Socket::Connection::_xs_json", 0);
dSP;
int count;
ENTER; SAVETMPS;
PUSHMARK(SP);
XPUSHs(json_enc);
XPUSHs(str_sv);
PUTBACK;
count = call_method("decode", G_SCALAR | G_EVAL);
SPAGAIN;
if (count > 0 && !SvTRUE(ERRSV)) {
( run in 0.423 second using v1.01-cache-2.11-cpan-600a1bdf6e4 )