int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) { int domain; int err; int fd; /* Use the lower 8 bits for the domain */ domain = flags & 0xFF; if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC) return -EINVAL; if (flags & ~0xFF) return -EINVAL; if (domain != AF_UNSPEC) { err = uv__socket(domain, SOCK_DGRAM, 0); if (err < 0) return err; fd = err; } else { fd = -1; } uv__handle_init(loop, (uv_handle_t*)handle, UV_UDP); handle->alloc_cb = NULL; handle->recv_cb = NULL; handle->send_queue_size = 0; handle->send_queue_count = 0; uv__io_init(&handle->io_watcher, uv__udp_io, fd); QUEUE_INIT(&handle->write_queue); QUEUE_INIT(&handle->write_completed_queue); return 0; }
void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, const char* name, uv_connect_cb cb) { struct sockaddr_un saddr; int saved_errno; int new_sock; int err; int r; saved_errno = errno; new_sock = (handle->fd == -1); err = -1; if (new_sock) if ((handle->fd = uv__socket(AF_UNIX, SOCK_STREAM, 0)) == -1) goto out; memset(&saddr, 0, sizeof saddr); uv_strlcpy(saddr.sun_path, name, sizeof(saddr.sun_path)); saddr.sun_family = AF_UNIX; /* We don't check for EINPROGRESS. Think about it: the socket * is either there or not. */ do { r = connect(handle->fd, (struct sockaddr*)&saddr, sizeof saddr); } while (r == -1 && errno == EINTR); if (r == -1) goto out; if (new_sock) if (uv__stream_open((uv_stream_t*)handle, handle->fd, UV_STREAM_READABLE | UV_STREAM_WRITABLE)) goto out; uv__io_start(handle->loop, &handle->read_watcher); uv__io_start(handle->loop, &handle->write_watcher); err = 0; out: handle->delayed_error = err ? errno : 0; /* Passed to callback. */ handle->connect_req = req; uv__req_init(handle->loop, req, UV_CONNECT); req->handle = (uv_stream_t*)handle; req->cb = cb; ngx_queue_init(&req->queue); /* Run callback on next tick. */ uv__io_feed(handle->loop, &handle->write_watcher, UV__IO_WRITE); /* Mimic the Windows pipe implementation, always * return 0 and let the callback handle errors. */ errno = saved_errno; }
void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, const char* name, uv_connect_cb cb) { struct sockaddr_un saddr; int saved_errno; int new_sock; int err; int r; saved_errno = errno; new_sock = (uv__stream_fd(handle) == -1); err = -1; if (new_sock) if ((handle->io_watcher.fd = uv__socket(AF_UNIX, SOCK_STREAM, 0)) == -1) goto out; memset(&saddr, 0, sizeof saddr); uv_strlcpy(saddr.sun_path, name, sizeof(saddr.sun_path)); saddr.sun_family = AF_UNIX; do { r = connect(uv__stream_fd(handle), (struct sockaddr*)&saddr, sizeof saddr); } while (r == -1 && errno == EINTR); if (r == -1) if (errno != EINPROGRESS) goto out; if (new_sock) if (uv__stream_open((uv_stream_t*)handle, uv__stream_fd(handle), UV_STREAM_READABLE | UV_STREAM_WRITABLE)) goto out; uv__io_start(handle->loop, &handle->io_watcher, UV__POLLIN | UV__POLLOUT); err = 0; out: handle->delayed_error = err ? errno : 0; /* Passed to callback. */ handle->connect_req = req; uv__req_init(handle->loop, req, UV_CONNECT); req->handle = (uv_stream_t*)handle; req->cb = cb; QUEUE_INIT(&req->queue); /* Force callback to run on next tick in case of error. */ if (err != 0) uv__io_feed(handle->loop, &handle->io_watcher); /* Mimic the Windows pipe implementation, always * return 0 and let the callback handle errors. */ errno = saved_errno; }
int uv__udp_bind(uv_udp_t* handle, const struct sockaddr* addr, unsigned int addrlen, unsigned int flags) { int err; int yes; int fd; /* Check for bad flags. */ if (flags & ~(UV_UDP_IPV6ONLY | UV_UDP_REUSEADDR)) return -EINVAL; /* Cannot set IPv6-only mode on non-IPv6 socket. */ if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6) return -EINVAL; fd = handle->io_watcher.fd; if (fd == -1) { err = uv__socket(addr->sa_family, SOCK_DGRAM, 0); if (err < 0) return err; fd = err; handle->io_watcher.fd = fd; } if (flags & UV_UDP_REUSEADDR) { err = uv__set_reuse(fd); if (err) goto out; } if (flags & UV_UDP_IPV6ONLY) { #ifdef IPV6_V6ONLY yes = 1; if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof yes) == -1) { err = -errno; goto out; } #else err = -ENOTSUP; goto out; #endif } if (bind(fd, addr, addrlen)) { err = -errno; goto out; } if (addr->sa_family == AF_INET6) handle->flags |= UV_HANDLE_IPV6; return 0; out: uv__close(handle->io_watcher.fd); handle->io_watcher.fd = -1; return err; }
int uv_pipe_bind(uv_pipe_t* handle, const char* name) { struct sockaddr_un saddr; const char* pipe_fname; int sockfd; int err; size_t name_len; pipe_fname = NULL; sockfd = -1; name_len = strlen(name); if (name_len > sizeof(saddr.sun_path) - 1) return -ENAMETOOLONG; /* Already bound? */ if (uv__stream_fd(handle) >= 0) return -EINVAL; /* Make a copy of the file name, it outlives this function's scope. */ pipe_fname = uv__strdup(name); if (pipe_fname == NULL) return -ENOMEM; /* We've got a copy, don't touch the original any more. */ name = NULL; err = uv__socket(AF_UNIX, SOCK_STREAM, 0); if (err < 0) goto err_socket; sockfd = err; memset(&saddr, 0, sizeof saddr); memcpy(saddr.sun_path, pipe_fname, name_len); saddr.sun_family = AF_UNIX; if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) { err = -errno; /* Convert ENOENT to EACCES for compatibility with Windows. */ if (err == -ENOENT) err = -EACCES; uv__close(sockfd); goto err_socket; } /* Success. */ handle->flags |= UV_HANDLE_BOUND; handle->pipe_fname = pipe_fname; /* Is a strdup'ed copy. */ handle->io_watcher.fd = sockfd; return 0; err_socket: uv__free((void*)pipe_fname); return err; }
static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) { int sockfd; if (uv__stream_fd(handle) != -1) return 0; sockfd = uv__socket(domain, SOCK_STREAM, 0); if (sockfd == -1) return uv__set_sys_error(handle->loop, errno); if (uv__stream_open((uv_stream_t*)handle, sockfd, flags)) { close(sockfd); return -1; } return 0; }
static int uv__bind(uv_tcp_t* tcp, int domain, struct sockaddr* addr, int addrsize) { int saved_errno; int status; saved_errno = errno; status = -1; if (tcp->fd < 0) { if ((tcp->fd = uv__socket(domain, SOCK_STREAM, 0)) == -1) { uv__set_sys_error(tcp->loop, errno); goto out; } if (uv__stream_open((uv_stream_t*)tcp, tcp->fd, UV_STREAM_READABLE | UV_STREAM_WRITABLE)) { close(tcp->fd); tcp->fd = -1; status = -2; goto out; } } assert(tcp->fd >= 0); tcp->delayed_error = 0; if (bind(tcp->fd, addr, addrsize) == -1) { if (errno == EADDRINUSE) { tcp->delayed_error = errno; } else { uv__set_sys_error(tcp->loop, errno); goto out; } } status = 0; out: errno = saved_errno; return status; }
static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) { int sockfd; int err; if (uv__stream_fd(handle) != -1) return 0; err = uv__socket(domain, SOCK_STREAM, 0); if (err < 0) return err; sockfd = err; err = uv__stream_open((uv_stream_t*) handle, sockfd, flags); if (err) { close(sockfd); return err; } return 0; }
int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { int r; if (tcp->delayed_error) { uv__set_sys_error(tcp->loop, tcp->delayed_error); return -1; } if (tcp->fd < 0) { if ((tcp->fd = uv__socket(AF_INET, SOCK_STREAM, 0)) == -1) { uv__set_sys_error(tcp->loop, errno); return -1; } if (uv__stream_open((uv_stream_t*)tcp, tcp->fd, UV_READABLE)) { uv__close(tcp->fd); tcp->fd = -1; return -1; } } assert(tcp->fd >= 0); r = listen(tcp->fd, backlog); if (r < 0) { uv__set_sys_error(tcp->loop, errno); return -1; } tcp->connection_cb = cb; /* Start listening for connections. */ uv__io_watcher_start( (uv_handle_t*)tcp, &tcp->io, &tcp->io.read_watcher, uv__server_io); return 0; }
static int new_socket(uv_tcp_t* handle, int domain, unsigned long flags) { struct sockaddr_storage saddr; socklen_t slen; int sockfd; int err; err = uv__socket(domain, SOCK_STREAM, 0); if (err < 0) return err; sockfd = err; err = uv__stream_open((uv_stream_t*) handle, sockfd, flags); if (err) { uv__close(sockfd); return err; } if (flags & UV_HANDLE_BOUND) { /* Bind this new socket to an arbitrary port */ slen = sizeof(saddr); memset(&saddr, 0, sizeof(saddr)); err = getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen); if (err) { uv__close(sockfd); return err; } err = bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen); if (err) { uv__close(sockfd); return err; } } return 0; }
static int uv__bind(uv_udp_t* handle, int domain, struct sockaddr* addr, socklen_t len, unsigned flags) { int saved_errno; int status; int yes; int fd; saved_errno = errno; status = -1; fd = -1; /* Check for bad flags. */ if (flags & ~UV_UDP_IPV6ONLY) { uv__set_sys_error(handle->loop, EINVAL); goto out; } /* Cannot set IPv6-only mode on non-IPv6 socket. */ if ((flags & UV_UDP_IPV6ONLY) && domain != AF_INET6) { uv__set_sys_error(handle->loop, EINVAL); goto out; } if (handle->io_watcher.fd == -1) { if ((fd = uv__socket(domain, SOCK_DGRAM, 0)) == -1) { uv__set_sys_error(handle->loop, errno); goto out; } handle->io_watcher.fd = fd; } fd = handle->io_watcher.fd; yes = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes) == -1) { uv__set_sys_error(handle->loop, errno); goto out; } /* On the BSDs, SO_REUSEADDR lets you reuse an address that's in the TIME_WAIT * state (i.e. was until recently tied to a socket) while SO_REUSEPORT lets * multiple processes bind to the same address. Yes, it's something of a * misnomer but then again, SO_REUSEADDR was already taken. * * None of the above applies to Linux: SO_REUSEADDR implies SO_REUSEPORT on * Linux and hence it does not have SO_REUSEPORT at all. */ #ifdef SO_REUSEPORT yes = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof yes) == -1) { uv__set_sys_error(handle->loop, errno); goto out; } #endif if (flags & UV_UDP_IPV6ONLY) { #ifdef IPV6_V6ONLY yes = 1; if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof yes) == -1) { uv__set_sys_error(handle->loop, errno); goto out; } #else uv__set_sys_error(handle->loop, ENOTSUP); goto out; #endif } if (bind(fd, addr, len) == -1) { uv__set_sys_error(handle->loop, errno); goto out; } handle->io_watcher.fd = fd; status = 0; out: if (status) { close(handle->io_watcher.fd); handle->io_watcher.fd = -1; } errno = saved_errno; return status; }
int uv__connect(uv_connect_t* req, uv_stream_t* stream, struct sockaddr* addr, socklen_t addrlen, uv_connect_cb cb) { int sockfd; int r; if (stream->fd <= 0) { if ((sockfd = uv__socket(addr->sa_family, SOCK_STREAM, 0)) == -1) { uv__set_sys_error(stream->loop, errno); return -1; } if (uv__stream_open(stream, sockfd, UV_READABLE | UV_WRITABLE)) { uv__close(sockfd); return -2; } } uv__req_init(stream->loop, (uv_req_t*)req); req->cb = cb; req->handle = stream; req->type = UV_CONNECT; ngx_queue_init(&req->queue); if (stream->connect_req) { uv__set_sys_error(stream->loop, EALREADY); return -1; } if (stream->type != UV_TCP) { uv__set_sys_error(stream->loop, ENOTSOCK); return -1; } stream->connect_req = req; do { r = connect(stream->fd, addr, addrlen); } while (r == -1 && errno == EINTR); stream->delayed_error = 0; if (r != 0 && errno != EINPROGRESS) { switch (errno) { /* If we get a ECONNREFUSED wait until the next tick to report the * error. Solaris wants to report immediately--other unixes want to * wait. */ case ECONNREFUSED: stream->delayed_error = errno; break; default: uv__set_sys_error(stream->loop, errno); return -1; } } assert(stream->write_watcher.data == stream); ev_io_start(stream->loop->ev, &stream->write_watcher); if (stream->delayed_error) { ev_feed_event(stream->loop->ev, &stream->write_watcher, EV_WRITE); } return 0; }
void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, const char* name, uv_connect_cb cb) { struct sockaddr_un saddr; int new_sock; int err; int r; size_t name_len; name_len = strlen(name); if (name_len > sizeof(saddr.sun_path) - 1) { err = -ENAMETOOLONG; goto out; } new_sock = (uv__stream_fd(handle) == -1); if (new_sock) { err = uv__socket(AF_UNIX, SOCK_STREAM, 0); if (err < 0) goto out; handle->io_watcher.fd = err; } memset(&saddr, 0, sizeof saddr); memcpy(saddr.sun_path, name, name_len); saddr.sun_family = AF_UNIX; do { r = connect(uv__stream_fd(handle), (struct sockaddr*)&saddr, sizeof saddr); } while (r == -1 && errno == EINTR); if (r == -1 && errno != EINPROGRESS) { err = -errno; #if defined(__CYGWIN__) || defined(__MSYS__) /* EBADF is supposed to mean that the socket fd is bad, but Cygwin reports EBADF instead of ENOTSOCK when the file is not a socket. We do not expect to see a bad fd here (e.g. due to new_sock), so translate the error. */ if (err == -EBADF) err = -ENOTSOCK; #endif goto out; } err = 0; if (new_sock) { err = uv__stream_open((uv_stream_t*)handle, uv__stream_fd(handle), UV_STREAM_READABLE | UV_STREAM_WRITABLE); } if (err == 0) uv__io_start(handle->loop, &handle->io_watcher, POLLIN | POLLOUT); out: handle->delayed_error = err; handle->connect_req = req; uv__req_init(handle->loop, req, UV_CONNECT); req->handle = (uv_stream_t*)handle; req->cb = cb; QUEUE_INIT(&req->queue); /* Force callback to run on next tick in case of error. */ if (err) uv__io_feed(handle->loop, &handle->io_watcher); }
int uv_pipe_bind(uv_pipe_t* handle, const char* name) { struct sockaddr_un saddr; const char* pipe_fname; int saved_errno; int sockfd; int status; int bound; saved_errno = errno; pipe_fname = NULL; sockfd = -1; status = -1; bound = 0; /* Already bound? */ if (handle->fd >= 0) { uv__set_artificial_error(handle->loop, UV_EINVAL); goto out; } /* Make a copy of the file name, it outlives this function's scope. */ if ((pipe_fname = strdup(name)) == NULL) { uv__set_sys_error(handle->loop, ENOMEM); goto out; } /* We've got a copy, don't touch the original any more. */ name = NULL; if ((sockfd = uv__socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { uv__set_sys_error(handle->loop, errno); goto out; } memset(&saddr, 0, sizeof saddr); uv_strlcpy(saddr.sun_path, pipe_fname, sizeof(saddr.sun_path)); saddr.sun_family = AF_UNIX; if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) { /* Convert ENOENT to EACCES for compatibility with Windows. */ uv__set_sys_error(handle->loop, (errno == ENOENT) ? EACCES : errno); goto out; } bound = 1; /* Success. */ handle->pipe_fname = pipe_fname; /* Is a strdup'ed copy. */ handle->fd = sockfd; status = 0; out: /* Clean up on error. */ if (status) { if (bound) { /* unlink() before close() to avoid races. */ assert(pipe_fname != NULL); unlink(pipe_fname); } close(sockfd); free((void*)pipe_fname); } errno = saved_errno; return status; }
int uv_pipe_bind(uv_pipe_t* handle, const char* name) { struct sockaddr_un sun; const char* pipe_fname; int saved_errno; int sockfd; int status; int bound; saved_errno = errno; pipe_fname = NULL; sockfd = -1; status = -1; bound = 0; /* Already bound? */ if (handle->fd >= 0) { uv_err_new_artificial(handle->loop, UV_EINVAL); goto out; } /* Make a copy of the file name, it outlives this function's scope. */ if ((pipe_fname = strdup(name)) == NULL) { uv_err_new(handle->loop, ENOMEM); goto out; } /* We've got a copy, don't touch the original any more. */ name = NULL; if ((sockfd = uv__socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { uv_err_new(handle->loop, errno); goto out; } memset(&sun, 0, sizeof sun); uv__strlcpy(sun.sun_path, pipe_fname, sizeof(sun.sun_path)); sun.sun_family = AF_UNIX; if (bind(sockfd, (struct sockaddr*)&sun, sizeof sun) == -1) { /* On EADDRINUSE: * * We hold the file lock so there is no other process listening * on the socket. Ergo, it's stale - remove it. * * This assumes that the other process uses locking too * but that's a good enough assumption for now. */ if (errno != EADDRINUSE || unlink(pipe_fname) == -1 || bind(sockfd, (struct sockaddr*)&sun, sizeof sun) == -1) { /* Convert ENOENT to EACCES for compatibility with Windows. */ uv_err_new(handle->loop, (errno == ENOENT) ? EACCES : errno); goto out; } } bound = 1; /* Success. */ handle->pipe_fname = pipe_fname; /* Is a strdup'ed copy. */ handle->fd = sockfd; status = 0; out: /* Clean up on error. */ if (status) { if (bound) { /* unlink() before close() to avoid races. */ assert(pipe_fname != NULL); unlink(pipe_fname); } uv__close(sockfd); free((void*)pipe_fname); } errno = saved_errno; return status; }
int uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, const char* name, uv_connect_cb cb) { struct sockaddr_un sun; int saved_errno; int sockfd; int status; int r; saved_errno = errno; sockfd = -1; status = -1; if ((sockfd = uv__socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { uv_err_new(handle->loop, errno); goto out; } memset(&sun, 0, sizeof sun); uv__strlcpy(sun.sun_path, name, sizeof(sun.sun_path)); sun.sun_family = AF_UNIX; /* We don't check for EINPROGRESS. Think about it: the socket * is either there or not. */ do { r = connect(sockfd, (struct sockaddr*)&sun, sizeof sun); } while (r == -1 && errno == EINTR); if (r == -1) { uv_err_new(handle->loop, errno); uv__close(sockfd); goto out; } uv__stream_open((uv_stream_t*)handle, sockfd, UV_READABLE | UV_WRITABLE); ev_io_start(handle->loop->ev, &handle->read_watcher); ev_io_start(handle->loop->ev, &handle->write_watcher); status = 0; out: handle->delayed_error = status; /* Passed to callback. */ handle->connect_req = req; req->handle = (uv_stream_t*)handle; req->type = UV_CONNECT; req->cb = cb; ngx_queue_init(&req->queue); /* Run callback on next tick. */ ev_feed_event(handle->loop->ev, &handle->read_watcher, EV_CUSTOM); assert(ev_is_pending(&handle->read_watcher)); /* Mimic the Windows pipe implementation, always * return 0 and let the callback handle errors. */ errno = saved_errno; return 0; }
static int uv__bind(uv_udp_t* handle, int domain, struct sockaddr* addr, socklen_t len, unsigned flags) { int saved_errno; int status; int yes; int fd; saved_errno = errno; status = -1; fd = -1; /* Check for bad flags. */ if (flags & ~UV_UDP_IPV6ONLY) { uv__set_sys_error(handle->loop, EINVAL); goto out; } /* Cannot set IPv6-only mode on non-IPv6 socket. */ if ((flags & UV_UDP_IPV6ONLY) && domain != AF_INET6) { uv__set_sys_error(handle->loop, EINVAL); goto out; } /* Check for already active socket. */ if (handle->fd != -1) { uv__set_artificial_error(handle->loop, UV_EALREADY); goto out; } if ((fd = uv__socket(domain, SOCK_DGRAM, 0)) == -1) { uv__set_sys_error(handle->loop, errno); goto out; } yes = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes) == -1) { uv__set_sys_error(handle->loop, errno); goto out; } if (flags & UV_UDP_IPV6ONLY) { #ifdef IPV6_V6ONLY yes = 1; if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof yes) == -1) { uv__set_sys_error(handle->loop, errno); goto out; } #else uv__set_sys_error(handle->loop, ENOTSUP); goto out; #endif } if (bind(fd, addr, len) == -1) { uv__set_sys_error(handle->loop, errno); goto out; } handle->fd = fd; status = 0; out: if (status) uv__close(fd); errno = saved_errno; return status; }