#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #define NEED_sv_2pvbyte #include "ppport.h" #include #include #include #include #define UV_ERRNO_CONST_GEN(val, name, s) \ newCONSTSUB(stash, #name, newSViv(val)); #define UV_CONST_GEN(uc, lc) \ newCONSTSUB(stash, #uc, newSViv(UV_##uc)); \ newCONSTSUB(stash, "UV_" #uc, newSViv(UV_##uc)); /* Handle wrappers */ typedef struct p5uv_handle_s p5uv_handle_t; typedef struct p5uv_stream_s p5uv_stream_t; typedef struct p5uv_tcp_s p5uv_tcp_t; typedef struct p5uv_udp_s p5uv_udp_t; typedef struct p5uv_pipe_s p5uv_pipe_t; typedef struct p5uv_tty_s p5uv_tty_t; typedef struct p5uv_poll_s p5uv_poll_t; typedef struct p5uv_timer_s p5uv_timer_t; typedef struct p5uv_prepare_s p5uv_prepare_t; typedef struct p5uv_check_s p5uv_check_t; typedef struct p5uv_idle_s p5uv_idle_t; typedef struct p5uv_async_s p5uv_async_t; #define P5UV_HANDLE_FIELDS \ uv_handle_t* handle; \ SV* close_cb; struct p5uv_handle_s { P5UV_HANDLE_FIELDS }; #define P5UV_STREAM_FIELDS \ SV* read_cb; \ SV* write_cb; \ SV* connect_cb; \ SV* connection_cb; \ SV* shutdown_cb; struct p5uv_stream_s { P5UV_HANDLE_FIELDS P5UV_STREAM_FIELDS }; struct p5uv_tcp_s { P5UV_HANDLE_FIELDS P5UV_STREAM_FIELDS }; struct p5uv_udp_s { P5UV_HANDLE_FIELDS SV* send_cb; SV* recv_cb; }; struct p5uv_tty_s { P5UV_HANDLE_FIELDS P5UV_STREAM_FIELDS }; struct p5uv_pipe_s { P5UV_HANDLE_FIELDS P5UV_STREAM_FIELDS }; struct p5uv_poll_s { P5UV_HANDLE_FIELDS SV* cb; }; struct p5uv_prepare_s { P5UV_HANDLE_FIELDS SV* cb; }; struct p5uv_check_s { P5UV_HANDLE_FIELDS SV* cb; }; struct p5uv_idle_s { P5UV_HANDLE_FIELDS SV* cb; }; struct p5uv_async_s { P5UV_HANDLE_FIELDS SV* cb; }; struct p5uv_timer_s { P5UV_HANDLE_FIELDS SV* cb; }; #undef P5UV_HANDLE_FIELDS #undef P5UV_STREAM_FIELDS static p5uv_handle_t* p5uv_handle_init(uv_handle_t* uv_handle) { p5uv_handle_t* p5uv_handle; switch (uv_handle->type) { case UV_TCP: p5uv_handle = (p5uv_handle_t*)calloc(1, sizeof(p5uv_tcp_t)); break; case UV_UDP: p5uv_handle = (p5uv_handle_t*)calloc(1, sizeof(p5uv_udp_t)); break; case UV_TTY: p5uv_handle = (p5uv_handle_t*)calloc(1, sizeof(p5uv_tty_t)); break; case UV_NAMED_PIPE: p5uv_handle = (p5uv_handle_t*)calloc(1, sizeof(p5uv_pipe_t)); break; case UV_POLL: p5uv_handle = (p5uv_handle_t*)calloc(1, sizeof(p5uv_poll_t)); break; case UV_PREPARE: p5uv_handle = (p5uv_handle_t*)calloc(1, sizeof(p5uv_prepare_t)); break; case UV_CHECK: p5uv_handle = (p5uv_handle_t*)calloc(1, sizeof(p5uv_check_t)); break; case UV_IDLE: p5uv_handle = (p5uv_handle_t*)calloc(1, sizeof(p5uv_idle_t)); break; case UV_ASYNC: p5uv_handle = (p5uv_handle_t*)calloc(1, sizeof(p5uv_async_t)); break; case UV_TIMER: p5uv_handle = (p5uv_handle_t*)calloc(1, sizeof(p5uv_timer_t)); break; default: croak("Unknown handle type: %d", uv_handle->type); } if (NULL == p5uv_handle) { croak("cannot allocate handle wrapper"); } return p5uv_handle; } static SV* sv_handle_wrap(uv_handle_t* uv_handle) { SV* sv; HV* hv; hv = (HV*)sv_2mortal((SV*)newHV()); sv = sv_2mortal(newRV_inc((SV*)hv)); sv_bless(sv, gv_stashpv("UV::handle", 1)); sv_magic((SV*)hv, NULL, PERL_MAGIC_ext, NULL, 0); mg_find((SV*)hv, PERL_MAGIC_ext)->mg_obj = (SV*)uv_handle; return sv; } static SV* sv_handle_wrap_init(uv_handle_t* uv_handle) { uv_handle->data = (void*)p5uv_handle_init(uv_handle); return sv_handle_wrap(uv_handle); } static void shutdown_cb(uv_shutdown_t* req, int status) { uv_stream_t* stream = req->handle; p5uv_stream_t* p5stream = (p5uv_stream_t*)stream->data; SV* sv_status; dSP; sv_status = sv_2mortal(newSViv(status)); ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_status); PUTBACK; call_sv(p5stream->shutdown_cb, G_SCALAR); SPAGAIN; PUTBACK; FREETMPS; LEAVE; free(req); } static void close_cb(uv_handle_t* handle) { p5uv_handle_t* p5handle; p5uv_stream_t* p5stream; p5uv_udp_t* p5udp; p5uv_poll_t* p5poll; dSP; p5handle = (p5uv_handle_t*)handle->data; if (p5handle->close_cb) { ENTER; SAVETMPS; PUSHMARK(SP); PUTBACK; call_sv(p5handle->close_cb, G_SCALAR); SPAGAIN; PUTBACK; FREETMPS; LEAVE; SvREFCNT_dec(p5handle->close_cb); } switch (handle->type) { case UV_TCP: case UV_TTY: case UV_NAMED_PIPE: /* stream */ p5stream = (p5uv_stream_t*)p5handle; if (NULL != p5stream->read_cb) SvREFCNT_dec(p5stream->read_cb); if (NULL != p5stream->write_cb) SvREFCNT_dec(p5stream->write_cb); if (NULL != p5stream->connect_cb) SvREFCNT_dec(p5stream->connect_cb); if (NULL != p5stream->connection_cb) SvREFCNT_dec(p5stream->connection_cb); if (NULL != p5stream->shutdown_cb) SvREFCNT_dec(p5stream->shutdown_cb); break; case UV_UDP: p5udp = (p5uv_udp_t*)p5handle; if (NULL != p5udp->send_cb) SvREFCNT_dec(p5udp->send_cb); if (NULL != p5udp->recv_cb) SvREFCNT_dec(p5udp->recv_cb); break; case UV_POLL: case UV_PREPARE: case UV_CHECK: case UV_IDLE: case UV_ASYNC: case UV_TIMER: /* simple cb handles */ p5poll = (p5uv_poll_t*)p5handle; if (NULL != p5poll->cb) SvREFCNT_dec(p5poll->cb); break; default: croak("unknown handle type: %d", handle->type); } free(handle); Safefree(p5handle); } static void poll_cb(uv_poll_t* handle, int status, int events) { SV* sv_status; SV* sv_events; p5uv_poll_t* p5poll = (p5uv_poll_t*)handle->data; dSP; ENTER; SAVETMPS; sv_status = sv_2mortal(newSViv(status)); sv_events = sv_2mortal(newSViv(events)); PUSHMARK(SP); XPUSHs(sv_status); XPUSHs(sv_events); PUTBACK; call_sv(p5poll->cb, G_SCALAR); SPAGAIN; PUTBACK; FREETMPS; LEAVE; } static void connection_cb(uv_stream_t* server, int status) { p5uv_stream_t* p5stream = (p5uv_stream_t*)server->data; dSP; ENTER; SAVETMPS; PUSHMARK(SP); PUTBACK; assert(0 == status); call_sv(p5stream->connection_cb, G_SCALAR); SPAGAIN; PUTBACK; FREETMPS; LEAVE; } static void connect_cb(uv_connect_t* req, int status) { uv_stream_t* stream = req->handle; SV* sv_status; SV* cb; dSP; ENTER; SAVETMPS; sv_status = sv_2mortal(newSViv(status)); PUSHMARK(SP); XPUSHs(sv_status); PUTBACK; cb = ((p5uv_stream_t*)stream->data)->connect_cb; call_sv(cb, G_SCALAR); SPAGAIN; PUTBACK; FREETMPS; LEAVE; Safefree(req); } static uv_buf_t alloc_cb(uv_handle_t* handle, size_t suggested_size) { char* buf; PERL_UNUSED_ARG(handle); buf = (char*)malloc(suggested_size); if (NULL == buf) { croak("cannot allocate buffer"); } return uv_buf_init(buf, suggested_size); } static void read_cb(uv_stream_t* stream, ssize_t nread, uv_buf_t buf) { SV* sv_nread; SV* sv_buf; p5uv_stream_t* p5stream = (p5uv_stream_t*)stream->data; dSP; ENTER; SAVETMPS; sv_nread = sv_2mortal(newSViv(nread)); if (nread > 0) { sv_buf = sv_2mortal(newSVpv(buf.base, nread)); } else { sv_buf = sv_2mortal(newSV(0)); } PUSHMARK(SP); XPUSHs(sv_nread); XPUSHs(sv_buf); PUTBACK; call_sv(p5stream->read_cb, G_SCALAR); SPAGAIN; PUTBACK; FREETMPS; LEAVE; free(buf.base); } static void read2_cb(uv_pipe_t* pipe, ssize_t nread, uv_buf_t buf, uv_handle_type pending) { SV* sv_nread; SV* sv_buf; SV* sv_pending; p5uv_stream_t* p5stream = (p5uv_stream_t*)pipe->data; dSP; ENTER; SAVETMPS; sv_nread = sv_2mortal(newSViv(nread)); if (nread > 0) { sv_buf = sv_2mortal(newSVpv(buf.base, nread)); } else { sv_buf = sv_2mortal(newSV(0)); } sv_pending = sv_2mortal(newSViv(pending)); PUSHMARK(SP); XPUSHs(sv_nread); XPUSHs(sv_buf); XPUSHs(sv_pending); PUTBACK; call_sv(p5stream->read_cb, G_SCALAR); SPAGAIN; PUTBACK; FREETMPS; LEAVE; free(buf.base); } static void write_cb(uv_write_t* req, int status){ uv_stream_t* stream = req->handle; p5uv_stream_t* p5stream = (p5uv_stream_t*)stream->data; SV* sv_status; dSP; if (p5stream->write_cb) { ENTER; SAVETMPS; sv_status = sv_2mortal(newSViv(status)); PUSHMARK(SP); XPUSHs(sv_status); PUTBACK; call_sv(p5stream->write_cb, G_SCALAR); SPAGAIN; PUTBACK; FREETMPS; LEAVE; } Safefree(req); } static void send_cb(uv_udp_send_t* req, int status) { uv_udp_t* udp = req->handle; p5uv_udp_t* p5udp = (p5uv_udp_t*)udp->data; SV* sv_status; dSP; if (p5udp->send_cb) { ENTER; SAVETMPS; sv_status = sv_2mortal(newSViv(status)); PUSHMARK(SP); XPUSHs(sv_status); PUTBACK; call_sv(p5udp->send_cb, G_SCALAR); SPAGAIN; PUTBACK; FREETMPS; LEAVE; } Safefree(req); } static void recv_cb(uv_udp_t* handle, ssize_t nread, uv_buf_t buf, struct sockaddr* addr, unsigned flags) { SV* sv_nread; SV* sv_buf; SV* sv_host; SV* sv_port; SV* sv_flags; struct sockaddr_in* addrin; struct sockaddr_in6* addrin6; char ip[INET6_ADDRSTRLEN]; p5uv_udp_t* p5udp = (p5uv_udp_t*)handle->data; dSP; ENTER; SAVETMPS; sv_nread = sv_2mortal(newSViv(nread)); sv_flags = sv_2mortal(newSViv(flags)); if (nread > 0) { sv_buf = sv_2mortal(newSVpv(buf.base, nread)); } else { sv_buf = sv_2mortal(newSV(0)); } if (NULL != addr) { switch (addr->sa_family) { case AF_INET: addrin = (struct sockaddr_in*)addr; uv_inet_ntop(AF_INET, &addrin->sin_addr, ip, INET6_ADDRSTRLEN); sv_host = sv_2mortal(newSV(0)); sv_setpv(sv_host, ip); sv_port = sv_2mortal(newSViv(ntohs(addrin->sin_port))); break; case AF_INET6: addrin6 = (struct sockaddr_in6*)addr; uv_inet_ntop(AF_INET6, &addrin6->sin6_addr, ip, INET6_ADDRSTRLEN); sv_host = sv_2mortal(newSV(0)); sv_setpv(sv_host, ip); sv_port = sv_2mortal(newSViv(ntohs(addrin6->sin6_port))); break; default: assert(0 && "bad address family"); abort(); } } else { sv_host = sv_2mortal(newSV(0)); sv_port = sv_2mortal(newSV(0)); } PUSHMARK(SP); XPUSHs(sv_nread); XPUSHs(sv_buf); XPUSHs(sv_host); XPUSHs(sv_port); XPUSHs(sv_flags); PUTBACK; call_sv(p5udp->recv_cb, G_SCALAR); SPAGAIN; PUTBACK; FREETMPS; LEAVE; free(buf.base); } static void prepare_cb(uv_prepare_t* handle, int status) { SV* sv_status; p5uv_prepare_t* p5prepare = (p5uv_prepare_t*)handle->data; dSP; sv_status = sv_2mortal(newSViv(status)); ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_status); PUTBACK; call_sv(p5prepare->cb, G_SCALAR); SPAGAIN; PUTBACK; FREETMPS; LEAVE; } static void check_cb(uv_check_t* handle, int status) { SV* sv_status; p5uv_check_t* p5check = (p5uv_check_t*)handle->data; dSP; sv_status = sv_2mortal(newSViv(status)); ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_status); PUTBACK; call_sv(p5check->cb, G_SCALAR); SPAGAIN; PUTBACK; FREETMPS; LEAVE; } static void idle_cb(uv_idle_t* handle, int status) { SV* sv_status; p5uv_idle_t* p5idle = (p5uv_idle_t*)handle->data; dSP; ENTER; SAVETMPS; sv_status = sv_2mortal(newSViv(status)); PUSHMARK(SP); XPUSHs(sv_status); PUTBACK; call_sv(p5idle->cb, G_SCALAR); SPAGAIN; PUTBACK; FREETMPS; LEAVE; } static void async_cb(uv_async_t* handle, int status) { SV* sv_status; p5uv_async_t* p5async = (p5uv_async_t*)handle->data; dSP; ENTER; SAVETMPS; sv_status = sv_2mortal(newSViv(status)); PUSHMARK(SP); XPUSHs(sv_status); PUTBACK; call_sv(p5async->cb, G_SCALAR); SPAGAIN; PUTBACK; FREETMPS; LEAVE; } static void timer_cb(uv_timer_t* handle, int status) { SV* sv_status; p5uv_timer_t* p5timer = (p5uv_timer_t*)handle->data; dSP; ENTER; SAVETMPS; sv_status = sv_2mortal(newSViv(status)); PUSHMARK(SP); XPUSHs(sv_status); PUTBACK; call_sv(p5timer->cb, G_SCALAR); SPAGAIN; PUTBACK; FREETMPS; LEAVE; } static void walk_cb(uv_handle_t* handle, void* arg) { SV* sv_handle = sv_handle_wrap(handle); dSP; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_handle); PUTBACK; call_sv((SV*)arg, G_SCALAR); SPAGAIN; PUTBACK; FREETMPS; LEAVE; } static void getaddrinfo_cb(uv_getaddrinfo_t* handle, int status, struct addrinfo* res) { SV* sv_status; AV* av_res; SV* sv_res; struct addrinfo* address; struct sockaddr_in* in; struct sockaddr_in6* in6; char ip[INET6_ADDRSTRLEN]; SV* sv_ip; dSP; sv_status = sv_2mortal(newSViv(status)); av_res = (AV*)sv_2mortal((SV*)newAV()); sv_res = sv_2mortal(newRV_inc((SV*)av_res)); if (0 == status) { for (address = res; address; address = address->ai_next) { assert(address->ai_socktype == SOCK_STREAM); switch (address->ai_family) { case AF_INET: in = (struct sockaddr_in*)address->ai_addr; uv_inet_ntop(AF_INET, &in->sin_addr, ip, INET6_ADDRSTRLEN); sv_ip = newSV(0); sv_setpv(sv_ip, ip); av_push(av_res, sv_ip); break; case AF_INET6: in6 = (struct sockaddr_in6*)address->ai_addr; uv_inet_ntop(AF_INET6, &in6->sin6_addr, ip, INET6_ADDRSTRLEN); sv_ip = newSV(0); sv_setpv(sv_ip, ip); av_push(av_res, sv_ip); break; } } } ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_status); XPUSHs(sv_res); PUTBACK; call_sv((SV*)handle->data, G_SCALAR); SPAGAIN; PUTBACK; FREETMPS; LEAVE; uv_freeaddrinfo(res); SvREFCNT_dec(handle->data); Safefree(handle); } MODULE=UV PACKAGE=UV PREFIX=uv_ PROTOTYPES: DISABLE BOOT: { HV* stash = gv_stashpv("UV", 1); /* errno */ UV_ERRNO_MAP(UV_ERRNO_CONST_GEN); /* handle type */ UV_HANDLE_TYPE_MAP(UV_CONST_GEN); /* req type */ UV_REQ_TYPE_MAP(UV_CONST_GEN); /* udp */ newCONSTSUB(stash, "UDP_IPV6ONLY", newSViv(UV_UDP_IPV6ONLY)); newCONSTSUB(stash, "UDP_PARTIAL", newSViv(UV_UDP_PARTIAL)); /* udp membership */ newCONSTSUB(stash, "LEAVE_GROUP", newSViv(UV_LEAVE_GROUP)); newCONSTSUB(stash, "JOIN_GROUP", newSViv(UV_JOIN_GROUP)); /* poll */ newCONSTSUB(stash, "READABLE", newSViv(UV_READABLE)); newCONSTSUB(stash, "WRITABLE", newSViv(UV_WRITABLE)); } void uv_default_loop() CODE: { SV* sv; HV* hv; hv = (HV*)sv_2mortal((SV*)newHV()); sv = sv_2mortal(newRV_inc((SV*)hv)); sv_bless(sv, gv_stashpv("UV::loop", 1)); sv_magic((SV*)hv, NULL, PERL_MAGIC_ext, NULL, 0); mg_find((SV*)hv, PERL_MAGIC_ext)->mg_obj = (SV*)uv_default_loop(); ST(0) = sv; XSRETURN(1); } int uv_run() CODE: { RETVAL = uv_run(uv_default_loop()); } OUTPUT: RETVAL int uv_run_once() CODE: { RETVAL = uv_run_once(uv_default_loop()); } OUTPUT: RETVAL void uv_version() CODE: { SV* sv; sv = sv_2mortal(newSV(0)); sv_setpvf(sv, "%d.%d", UV_VERSION_MAJOR, UV_VERSION_MINOR); ST(0) = sv; } int uv_last_error() CODE: { uv_err_t err; err = uv_last_error(uv_default_loop()); RETVAL = err.code; } OUTPUT: RETVAL const char* uv_strerror(int code) CODE: { uv_err_t err; err.code = code; RETVAL = uv_strerror(err); } OUTPUT: RETVAL const char* uv_err_name(int code) CODE: { uv_err_t err; err.code = code; RETVAL = uv_err_name(err); } OUTPUT: RETVAL int uv_shutdown(uv_stream_t* handle, SV* cb) CODE: { uv_shutdown_t* req; p5uv_stream_t* p5stream; Newx(req, 1, uv_shutdown_t); p5stream = (p5uv_stream_t*)handle->data; if (p5stream->shutdown_cb) SvREFCNT_dec(p5stream->shutdown_cb); p5stream->shutdown_cb = SvREFCNT_inc(cb); RETVAL = uv_shutdown(req, handle, shutdown_cb); } OUTPUT: RETVAL int uv_is_active(uv_handle_t* handle) void uv_walk(SV* cb) CODE: { uv_walk(uv_default_loop(), walk_cb, SvREFCNT_inc(cb)); SvREFCNT_dec(cb); } void uv_close(uv_handle_t* handle, SV* cb = NULL) CODE: { p5uv_handle_t* p5handle = (p5uv_handle_t*)handle->data; if (p5handle->close_cb) { SvREFCNT_dec(p5handle->close_cb); p5handle->close_cb = NULL; } if (cb) { p5handle->close_cb = SvREFCNT_inc(cb); } uv_close(handle, close_cb); } NV uv_now() CODE: { /* what's the proper way to return a int64_t? */ RETVAL = (NV) uv_now(uv_default_loop()); } OUTPUT: RETVAL int uv_listen(uv_stream_t* stream, int backlog, SV* cb) CODE: { p5uv_stream_t* p5stream = (p5uv_stream_t*)stream->data; if (p5stream->connection_cb) SvREFCNT_dec(p5stream->connection_cb); p5stream->connection_cb = SvREFCNT_inc(cb); RETVAL = uv_listen(stream, backlog, connection_cb); } OUTPUT: RETVAL int uv_accept(uv_stream_t* server, uv_stream_t* client) int uv_read_start(uv_stream_t* stream, SV* cb) CODE: { p5uv_stream_t* p5stream = (p5uv_stream_t*)stream->data; if (p5stream->read_cb) SvREFCNT_dec(p5stream->read_cb); p5stream->read_cb = SvREFCNT_inc(cb); RETVAL = uv_read_start(stream, alloc_cb, read_cb); } OUTPUT: RETVAL int uv_read_stop(uv_stream_t* stream) int uv_read2_start(uv_stream_t* stream, SV* cb) CODE: { p5uv_stream_t* p5stream = (p5uv_stream_t*)stream; if (p5stream->read_cb) SvREFCNT_dec(p5stream->read_cb); p5stream->read_cb = SvREFCNT_inc(cb); RETVAL = uv_read2_start(stream, alloc_cb, read2_cb); } OUTPUT: RETVAL int uv_write(uv_stream_t* stream, SV* sv_buf, SV* cb = NULL) CODE: { p5uv_stream_t* p5stream = (p5uv_stream_t*)stream->data; char* buf; STRLEN len; uv_write_t* req; uv_buf_t b; if (p5stream->write_cb) { SvREFCNT_dec(p5stream->write_cb); p5stream->write_cb = NULL; } if (cb) p5stream->write_cb = SvREFCNT_inc(cb); Newx(req, 1, uv_write_t); buf = SvPV(sv_buf, len); b = uv_buf_init(buf, len); RETVAL = uv_write(req, stream, &b, 1, write_cb); } OUTPUT: RETVAL int uv_write2(uv_stream_t* stream, SV* sv_buf, uv_stream_t* send_stream, SV* cb = NULL) CODE: { p5uv_stream_t* p5stream = (p5uv_stream_t*)stream->data; char* buf; STRLEN len; uv_write_t* req; uv_buf_t b; if (p5stream->write_cb) { SvREFCNT_dec(p5stream->write_cb); p5stream->write_cb = NULL; } if (cb) p5stream->write_cb = SvREFCNT_inc(cb); Newx(req, 1, uv_write_t); buf = SvPV(sv_buf, len); b = uv_buf_init(buf, len); RETVAL = uv_write2(req, stream, &b, 1, send_stream, write_cb); } OUTPUT: RETVAL int uv_is_readable(uv_stream_t* stream); int uv_is_writable(uv_stream_t* stream); int uv_is_closing(uv_handle_t* handle); void uv_tcp_init() CODE: { uv_tcp_t* tcp; int r; Newx(tcp, 1, uv_tcp_t); r = uv_tcp_init(uv_default_loop(), tcp); if (r) { croak("cannot initialize tcp handle"); } ST(0) = sv_handle_wrap_init((uv_handle_t*)tcp); XSRETURN(1); } int uv_tcp_nodelay(uv_tcp_t* tcp, int enable = 1) int uv_tcp_keepalive(uv_tcp_t* tcp, int enable, unsigned int delay) int uv_tcp_simultaneous_accepts(uv_tcp_t* tcp, int enable) int uv_tcp_bind(uv_tcp_t* tcp, const char* ip, int port) CODE: { RETVAL = uv_tcp_bind(tcp, uv_ip4_addr(ip, port)); } OUTPUT: RETVAL int uv_tcp_bind6(uv_tcp_t* tcp, const char* ip, int port) CODE: { RETVAL = uv_tcp_bind6(tcp, uv_ip6_addr(ip, port)); } OUTPUT: RETVAL void uv_tcp_getsockname(uv_tcp_t* handle) CODE: { int r; struct sockaddr_storage address; struct sockaddr_in* in; struct sockaddr_in6* in6; int addrlen; char ip[INET6_ADDRSTRLEN]; SV* sv_ip; SV* sv_port; addrlen = sizeof(address); r = uv_tcp_getsockname(handle, (struct sockaddr*)&address, &addrlen); assert(0 == r); switch (address.ss_family) { case AF_INET: in = (struct sockaddr_in*)&address; uv_inet_ntop(AF_INET, &in->sin_addr, ip, INET6_ADDRSTRLEN); sv_ip = sv_2mortal(newSV(0)); sv_setpv(sv_ip, ip); sv_port = sv_2mortal(newSViv(ntohs(in->sin_port))); break; case AF_INET6: in6 = (struct sockaddr_in6*)&address; uv_inet_ntop(AF_INET6, &in6->sin6_addr, ip, INET6_ADDRSTRLEN); sv_ip = sv_2mortal(newSV(0)); sv_setpv(sv_ip, ip); sv_port = sv_2mortal(newSViv(htons(in6->sin6_port))); break; default: croak("bad family"); } ST(0) = sv_ip; ST(1) = sv_port; XSRETURN(2); } void uv_tcp_getpeername(uv_tcp_t* handle) CODE: { int r; struct sockaddr_storage address; struct sockaddr_in* in; struct sockaddr_in6* in6; int addrlen; char ip[INET6_ADDRSTRLEN]; SV* sv_ip; SV* sv_port; addrlen = sizeof(address); r = uv_tcp_getpeername(handle, (struct sockaddr*)&address, &addrlen); assert(0 == r); switch (address.ss_family) { case AF_INET: in = (struct sockaddr_in*)&address; uv_inet_ntop(AF_INET, &in->sin_addr, ip, INET6_ADDRSTRLEN); sv_ip = sv_2mortal(newSV(0)); sv_setpv(sv_ip, ip); sv_port = sv_2mortal(newSViv(ntohs(in->sin_port))); break; case AF_INET6: in6 = (struct sockaddr_in6*)&address; uv_inet_ntop(AF_INET6, &in6->sin6_addr, ip, INET6_ADDRSTRLEN); sv_ip = sv_2mortal(newSV(0)); sv_setpv(sv_ip, ip); sv_port = sv_2mortal(newSViv(htons(in6->sin6_port))); break; default: croak("bad family"); } ST(0) = sv_ip; ST(1) = sv_port; XSRETURN(2); } int uv_tcp_connect(uv_tcp_t* tcp, const char* ip, int port, SV* cb) CODE: { uv_connect_t* req; p5uv_tcp_t* p5tcp = (p5uv_tcp_t*)tcp->data; if (p5tcp->connect_cb) SvREFCNT_dec(p5tcp->connect_cb); p5tcp->connect_cb = SvREFCNT_inc(cb); Newx(req, 1, uv_connect_t); RETVAL = uv_tcp_connect(req, tcp, uv_ip4_addr(ip, port), connect_cb); } OUTPUT: RETVAL int uv_tcp_connect6(uv_tcp_t* tcp, const char* ip, int port, SV* cb) CODE: { uv_connect_t* req; p5uv_tcp_t* p5tcp = (p5uv_tcp_t*)tcp->data; if (p5tcp->connect_cb) SvREFCNT_dec(p5tcp->connect_cb); p5tcp->connect_cb = SvREFCNT_inc(cb); Newx(req, 1, uv_connect_t); RETVAL = uv_tcp_connect6(req, tcp, uv_ip6_addr(ip, port), connect_cb); } OUTPUT: RETVAL void uv_udp_init() CODE: { uv_udp_t* udp; int r; Newx(udp, 1, uv_udp_t); r = uv_udp_init(uv_default_loop(), udp); if (r) { croak("cannot initialize udp handle"); } ST(0) = sv_handle_wrap_init((uv_handle_t*)udp); XSRETURN(1); } int uv_udp_bind(uv_udp_t* udp, const char* ip, int port, int flags = 0) CODE: { RETVAL = uv_udp_bind(udp, uv_ip4_addr(ip, port), flags); } OUTPUT: RETVAL int uv_udp_bind6(uv_udp_t* udp, const char* ip, int port, int flags = 0) CODE: { RETVAL = uv_udp_bind6(udp, uv_ip6_addr(ip, port), flags); } OUTPUT: RETVAL void uv_udp_getsockname(uv_udp_t* udp) CODE: { struct sockaddr_storage address; struct sockaddr_in* in; struct sockaddr_in6* in6; char ip[INET6_ADDRSTRLEN]; int addrlen; int r; SV* sv_ip; SV* sv_port; addrlen = sizeof(address); r = uv_udp_getsockname(udp, (struct sockaddr*)&address, &addrlen); assert(0 == r); switch (address.ss_family) { case AF_INET: in = (struct sockaddr_in*)&address; uv_inet_ntop(AF_INET, &in->sin_addr, ip, INET6_ADDRSTRLEN); sv_ip = sv_2mortal(newSV(0)); sv_setpv(sv_ip, ip); sv_port = sv_2mortal(newSViv(ntohs(in->sin_port))); break; case AF_INET6: in6 = (struct sockaddr_in6*)&address; uv_inet_ntop(AF_INET6, &in6->sin6_addr, ip, INET6_ADDRSTRLEN); sv_ip = sv_2mortal(newSV(0)); sv_setpv(sv_ip, ip); sv_port = sv_2mortal(newSViv(ntohs(in6->sin6_port))); break; default: croak("bad address family"); } ST(0) = sv_ip; ST(1) = sv_port; XSRETURN(2); } int uv_udp_set_membership(uv_udp_t* udp, const char* multicast_addr, const char* interface_addr, int membership) int uv_udp_set_multicast_loop(uv_udp_t* udp, int on); int uv_udp_set_multicast_ttl(uv_udp_t* udp, int ttl); int uv_udp_set_broadcast(uv_udp_t* udp, int on); int uv_udp_set_ttl(uv_udp_t* udp, int ttl); int uv_udp_send(uv_udp_t* udp, SV* sv_buf, const char* ip, int port, SV* cb = NULL) CODE: { p5uv_udp_t* p5udp = (p5uv_udp_t*)udp->data; char* buf; STRLEN len; uv_udp_send_t* req; uv_buf_t b; if (p5udp->send_cb) { SvREFCNT_dec(p5udp->send_cb); p5udp->send_cb = NULL; } if (cb) { p5udp->send_cb = SvREFCNT_inc(cb); } Newx(req, 1, uv_udp_send_t); buf = SvPV(sv_buf, len); b = uv_buf_init(buf, len); RETVAL = uv_udp_send(req, udp, &b, 1, uv_ip4_addr(ip, port), send_cb); } OUTPUT: RETVAL int uv_udp_send6(uv_udp_t* udp, SV* sv_buf, const char* ip, int port, SV* cb = NULL) CODE: { p5uv_udp_t* p5udp = (p5uv_udp_t*)udp->data; char* buf; STRLEN len; uv_udp_send_t* req; uv_buf_t b; if (p5udp->send_cb) { SvREFCNT_dec(p5udp->send_cb); p5udp->send_cb = NULL; } if (cb) { p5udp->send_cb = SvREFCNT_inc(cb); } Newx(req, 1, uv_udp_send_t); buf = SvPV(sv_buf, len); b = uv_buf_init(buf, len); RETVAL = uv_udp_send6(req, udp, &b, 1, uv_ip6_addr(ip, port), send_cb); } OUTPUT: RETVAL int uv_udp_recv_start(uv_udp_t* udp, SV* cb) CODE: { p5uv_udp_t* p5udp = (p5uv_udp_t*)udp->data; if (p5udp->recv_cb) SvREFCNT_dec(p5udp->recv_cb); p5udp->recv_cb = SvREFCNT_inc(cb); RETVAL = uv_udp_recv_start(udp, alloc_cb, recv_cb); } OUTPUT: RETVAL int uv_udp_recv_stop(uv_udp_t* udp) void uv_tty_init(int fd, int readable) CODE: { uv_tty_t* tty; int r; Newx(tty, 1, uv_tty_t); r = uv_tty_init(uv_default_loop(), tty, fd, readable); if (r) { croak("cannot initialize tty handle"); } ST(0) = sv_handle_wrap_init((uv_handle_t*)tty); XSRETURN(1); } int uv_tty_set_mode(uv_tty_t* tty, int mode) void uv_tty_reset_mode() void uv_tty_get_winsize(uv_tty_t* tty) CODE: { int width, height; int r; SV* sv_width; SV* sv_height; r = uv_tty_get_winsize(tty, &width, &height); assert(0 == r); sv_width = sv_2mortal(newSViv(width)); sv_height = sv_2mortal(newSViv(height)); ST(0) = sv_width; ST(1) = sv_height; XSRETURN(2); } void uv_poll_init(int fd) CODE: { uv_poll_t* poll; int r; Newx(poll, 1, uv_poll_t); r = uv_poll_init(uv_default_loop(), poll, fd); if (r) { croak("cannot initialize poll handle"); } ST(0) = sv_handle_wrap_init((uv_handle_t*)poll); XSRETURN(1); } int uv_poll_start(uv_poll_t* handle, int events, SV* cb) CODE: { p5uv_poll_t* p5poll = (p5uv_poll_t*)handle->data; if (p5poll->cb) SvREFCNT_dec(p5poll->cb); p5poll->cb = SvREFCNT_inc(cb); RETVAL = uv_poll_start(handle, events, poll_cb); } OUTPUT: RETVAL int uv_poll_stop(uv_poll_t* handle) int uv_guess_handle(int fd) void uv_pipe_init(int ipc) CODE: { uv_pipe_t* pipe; int r; Newx(pipe, 1, uv_pipe_t); r = uv_pipe_init(uv_default_loop(), pipe, ipc); if (r) { croak("cannot initialize pipe handle"); } ST(0) = sv_handle_wrap_init((uv_handle_t*)pipe); XSRETURN(1); } void uv_pipe_open(uv_pipe_t* pipe, int fd) int uv_pipe_bind(uv_pipe_t* pipe, const char* name) void uv_pipe_connect(uv_pipe_t* pipe, const char* name, SV* cb) CODE: { uv_connect_t* req; p5uv_pipe_t* p5pipe = (p5uv_pipe_t*)pipe->data; if (p5pipe->connect_cb) SvREFCNT_dec(p5pipe->connect_cb); p5pipe->connect_cb = SvREFCNT_inc(cb); Newx(req, 1, uv_connect_t); uv_pipe_connect(req, pipe, name, connect_cb); } void uv_prepare_init() CODE: { uv_prepare_t* prepare; int r; Newx(prepare, 1, uv_prepare_t); r = uv_prepare_init(uv_default_loop(), prepare); if (r) { croak("cannot initialize prepare handle"); } ST(0) = sv_handle_wrap_init((uv_handle_t*)prepare); XSRETURN(1); } int uv_prepare_start(uv_prepare_t* prepare, SV* cb) CODE: { p5uv_prepare_t* p5prepare = (p5uv_prepare_t*)prepare->data; if (p5prepare->cb) SvREFCNT_dec(p5prepare->cb); p5prepare->cb = SvREFCNT_inc(cb); RETVAL = uv_prepare_start(prepare, prepare_cb); } OUTPUT: RETVAL int uv_prepare_stop(uv_prepare_t* prepare) void uv_check_init() CODE: { uv_check_t* check; int r; Newx(check, 1, uv_check_t); r = uv_check_init(uv_default_loop(), check); if (r) { croak("cannot initialize check handle"); } ST(0) = sv_handle_wrap_init((uv_handle_t*)check); XSRETURN(1); } int uv_check_start(uv_check_t* check, SV* cb) CODE: { p5uv_check_t* p5check = (p5uv_check_t*)check->data; if (p5check->cb) SvREFCNT_dec(p5check->cb); p5check->cb = SvREFCNT_inc(cb); RETVAL = uv_check_start(check, check_cb); } OUTPUT: RETVAL int uv_check_stop(uv_check_t* check) void uv_idle_init() CODE: { uv_idle_t* idle; int r; Newx(idle, 1, uv_idle_t); r = uv_idle_init(uv_default_loop(), idle); if (r) { croak("cannot initialize idle handle"); } ST(0) = sv_handle_wrap_init((uv_handle_t*)idle); XSRETURN(1); } int uv_idle_start(uv_idle_t* idle, SV* cb) CODE: { p5uv_idle_t* p5idle = (p5uv_idle_t*)idle->data; if (p5idle->cb) SvREFCNT_dec(p5idle->cb); p5idle->cb = SvREFCNT_inc(cb); RETVAL = uv_idle_start(idle, idle_cb); } OUTPUT: RETVAL int uv_idle_stop(uv_idle_t* idle) void uv_async_init(SV* cb) CODE: { SV* sv_async; uv_async_t* async; p5uv_async_t* p5async; int r; Newx(async, 1, uv_async_t); r = uv_async_init(uv_default_loop(), async, async_cb); if (r) { croak("cannot initialize async handle"); } sv_async = sv_handle_wrap_init((uv_handle_t*)async); p5async = (p5uv_async_t*)async->data; p5async->cb = SvREFCNT_inc(cb); ST(0) = sv_async; XSRETURN(1); } int uv_async_send(uv_async_t* async) void uv_timer_init() CODE: { uv_timer_t* timer; int r; Newx(timer, 1, uv_timer_t); r = uv_timer_init(uv_default_loop(), timer); if (r) { croak("cannot initialize timer handle"); } ST(0) = sv_handle_wrap_init((uv_handle_t*)timer); XSRETURN(1); } int uv_timer_start(uv_timer_t* timer, double timeout, double repeat, SV* cb) CODE: { p5uv_timer_t* p5timer = (p5uv_timer_t*)timer->data; if (p5timer->cb) SvREFCNT_dec(p5timer->cb); p5timer->cb = SvREFCNT_inc(cb); RETVAL = uv_timer_start(timer, timer_cb, (int64_t)timeout, (int64_t)repeat); } OUTPUT: RETVAL int uv_timer_stop(uv_timer_t* timer) int uv_timer_again(uv_timer_t* timer) void uv_timer_set_repeat(uv_timer_t* timer, double repeat) CODE: { uv_timer_set_repeat(timer, (int64_t)repeat); } double uv_timer_get_repeat(uv_timer_t* timer) CODE: { RETVAL = (double)uv_timer_get_repeat(timer); } OUTPUT: RETVAL int uv_getaddrinfo(const char* node, SV* sv_service, SV* cb, int hint = 0) CODE: { uv_getaddrinfo_t* handle; struct addrinfo hints; int fam; char* service = NULL; if (SvPOK(sv_service)) { service = SvPV_nolen(sv_service); } fam = AF_UNSPEC; switch (hint) { case 4: fam = AF_INET; break; case 6: fam = AF_INET6; break; } Newx(handle, 1, uv_getaddrinfo_t); handle->data = (void*)SvREFCNT_inc(cb); memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = fam; hints.ai_socktype = SOCK_STREAM; RETVAL = uv_getaddrinfo(uv_default_loop(), handle, getaddrinfo_cb, node, service, &hints); } OUTPUT: RETVAL MODULE=UV PACKAGE=UV::loop unsigned int active_handles(SV* sv_loop) CODE: { MAGIC* m; if (!SvROK(sv_loop)) { croak("Usage: UV::default_loop->active_handles"); } m = mg_find(SvRV(sv_loop), PERL_MAGIC_ext); if (!m) { croak("invalid UV::loop object"); } uv_loop_t* loop = (uv_loop_t*)m->mg_obj; RETVAL = loop->active_handles; } OUTPUT: RETVAL MODULE=UV PACKAGE=UV::handle int type(uv_handle_t* handle) CODE: { RETVAL = handle->type; } OUTPUT: RETVAL