+/*
+ * 'httpAddrListen()' - Create a listening socket bound to the specified
+ * address and port.
+ *
+ * @since CUPS 1.7/macOS 10.9@
+ */
+
+int /* O - Socket or -1 on error */
+httpAddrListen(http_addr_t *addr, /* I - Address to bind to */
+ int port) /* I - Port number to bind to */
+{
+ int fd = -1, /* Socket */
+ val, /* Socket value */
+ status; /* Bind status */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!addr || port < 0)
+ return (-1);
+
+ /*
+ * Create the socket and set options...
+ */
+
+ if ((fd = socket(addr->addr.sa_family, SOCK_STREAM, 0)) < 0)
+ {
+ _cupsSetHTTPError(HTTP_STATUS_ERROR);
+ return (-1);
+ }
+
+ val = 1;
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, CUPS_SOCAST &val, sizeof(val));
+
+#ifdef IPV6_V6ONLY
+ if (addr->addr.sa_family == AF_INET6)
+ setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, CUPS_SOCAST &val, sizeof(val));
+#endif /* IPV6_V6ONLY */
+
+ /*
+ * Bind the socket...
+ */
+
+#ifdef AF_LOCAL
+ if (addr->addr.sa_family == AF_LOCAL)
+ {
+ mode_t mask; /* Umask setting */
+
+ /*
+ * Remove any existing domain socket file...
+ */
+
+ unlink(addr->un.sun_path);
+
+ /*
+ * Save the current umask and set it to 0 so that all users can access
+ * the domain socket...
+ */
+
+ mask = umask(0);
+
+ /*
+ * Bind the domain socket...
+ */
+
+ status = bind(fd, (struct sockaddr *)addr, (socklen_t)httpAddrLength(addr));
+
+ /*
+ * Restore the umask and fix permissions...
+ */
+
+ umask(mask);
+ chmod(addr->un.sun_path, 0140777);
+ }
+ else
+#endif /* AF_LOCAL */
+ {
+ _httpAddrSetPort(addr, port);
+
+ status = bind(fd, (struct sockaddr *)addr, (socklen_t)httpAddrLength(addr));
+ }
+
+ if (status)
+ {
+ _cupsSetHTTPError(HTTP_STATUS_ERROR);
+
+ close(fd);
+
+ return (-1);
+ }
+
+ /*
+ * Listen...
+ */
+
+ if (listen(fd, 5))
+ {
+ _cupsSetHTTPError(HTTP_STATUS_ERROR);
+
+ close(fd);
+
+ return (-1);
+ }
+
+ /*
+ * Close on exec...
+ */
+
+#ifndef WIN32
+ fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
+#endif /* !WIN32 */
+
+#ifdef SO_NOSIGPIPE
+ /*
+ * Disable SIGPIPE for this socket.
+ */
+
+ val = 1;
+ setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, CUPS_SOCAST &val, sizeof(val));
+#endif /* SO_NOSIGPIPE */
+
+ return (fd);
+}
+
+