// This file is a part of Julia. License is MIT: http://julialang.org/license #include "platform.h" /* * There is no need to define WINVER because it is already defined in Makefile. #if defined(_COMPILER_MINGW_) #define WINVER _WIN32_WINNT #define _WIN32_WINDOWS _WIN32_WINNT #endif */ #include #include #include #include #include #include #ifdef _OS_WINDOWS_ #include #include #else #include "errno.h" #include #include #endif #include "julia.h" #include "julia_internal.h" #include "support/ios.h" #include "uv.h" #if defined(_COMPILER_MICROSOFT_) && !defined(write) #include #define write _write #endif #ifdef __cplusplus #include extern "C" { #endif /** libuv callbacks */ enum CALLBACK_TYPE { CB_PTR, CB_INT32, CB_UINT32, CB_INT64, CB_UINT64 }; #ifdef _P64 #define CB_INT CB_INT64 #define CB_UINT CB_UINT64 #else #define CB_INT CB_INT32 #define CB_UINT CB_UINT32 #endif /* * Notes for adding new callbacks * - Make sure to type annotate the callback, so we'll get the one in the new * Base module rather than the old one. * */ //These callbacks are implemented in stream.jl #define JL_CB_TYPES(XX) \ XX(close) \ XX(return_spawn) \ XX(readcb) \ XX(alloc_buf) \ XX(connectcb) \ XX(connectioncb) \ XX(asynccb) \ XX(getaddrinfo) \ XX(pollcb) \ XX(fspollcb) \ XX(isopen) \ XX(fseventscb) \ XX(writecb_task) \ XX(recv) \ XX(send) //TODO add UDP and other missing callbacks #define JULIA_HOOK_(m,hook) ((jl_function_t*)jl_get_global(m, jl_symbol("_uv_hook_" #hook))) #define JULIA_HOOK(hook) jl_uvhook_##hook #define XX(hook) static jl_function_t *JULIA_HOOK(hook) = 0; JL_CB_TYPES(XX) #undef XX DLLEXPORT void jl_get_uv_hooks() { if (JULIA_HOOK(close)) return; // only do this once #define XX(hook) JULIA_HOOK(hook) = JULIA_HOOK_(jl_base_module, hook); JL_CB_TYPES(XX) #undef XX } #undef JL_CB_TYPES extern jl_module_t *jl_old_base_module; // Use: JULIA_CB(hook, arg1, numberOfAdditionalArgs, arg2Type, arg2, ..., argNType, argN) #define JULIA_CB(hook,val, ...) \ (!jl_old_base_module ? ( \ jl_callback_call(JULIA_HOOK(hook),(jl_value_t*)val,__VA_ARGS__) \ ) : ( \ jl_callback_call( \ JULIA_HOOK_(jl_base_relative_to(((jl_datatype_t*)jl_typeof(val))->name->module), hook), \ (jl_value_t*)val,__VA_ARGS__) \ )) jl_value_t *jl_callback_call(jl_function_t *f,jl_value_t *val,int count,...) { if (val != 0) count += 1; else return NULL; jl_value_t **argv; JL_GC_PUSHARGS(argv,count); jl_value_t *v; va_list argp; va_start(argp,count); int i; assert(val != 0); argv[0]=val; for(i=((val==0)?0:1); idata) { JULIA_CB(close,handle->data,0); } free(handle); } DLLEXPORT void jl_uv_shutdownCallback(uv_shutdown_t *req, int status) { /* * This happens if the remote machine closes the connecition while we're * in the shutdown request (in that case we call uv_close, thus cancelling this) * request. */ if (status != UV__ECANCELED && !uv_is_closing((uv_handle_t*)req->handle)) { uv_close((uv_handle_t*)req->handle, &jl_uv_closeHandle); } free(req); } DLLEXPORT void jl_uv_return_spawn(uv_process_t *p, int64_t exit_status, int term_signal) { JULIA_CB(return_spawn,p->data,2,CB_INT64,exit_status,CB_INT32,term_signal); } DLLEXPORT void jl_uv_readcb(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf) { JULIA_CB(readcb,handle->data,3,CB_INT,nread,CB_PTR,(buf->base),CB_UINT,buf->len); } DLLEXPORT void jl_uv_alloc_buf(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { if (handle->data) { jl_value_t *ret = JULIA_CB(alloc_buf,handle->data,1,CB_UINT,suggested_size); JL_GC_PUSH1(&ret); // TODO: jl_fieldref allocates boxes here. should avoid that. assert(jl_is_tuple(ret) && jl_nfields(ret)==2 && jl_is_pointer(jl_fieldref(ret,0))); buf->base = (char*)jl_unbox_voidpointer(jl_fieldref(ret,0)); #ifdef _P64 assert(jl_is_uint64(jl_fieldref(ret,1))); buf->len = jl_unbox_uint64(jl_fieldref(ret,1)); #else assert(jl_is_uint32(jl_fieldref(ret,1))); buf->len = jl_unbox_uint32(jl_fieldref(ret,1)); #endif JL_GC_POP(); } else { buf->len = 0; } } DLLEXPORT void jl_uv_connectcb(uv_connect_t *connect, int status) { JULIA_CB(connectcb,connect->handle->data,1,CB_INT32,status); free(connect); } DLLEXPORT void jl_uv_connectioncb(uv_stream_t *stream, int status) { JULIA_CB(connectioncb,stream->data,1,CB_INT32,status); } DLLEXPORT void jl_uv_getaddrinfocb(uv_getaddrinfo_t *req,int status, struct addrinfo *addr) { JULIA_CB(getaddrinfo,req->data,2,CB_PTR,addr,CB_INT32,status); free(req); } DLLEXPORT void jl_uv_asynccb(uv_handle_t *handle) { JULIA_CB(asynccb,handle->data,0); } DLLEXPORT void jl_uv_pollcb(uv_poll_t *handle, int status, int events) { JULIA_CB(pollcb,handle->data,2,CB_INT32,status,CB_INT32,events); } DLLEXPORT void jl_uv_fspollcb(uv_fs_poll_t *handle, int status, const uv_stat_t *prev, const uv_stat_t *curr) { JULIA_CB(fspollcb,handle->data,3,CB_INT32,status,CB_PTR,prev,CB_PTR,curr); } DLLEXPORT void jl_uv_fseventscb(uv_fs_event_t *handle, const char *filename, int events, int status) { JULIA_CB(fseventscb,handle->data,3,CB_PTR,filename,CB_INT32,events,CB_INT32,status); } DLLEXPORT void jl_uv_recvcb(uv_udp_t *handle, ssize_t nread, const uv_buf_t *buf, struct sockaddr* addr, unsigned flags) { JULIA_CB(recv,handle->data,5,CB_INT,nread,CB_PTR,(buf->base),CB_UINT,buf->len,CB_PTR,addr,CB_INT32,flags); } DLLEXPORT void jl_uv_sendcb(uv_udp_send_t *handle, int status) { JULIA_CB(send,handle->data,1,CB_INT32,status); free(handle); } /** This file contains wrappers for most of libuv's stream functionailty. Once we can allocate structs in Julia, this file will be removed */ DLLEXPORT int jl_run_once(uv_loop_t *loop) { if (loop) { loop->stop_flag = 0; return uv_run(loop,UV_RUN_ONCE); } else return 0; } DLLEXPORT void jl_run_event_loop(uv_loop_t *loop) { if (loop) { loop->stop_flag = 0; uv_run(loop,UV_RUN_DEFAULT); } } DLLEXPORT int jl_process_events(uv_loop_t *loop) { if (loop) { loop->stop_flag = 0; return uv_run(loop,UV_RUN_NOWAIT); } else return 0; } DLLEXPORT int jl_init_pipe(uv_pipe_t *pipe, int writable, int readable, int julia_only) { int flags = 0; if (writable) flags |= UV_PIPE_WRITABLE; if (readable) flags |= UV_PIPE_READABLE; if (!julia_only) flags |= UV_PIPE_SPAWN_SAFE; int err = uv_pipe_init(jl_io_loop, pipe, flags); return err; } DLLEXPORT void jl_close_uv(uv_handle_t *handle) { if (handle->type==UV_TTY) uv_tty_set_mode((uv_tty_t*)handle,0); if ((handle->type == UV_NAMED_PIPE || handle->type == UV_TCP) && uv_is_writable((uv_stream_t*)handle)) { uv_shutdown_t *req = (uv_shutdown_t*)malloc(sizeof(uv_shutdown_t)); req->data = 0; /* * We are explicity ignoring the error here for the following reason: * There is only two scenarios in which this returns an error: * a) In case the stream is already shut down, in which case we're likely * in the process of closing this stream (since there's no other call to * uv_shutdown). * b) In case the stream is already closed, in which case uv_close would * cause an assertion failure. */ uv_shutdown(req, (uv_stream_t*)handle, &jl_uv_shutdownCallback); } else if (handle->type == UV_FILE) { uv_fs_t req; jl_uv_file_t *fd = (jl_uv_file_t*)handle; if (fd->file != -1) { uv_fs_close(handle->loop, &req, fd->file, NULL); fd->file = -1; } } else if (!uv_is_closing((uv_handle_t*)handle)) { uv_close(handle,&jl_uv_closeHandle); } } DLLEXPORT void jl_forceclose_uv(uv_handle_t *handle) { uv_close(handle,&jl_uv_closeHandle); } DLLEXPORT void jl_uv_associate_julia_struct(uv_handle_t *handle, jl_value_t *data) { handle->data = data; } DLLEXPORT void jl_uv_disassociate_julia_struct(uv_handle_t *handle) { handle->data = NULL; } DLLEXPORT int jl_listen(uv_stream_t *stream, int backlog) { return uv_listen(stream,backlog,&jl_uv_connectioncb); } DLLEXPORT int jl_spawn(char *name, char **argv, uv_loop_t *loop, uv_process_t *proc, jl_value_t *julia_struct, uv_handle_type stdin_type, uv_pipe_t *stdin_pipe, uv_handle_type stdout_type, uv_pipe_t *stdout_pipe, uv_handle_type stderr_type, uv_pipe_t *stderr_pipe, int detach, char **env, char *cwd) { uv_process_options_t opts; uv_stdio_container_t stdio[3]; int error; opts.file = name; opts.env = env; #ifdef _OS_WINDOWS_ opts.flags = 0; #else opts.flags = UV_PROCESS_RESET_SIGPIPE; #endif opts.cwd = cwd; opts.args = argv; if (detach) opts.flags |= UV_PROCESS_DETACHED; opts.stdio = stdio; opts.stdio_count = 3; stdio[0].type = stdin_type; stdio[0].data.stream = (uv_stream_t*)(stdin_pipe); stdio[1].type = stdout_type; stdio[1].data.stream = (uv_stream_t*)(stdout_pipe); stdio[2].type = stderr_type; stdio[2].data.stream = (uv_stream_t*)(stderr_pipe); opts.exit_cb = &jl_uv_return_spawn; error = uv_spawn(loop,proc,&opts); return error; } #ifdef _OS_WINDOWS_ #include DLLEXPORT struct tm* localtime_r(const time_t *t, struct tm *tm) { struct tm *tmp = localtime(t); //localtime is reentrant on windows if (tmp) *tm = *tmp; return tmp; } #endif /*DLLEXPORT uv_loop_t *jl_new_event_loop() { return uv_loop_new(); }*/ DLLEXPORT uv_loop_t *jl_global_event_loop(void) { return jl_io_loop; } DLLEXPORT int jl_poll_start(uv_poll_t *handle, int32_t events) { return uv_poll_start(handle, events, &jl_uv_pollcb); } DLLEXPORT int jl_fs_poll_start(uv_fs_poll_t *handle, char *file, uint32_t interval) { return uv_fs_poll_start(handle,&jl_uv_fspollcb,file,interval); } DLLEXPORT int jl_fs_event_init(uv_loop_t *loop, uv_fs_event_t *handle, const char *filename, int flags) { uv_fs_event_init(loop,handle); return uv_fs_event_start(handle,&jl_uv_fseventscb,filename,flags); } DLLEXPORT int jl_fs_unlink(char *path) { uv_fs_t req; JL_SIGATOMIC_BEGIN(); int ret = uv_fs_unlink(jl_io_loop, &req, path, NULL); uv_fs_req_cleanup(&req); JL_SIGATOMIC_END(); return ret; } DLLEXPORT int jl_fs_rename(char *src_path, char *dst_path) { uv_fs_t req; JL_SIGATOMIC_BEGIN(); int ret = uv_fs_rename(jl_io_loop, &req, src_path, dst_path, NULL); uv_fs_req_cleanup(&req); JL_SIGATOMIC_END(); return ret; } DLLEXPORT int jl_fs_sendfile(int src_fd, int dst_fd, int64_t in_offset, size_t len) { uv_fs_t req; JL_SIGATOMIC_BEGIN(); int ret = uv_fs_sendfile(jl_io_loop, &req, dst_fd, src_fd, in_offset, len, NULL); uv_fs_req_cleanup(&req); JL_SIGATOMIC_END(); return ret; } DLLEXPORT int jl_fs_symlink(char *path, char *new_path, int flags) { uv_fs_t req; int ret = uv_fs_symlink(jl_io_loop, &req, path, new_path, flags, NULL); uv_fs_req_cleanup(&req); return ret; } DLLEXPORT int jl_fs_chmod(char *path, int mode) { uv_fs_t req; int ret = uv_fs_chmod(jl_io_loop, &req, path, mode, NULL); uv_fs_req_cleanup(&req); return ret; } DLLEXPORT int jl_fs_write(int handle, const char *data, size_t len, int64_t offset) { uv_fs_t req; uv_buf_t buf[1]; buf[0].base = (char*)data; buf[0].len = len; int ret = uv_fs_write(jl_io_loop, &req, handle, buf, 1, offset, NULL); uv_fs_req_cleanup(&req); return ret; } DLLEXPORT int jl_fs_read(int handle, char *data, size_t len) { uv_fs_t req; uv_buf_t buf[1]; buf[0].base = data; buf[0].len = len; int ret = uv_fs_read(jl_io_loop, &req, handle, buf, 1, -1, NULL); uv_fs_req_cleanup(&req); return ret; } DLLEXPORT int jl_fs_read_byte(int handle) { uv_fs_t req; char c; uv_buf_t buf[1]; buf[0].base = &c; buf[0].len = 1; int ret = uv_fs_read(jl_io_loop, &req, handle, buf, 1, -1, NULL); uv_fs_req_cleanup(&req); if (ret == -1) return ret; return (int)c; } DLLEXPORT int jl_fs_close(int handle) { uv_fs_t req; int ret = uv_fs_close(jl_io_loop, &req, handle, NULL); uv_fs_req_cleanup(&req); return ret; } DLLEXPORT void jl_uv_writecb_task(uv_write_t *req, int status) { JULIA_CB(writecb_task, req->handle->data, 2, CB_PTR, req, CB_INT32, status); } DLLEXPORT int jl_uv_write(uv_stream_t *stream, const char *data, size_t n, uv_write_t *uvw, void *writecb) { uv_buf_t buf[1]; buf[0].base = (char*)data; buf[0].len = n; JL_SIGATOMIC_BEGIN(); int err = uv_write(uvw,stream,buf,1,(uv_write_cb)writecb); JL_SIGATOMIC_END(); return err; } DLLEXPORT void jl_uv_writecb(uv_write_t *req, int status) { free(req); if (status < 0) { jl_safe_printf("jl_uv_writecb() ERROR: %s %s\n", uv_strerror(status), uv_err_name(status)); } } // Note: jl_write() is called only by jl_vprintf(). // See: doc/devdocs/stdio.rst static void jl_write(uv_stream_t *stream, const char *str, size_t n) { assert(stream); uv_file fd = 0; // Fallback for output during early initialisation... if (stream == (void*)STDOUT_FILENO || stream == (void*)STDERR_FILENO) { if (!jl_io_loop) jl_io_loop = uv_default_loop(); fd = (uv_file)(size_t)stream; } else if (stream->type == UV_FILE) { fd = ((jl_uv_file_t*)stream)->file; } if (fd) { // Write to file descriptor... jl_fs_write(fd, str, n, -1); } else if (stream->type > UV_HANDLE_TYPE_MAX) { // Write to ios.c stream... // This is needed because caller jl_static_show() in builtins.c can be // called from fl_print in flisp/print.c (via cvalue_printdata()), // and cvalue_printdata() passes ios_t* to jl_static_show(). ios_write((ios_t*)stream, str, n); } else { // Write to libuv stream... uv_write_t *req = (uv_write_t*)malloc(sizeof(uv_write_t)+n); char *data = (char*)(req+1); memcpy(data,str,n); uv_buf_t buf[1]; buf[0].base = data; buf[0].len = n; req->data = NULL; JL_SIGATOMIC_BEGIN(); int status = uv_write(req, stream, buf, 1, (uv_write_cb)jl_uv_writecb); JL_SIGATOMIC_END(); if (status < 0) { jl_uv_writecb(req, status); } } } extern int vasprintf(char **str, const char *fmt, va_list ap); int jl_vprintf(uv_stream_t *s, const char *format, va_list args) { char *str=NULL; int c; va_list al; #if defined(_OS_WINDOWS_) && !defined(_COMPILER_MINGW_) al = args; #else va_copy(al, args); #endif c = vasprintf(&str, format, al); if (c >= 0) { jl_write(s, str, c); free(str); } va_end(al); return c; } int jl_printf(uv_stream_t *s, const char *format, ...) { va_list args; int c; va_start(args, format); c = jl_vprintf(s, format, args); va_end(args); return c; } DLLEXPORT void jl_safe_printf(const char *fmt, ...) { static char buf[1000]; buf[0] = '\0'; va_list args; va_start(args, fmt); // Not async signal safe on some platforms? vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); buf[999] = '\0'; if (write(STDERR_FILENO, buf, strlen(buf)) < 0) { // nothing we can do; ignore the failure } } DLLEXPORT void jl_exit(int exitcode) { uv_tty_reset_mode(); jl_atexit_hook(); exit(exitcode); } DLLEXPORT int jl_getpid() { #ifdef _OS_WINDOWS_ return GetCurrentProcessId(); #else return getpid(); #endif } //NOTE: These function expects port/host to be in network byte-order (Big Endian) DLLEXPORT int jl_tcp_bind(uv_tcp_t *handle, uint16_t port, uint32_t host, unsigned int flags) { struct sockaddr_in addr; memset(&addr, 0, sizeof(struct sockaddr_in)); addr.sin_port = port; addr.sin_addr.s_addr = host; addr.sin_family = AF_INET; return uv_tcp_bind(handle, (struct sockaddr*)&addr, flags); } DLLEXPORT int jl_tcp_bind6(uv_tcp_t *handle, uint16_t port, void *host, unsigned int flags) { struct sockaddr_in6 addr; memset(&addr, 0, sizeof(struct sockaddr_in6)); addr.sin6_port = port; memcpy(&addr.sin6_addr, host, 16); addr.sin6_family = AF_INET6; return uv_tcp_bind(handle, (struct sockaddr*)&addr, flags); } DLLEXPORT int jl_udp_bind(uv_udp_t *handle, uint16_t port, uint32_t host, uint32_t flags) { struct sockaddr_in addr; memset(&addr, 0, sizeof(struct sockaddr_in)); addr.sin_port = port; addr.sin_addr.s_addr = host; addr.sin_family = AF_INET; return uv_udp_bind(handle, (struct sockaddr*)&addr, flags); } DLLEXPORT int jl_udp_bind6(uv_udp_t *handle, uint16_t port, void *host, uint32_t flags) { struct sockaddr_in6 addr; memset(&addr, 0, sizeof(struct sockaddr_in6)); addr.sin6_port = port; memcpy(&addr.sin6_addr, host, 16); addr.sin6_family = AF_INET6; return uv_udp_bind(handle, (struct sockaddr*)&addr, flags); } DLLEXPORT int jl_udp_send(uv_udp_t *handle, uint16_t port, uint32_t host, void *data, uint32_t size) { struct sockaddr_in addr; memset(&addr, 0, sizeof(struct sockaddr_in)); addr.sin_port = port; addr.sin_addr.s_addr = host; addr.sin_family = AF_INET; uv_buf_t buf[1]; buf[0].base = (char *) data; buf[0].len = size; uv_udp_send_t *req = (uv_udp_send_t*)malloc(sizeof(uv_udp_send_t)); req->data = handle->data; return uv_udp_send(req, handle, buf, 1, (struct sockaddr*)&addr, &jl_uv_sendcb); } DLLEXPORT int jl_udp_send6(uv_udp_t *handle, uint16_t port, void *host, void *data, uint32_t size) { struct sockaddr_in6 addr; memset(&addr, 0, sizeof(struct sockaddr_in6)); addr.sin6_port = port; memcpy(&addr.sin6_addr, host, 16); addr.sin6_family = AF_INET6; uv_buf_t buf[1]; buf[0].base = (char *) data; buf[0].len = size; uv_udp_send_t *req = (uv_udp_send_t *) malloc(sizeof(uv_udp_send_t)); req->data = handle->data; return uv_udp_send(req, handle, buf, 1, (struct sockaddr*)&addr, &jl_uv_sendcb); } DLLEXPORT int jl_uv_sizeof_interface_address() { return sizeof(uv_interface_address_t); } DLLEXPORT int jl_uv_interface_addresses(uv_interface_address_t **ifAddrStruct,int *count) { return uv_interface_addresses(ifAddrStruct,count); } DLLEXPORT int jl_uv_interface_address_is_internal(uv_interface_address_t *addr) { return addr->is_internal; } DLLEXPORT struct sockaddr_in *jl_uv_interface_address_sockaddr(uv_interface_address_t *ifa) { return &ifa->address.address4; } DLLEXPORT int jl_getaddrinfo(uv_loop_t *loop, const char *host, const char *service, jl_function_t *cb) { uv_getaddrinfo_t *req = (uv_getaddrinfo_t*)malloc(sizeof(uv_getaddrinfo_t)); struct addrinfo hints; memset (&hints, 0, sizeof (hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags |= AI_CANONNAME; req->data = cb; return uv_getaddrinfo(loop,req,jl_uv_getaddrinfocb,host,service,&hints); } DLLEXPORT struct sockaddr *jl_sockaddr_from_addrinfo(struct addrinfo *addrinfo) { return addrinfo->ai_addr; } DLLEXPORT struct addrinfo *jl_next_from_addrinfo(struct addrinfo *addrinfo) { return addrinfo->ai_next; } DLLEXPORT int jl_sockaddr_in_is_ip4(struct sockaddr_in *addr) { return (addr->sin_family==AF_INET); } DLLEXPORT int jl_sockaddr_in_is_ip6(struct sockaddr_in *addr) { return (addr->sin_family==AF_INET6); } DLLEXPORT int jl_sockaddr_is_ip4(struct sockaddr_storage *addr) { return (addr->ss_family==AF_INET); } DLLEXPORT int jl_sockaddr_is_ip6(struct sockaddr_storage *addr) { return (addr->ss_family==AF_INET6); } DLLEXPORT unsigned int jl_sockaddr_host4(struct sockaddr_in *addr) { return addr->sin_addr.s_addr; } DLLEXPORT unsigned int jl_sockaddr_host6(struct sockaddr_in6 *addr, char *host) { memcpy(host, &addr->sin6_addr, 16); return addr->sin6_scope_id; } DLLEXPORT void jl_sockaddr_set_port(struct sockaddr_storage *addr,uint16_t port) { if (addr->ss_family==AF_INET) { ((struct sockaddr_in*)addr)->sin_port=port; } else { ((struct sockaddr_in6*)addr)->sin6_port=port; } } DLLEXPORT int jl_tcp4_connect(uv_tcp_t *handle,uint32_t host, uint16_t port) { struct sockaddr_in addr; uv_connect_t *req = (uv_connect_t*)malloc(sizeof(uv_connect_t)); req->data = 0; memset(&addr, 0, sizeof(struct sockaddr_in)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = host; addr.sin_port = port; return uv_tcp_connect(req,handle,(struct sockaddr*)&addr,&jl_uv_connectcb); } DLLEXPORT int jl_tcp6_connect(uv_tcp_t *handle, void *host, uint16_t port) { struct sockaddr_in6 addr; uv_connect_t *req = (uv_connect_t*)malloc(sizeof(uv_connect_t)); req->data = 0; memset(&addr, 0, sizeof(struct sockaddr_in6)); addr.sin6_family = AF_INET6; memcpy(&addr.sin6_addr, host, 16); addr.sin6_port = port; return uv_tcp_connect(req,handle,(struct sockaddr*)&addr,&jl_uv_connectcb); } DLLEXPORT int jl_connect_raw(uv_tcp_t *handle,struct sockaddr_storage *addr) { uv_connect_t *req = (uv_connect_t*)malloc(sizeof(uv_connect_t)); req->data = 0; return uv_tcp_connect(req,handle,(struct sockaddr*)addr,&jl_uv_connectcb); } #ifdef _OS_LINUX_ DLLEXPORT int jl_tcp_quickack(uv_tcp_t *handle, int on) { int fd = (handle)->io_watcher.fd; if (fd != -1) { if (setsockopt(fd, IPPROTO_TCP, TCP_QUICKACK, &on, sizeof(on))) { return -1; } } return 0; } #endif #ifndef _OS_WINDOWS_ DLLEXPORT int jl_uv_unix_fd_is_watched(int fd, uv_poll_t *handle, uv_loop_t *loop) { if (fd >= loop->nwatchers) return 0; if (loop->watchers[fd] == NULL) return 0; if (loop->watchers[fd] == &handle->io_watcher) return 0; return 1; } #endif #ifdef _OS_WINDOWS_ static inline int ishexchar(char c) { if (c >= '0' && c <= '9') return 1; if (c >= 'a' && c <= 'z') return 1; return 0; } DLLEXPORT int jl_ispty(uv_pipe_t *pipe) { if (pipe->type != UV_NAMED_PIPE) return 0; size_t len = 0; if (uv_pipe_getsockname(pipe, NULL, &len) != UV_ENOBUFS) return 0; char *name = (char *) alloca(len); if (uv_pipe_getsockname(pipe, name, &len)) return 0; // return true if name matches regex: // ^\\\\?\\pipe\\(msys|cygwin)-[0-9a-z]{16}-[pt]ty[1-9][0-9]*- //jl_printf(JL_STDERR,"pipe_name: %s\n", name); int n = 0; if (!strncmp(name,"\\\\?\\pipe\\msys-",14)) n = 14; else if (!strncmp(name,"\\\\?\\pipe\\cygwin-",16)) n = 16; else return 0; //jl_printf(JL_STDERR,"prefix pass\n"); name += n; for (int n = 0; n < 16; n++) if (!ishexchar(*name++)) return 0; //jl_printf(JL_STDERR,"hex pass\n"); if ((*name++)!='-') return 0; if (*name != 'p' && *name != 't') return 0; name++; if (*name++ != 't' || *name++ != 'y') return 0; //jl_printf(JL_STDERR,"tty pass\n"); return 1; } #endif DLLEXPORT uv_handle_type jl_uv_handle_type(uv_handle_t *handle) { #ifdef _OS_WINDOWS_ if (jl_ispty((uv_pipe_t*)handle)) return UV_TTY; #endif return handle->type; } DLLEXPORT int jl_tty_set_mode(uv_tty_t *handle, int mode) { if (handle->type != UV_TTY) return 0; return uv_tty_set_mode(handle, mode); } DLLEXPORT uv_file jl_uv_file_handle(jl_uv_file_t *f) { return f->file; } DLLEXPORT void jl_uv_req_set_data(uv_req_t *req, void *data) { req->data = data; } DLLEXPORT void *jl_uv_req_data(uv_req_t *req) { return req->data; } DLLEXPORT void *jl_uv_handle_data(uv_handle_t *handle) { return handle->data; } #ifndef _OS_WINDOWS_ #if defined(__APPLE__) int uv___stream_fd(uv_stream_t *handle); #define uv__stream_fd(handle) (uv___stream_fd((uv_stream_t*)(handle))) #else #define uv__stream_fd(handle) ((handle)->io_watcher.fd) #endif /* defined(__APPLE__) */ DLLEXPORT int jl_uv_handle(uv_stream_t *handle) { return uv__stream_fd(handle); } #else DLLEXPORT HANDLE jl_uv_handle(uv_stream_t *handle) { switch (handle->type) { case UV_TTY: return ((uv_tty_t*)handle)->handle; case UV_NAMED_PIPE: return ((uv_pipe_t*)handle)->handle; default: return INVALID_HANDLE_VALUE; } } #endif #ifdef __cplusplus } #endif