/* * @returns 0 on success, -1 on error. */ int uping_init(void) { struct sockaddr_in from = { 0 }; int fd; memset(&from, 0, sizeof(from)); from.sin_addr = VirtualHost.sin_addr; from.sin_port = htons(atoi(UDP_PORT)); from.sin_family = AF_INET; if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { Debug((DEBUG_ERROR, "UPING: UDP listener socket call failed: %s", (strerror(errno)) ? strerror(errno) : "Unknown error")); return -1; } if (!os_set_reuseaddr(fd)) { log_write(LS_SOCKET, L_ERROR, 0, "UPING: set reuseaddr on UDP listener failed: %m (fd %d)", fd); Debug((DEBUG_ERROR, "UPING: set reuseaddr on UDP listener failed: %s", (strerror(errno)) ? strerror(errno) : "Unknown error")); close(fd); return -1; } if (bind(fd, (struct sockaddr*) &from, sizeof(from)) == -1) { log_write(LS_SOCKET, L_ERROR, 0, "UPING: bind on UDP listener (%d fd %d) failed: %m", htons(from.sin_port), fd); Debug((DEBUG_ERROR, "UPING: bind on UDP listener failed : %s", (strerror(errno)) ? strerror(errno) : "Unknown error")); close(fd); return -1; } if (!os_set_nonblocking(fd)) { Debug((DEBUG_ERROR, "UPING: set non-blocking: %s", (strerror(errno)) ? strerror(errno) : "Unknown error")); close(fd); return -1; } if (!socket_add(&upingSock, uping_echo_callback, 0, SS_DATAGRAM, SOCK_EVENT_READABLE, fd)) { Debug((DEBUG_ERROR, "UPING: Unable to queue fd to event system")); close(fd); return -1; } UPingFileDescriptor = fd; return fd; }
/** Open a TCP or UDP socket on a particular address. * @param[in] local Local address to bind to. * @param[in] type SOCK_STREAM or SOCK_DGRAM. * @param[in] port_name Port name (used in error diagnostics). * @param[in] family A specific address family to use, or 0 for automatic. * @return Bound descriptor, or -1 on error. */ int os_socket(const struct irc_sockaddr* local, int type, const char* port_name, int family) { struct sockaddr_native addr; int size, fd; assert(local != 0); size = sockaddr_from_irc(&addr, local, -1, family); fd = socket(addr.sn_family, type, 0); if (fd < 0) { report_error(SOCKET_ERROR_MSG, port_name, errno); return -1; } if (fd > MAXCLIENTS - 1) { report_error(CONNLIMIT_ERROR_MSG, port_name, 0); close(fd); return -1; } if (!os_set_reuseaddr(fd)) { report_error(REUSEADDR_ERROR_MSG, port_name, errno); close(fd); return -1; } if (!os_set_nonblocking(fd)) { report_error(NONB_ERROR_MSG, port_name, errno); close(fd); return -1; } if (local) { #if defined(IPV6_V6ONLY) int on = 1; if (family == AF_INET6 && irc_in_addr_unspec(&local->addr)) setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); #endif if (bind(fd, (struct sockaddr*)&addr, size)) { report_error(BIND_ERROR_MSG, port_name, errno); close(fd); return -1; } } return fd; }