Exemplo n.º 1
0
/*
 * @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;
}