/* b01902062 藍ĉŒşç‘‹ */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "chttpd-socket.h" #include #include #include #include #include #include #include #define SOCKADDR(x) ((struct sockaddr*)(x)) #define SOCKLEN(x) ((socklen_t)(x)) int chttpd_socket_new_unix (const char* path, struct sockaddr_un* saddr, socklen_t* saddrlen) { struct sockaddr_un addr; socklen_t addrlen = sizeof (addr); size_t pathlen; memset (&addr, 0, sizeof (addr)); pathlen = sizeof (addr) - offsetof (struct sockaddr_un, sun_path) - 1; addr.sun_family = AF_UNIX; strncpy (addr.sun_path, path, pathlen); int sockfd = socket (AF_UNIX, SOCK_STREAM, 0); if (sockfd < 0) { return CHTTPD_SOCKET_NEW_ERROR_SOCKET; } if (bind (sockfd, SOCKADDR (&addr), addrlen) < 0) { close (sockfd); return CHTTPD_SOCKET_NEW_ERROR_BIND; } if (listen (sockfd, SOMAXCONN) < 0) { close (sockfd); return CHTTPD_SOCKET_NEW_ERROR_LISTEN; } if (saddr != NULL) { *saddr = addr; } if (saddrlen != NULL) { *saddrlen = addrlen; } return sockfd; } int chttpd_socket_new_inet (const char* host, const char* service, int domain, struct sockaddr* saddr, socklen_t* saddrlen, int* error) { if (service == NULL) { service = "http"; } if (domain != AF_INET && domain != AF_INET6) { domain = AF_UNSPEC; } struct addrinfo hints, *result; memset (&hints, 0, sizeof (hints)); hints.ai_family = domain; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; int gai_error = getaddrinfo (host, service, &hints, &result); if (gai_error != 0) { if (error != NULL) { *error = gai_error; } return CHTTPD_SOCKET_NEW_ERROR_GETADDRINFO; } int sockfd = -1; int bindrv = -1; for (struct addrinfo* iter = result; iter != NULL; iter = iter->ai_next) { sockfd = socket (iter->ai_family, SOCK_STREAM, 0); if (sockfd < 0) { continue; } if (iter->ai_family == AF_INET6) { setsockopt (sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){ 1 }, sizeof (int)); } bindrv = bind (sockfd, iter->ai_addr, iter->ai_addrlen); if (bindrv < 0) { close (sockfd); } else if (listen (sockfd, SOMAXCONN) < 0) { close (sockfd); } else { if (saddr != NULL) { switch (iter->ai_family) { case AF_INET: *(struct sockaddr_in*)(saddr) = *(struct sockaddr_in*)(iter->ai_addr); break; case AF_INET6: *(struct sockaddr_in6*)(saddr) = *(struct sockaddr_in6*)(iter->ai_addr); break; default: freeaddrinfo (result); return CHTTPD_SOCKET_NEW_ERROR_UNEXPECTED; } } if (saddrlen != NULL) { *saddrlen = iter->ai_addrlen; } freeaddrinfo (result); return sockfd; } } freeaddrinfo (result); if (sockfd < 0) { return CHTTPD_SOCKET_NEW_ERROR_SOCKET; } if (bindrv < 0) { return CHTTPD_SOCKET_NEW_ERROR_BIND; } return CHTTPD_SOCKET_NEW_ERROR_LISTEN; }