/* * "inet_ntoa/inet_pton" for struct sockaddr_gen */ static const char * sgen_toa(struct sockaddr_gen *addr) { static char buf[INET6_ADDRSTRLEN]; return (inet_ntop(SGFAM(addr), SGADDRP(addr), buf, sizeof (buf))); }
SERVER * server_init(int fd, const struct sockaddr_gen *sg, int backlog, int max_clients, void (*handler)(CLIENT *cp)) { static int one = 1; socklen_t slen; SERVER *sp; if (debug) fprintf(stderr, "server_init(%d, ..., %d, %d, ...): Start\n", fd, backlog, max_clients); A_NEW(sp); sp->fd = -1; sp->state = 0; pthread_attr_init(&sp->ca_detached); pthread_attr_setdetachstate(&sp->ca_detached, PTHREAD_CREATE_DETACHED); pthread_mutex_init(&sp->clients_mtx, NULL); pthread_cond_init(&sp->clients_cv, NULL); sp->clients_cur = 0; sp->clients_max = max_clients; if (fd < 0) { if (sg == NULL) { syslog(LOG_ERR, "server_init: NULL address and no file descriptor"); server_destroy(sp); if (debug) fprintf(stderr, "server_init(): End: Failure\n"); return NULL; } sp->sin = *sg; sp->fd = socket(SGFAM(sp->sin), SOCK_STREAM, 0); #ifdef HAVE_IPV6 if (sp->fd < 0 && (errno == EAFNOSUPPORT || errno == EPFNOSUPPORT) && SGFAM(sp->sin) == AF_INET6) { #if 0 /* Try to convert to IPv4 format... */ struct in6_addr *addr6 = (struct in6_addr *) SGADDRP(sp->sin); if (IN6_IS_ADDR_V4MAPPED(addr6)) { UINT32 addr4 = addr6->s6_addr32[3]; SGFAM(sp->sin) = AF_INET; * (UINT32 *) SGADDRP(sp->sin) = addr4; } #endif /* Let's try with an IPv4 socket - who knows, it might work */ errno = 0; sp->fd = socket(PF_INET, SOCK_STREAM, 0); } #endif if (sp->fd < 0) { syslog(LOG_ERR, "socket(%s, SOCK_STREAM) failed (errno=%d): %m", (SGFAM(sp->sin) == AF_INET ? "AF_INET" : "AF_INET6"), errno); server_destroy(sp); if (debug) fprintf(stderr, "server_init(): End: Failure\n"); return NULL; } (void) setsockopt(sp->fd, SOL_SOCKET, SO_REUSEADDR, (void *) &one, sizeof(one)); if (s_bind(sp->fd, (struct sockaddr *) &sp->sin, SGSOCKSIZE(sp->sin)) < 0) { char buf1[16]; syslog(LOG_ERR, "bind(%d,%s:%d) failed: %m", sp->fd, s_inet_ntox(&sp->sin, buf1, sizeof(buf1)), ntohs(SGPORT(sp->sin))); server_destroy(sp); if (debug) fprintf(stderr, "server_init(): End: Failure\n"); return NULL; } } else { sp->fd = fd; slen = sizeof(sp->sin); getsockname(sp->fd, (struct sockaddr *) &sp->sin, &slen); } /* We do this outside the 'if' clause to support broken Inetd implementations */ if (backlog >= 0 && listen(sp->fd, backlog) < 0) { syslog(LOG_ERR, "listen(%d, %d) failed: %m", sp->fd, backlog); server_destroy(sp); if (debug) fprintf(stderr, "server_init(): End: Failure\n"); return NULL; } sp->handler = handler; if (debug) fprintf(stderr, "server_init(): End: OK\n"); return sp; }