+static int hsrv_itf_connect(struct hsrv_itf *itf);
+
+static void hsrv_itf_callback(void *closure, uint32_t revents, struct fdev *fdev)
+{
+ struct hsrv_itf *itf = closure;
+ int fd, sts;
+ struct sockaddr addr;
+ socklen_t lenaddr;
+
+ if ((revents & EPOLLHUP) != 0) {
+ ERROR("disconnection for server %s: %m", itf->uri);
+ hsrv_itf_connect(itf);
+ fdev_unref(fdev);
+ } else if ((revents & EPOLLIN) != 0) {
+ lenaddr = (socklen_t)sizeof addr;
+ fd = accept(fdev_fd(fdev), &addr, &lenaddr);
+ if (fd < 0)
+ ERROR("can't accept connection to %s: %m", itf->uri);
+ else {
+ sts = MHD_add_connection(itf->hsrv->httpd, fd, &addr, lenaddr);
+ if (sts != MHD_YES) {
+ ERROR("can't add incoming connection to %s: %m", itf->uri);
+ close(fd);
+ }
+ }
+ }
+}
+
+static int hsrv_itf_connect(struct hsrv_itf *itf)
+{
+ struct sockaddr addr;
+ socklen_t lenaddr;
+ char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
+ int rgni;
+
+ itf->fdev = afb_socket_open_fdev(itf->uri, 1);
+ if (!itf->fdev) {
+ ERROR("can't create socket %s", itf->uri);
+ return 0;
+ }
+ fdev_set_events(itf->fdev, EPOLLIN);
+ fdev_set_callback(itf->fdev, hsrv_itf_callback, itf);
+ memset(&addr, 0, sizeof addr);
+ lenaddr = (socklen_t)sizeof addr;
+ getsockname(fdev_fd(itf->fdev), &addr, &lenaddr);
+ if (addr.sa_family == AF_INET && !((struct sockaddr_in*)&addr)->sin_addr.s_addr) {
+ strncpy(hbuf, "*", NI_MAXHOST);
+ sprintf(sbuf, "%d", (int)ntohs(((struct sockaddr_in*)&addr)->sin_port));
+ } else {
+ rgni = getnameinfo(&addr, lenaddr, hbuf, sizeof hbuf, sbuf, sizeof sbuf, NI_NUMERICSERV);
+ if (rgni != 0) {
+ ERROR("getnameinfo returned %d: %s", rgni, gai_strerror(rgni));
+ hbuf[0] = sbuf[0] = '?';
+ hbuf[1] = sbuf[1] = 0;
+ }
+ }
+ NOTICE("Listening interface %s:%s", hbuf, sbuf);
+ return 1;
+}
+
+int afb_hsrv_add_interface(struct afb_hsrv *hsrv, const char *uri)
+{
+ struct hsrv_itf *itf;
+
+ itf = malloc(sizeof *itf + 1 + strlen(uri));
+ if (itf == NULL)
+ return -1;
+
+ itf->hsrv = hsrv;
+ itf->fdev = NULL;
+ strcpy(itf->uri, uri);
+ itf->next = hsrv->interfaces;
+ hsrv->interfaces = itf;
+ return hsrv_itf_connect(itf);
+}
+
+int afb_hsrv_add_interface_tcp(struct afb_hsrv *hsrv, const char *itf, uint16_t port)
+{
+ int rc;
+ char buffer[1024];
+
+ if (itf == NULL) {
+ itf = "*"; /* awaiting getifaddrs impl */
+ }
+ rc = snprintf(buffer, sizeof buffer, "tcp:%s:%d", itf, (int)port);
+ if (rc < 0 || rc >= (int)sizeof buffer) {
+ if (rc > 0)
+ errno = EINVAL;
+ return 0;
+ }
+ return afb_hsrv_add_interface(hsrv, buffer);
+}