#include "uwsgi.h" extern struct uwsgi_server uwsgi; static int connect_to_unix(char *, int, int); static int connect_to_tcp(char *, int, int, int); static int connect_to_udp(char *, int); void uwsgi_socket_setup_protocol(struct uwsgi_socket *uwsgi_sock, char *protocol) { if (!protocol) protocol = "uwsgi"; struct uwsgi_protocol *up = uwsgi.protocols; while(up) { if (!strcmp(protocol, up->name)) { up->func(uwsgi_sock); return; } up = up->next; } uwsgi_log("unable to find protocol %s\n", protocol); exit(1); } static int uwsgi_socket_strcmp(char *sock1, char *sock2) { size_t sock1_len = strlen(sock1); size_t sock2_len = strlen(sock2); if (!uwsgi_starts_with(sock1, sock1_len, "0.0.0.0:", 8)) { sock1 += 7; sock1_len = strlen(sock1); } if (!uwsgi_starts_with(sock2, sock2_len, "0.0.0.0:", 8)) { sock2 += 7; sock2_len = strlen(sock2); } return uwsgi_strncmp(sock1, sock1_len, sock2, sock2_len); } char *uwsgi_getsockname(int fd) { socklen_t socket_type_len = sizeof(struct sockaddr_un); union uwsgi_sockaddr usa; union uwsgi_sockaddr_ptr gsa; char computed_port[6]; char ipv4a[INET_ADDRSTRLEN + 1]; gsa.sa = (struct sockaddr *) &usa; if (!getsockname(fd, gsa.sa, &socket_type_len)) { if (gsa.sa->sa_family == AF_UNIX) { // unnamed socket ? if (socket_type_len == sizeof(sa_family_t)) return ""; if (usa.sa_un.sun_path[0] == 0) { return uwsgi_concat2("@", usa.sa_un.sun_path + 1); } else { return uwsgi_str(usa.sa_un.sun_path); } } else { memset(ipv4a, 0, INET_ADDRSTRLEN + 1); memset(computed_port, 0, 6); if (snprintf(computed_port, 6, "%d", ntohs(gsa.sa_in->sin_port)) > 0) { if (inet_ntop(AF_INET, (const void *) &gsa.sa_in->sin_addr.s_addr, ipv4a, INET_ADDRSTRLEN)) { if (!strcmp("0.0.0.0", ipv4a)) { return uwsgi_concat2(":", computed_port); } else { return uwsgi_concat3(ipv4a, ":", computed_port); } } } } } return NULL; } static int create_server_socket(int domain, int type) { int serverfd = socket(domain, type, 0); if (serverfd < 0) { uwsgi_error("socket()"); uwsgi_nuclear_blast(); return -1; } if (uwsgi.close_on_exec2 && fcntl(serverfd, F_SETFD, FD_CLOEXEC) < 0) uwsgi_error("fcntl()"); if (domain != AF_UNIX) { int reuse = 1; if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse, sizeof(int)) < 0) { uwsgi_error("SO_REUSEADDR setsockopt()"); uwsgi_nuclear_blast(); return -1; } } if (type == SOCK_STREAM) { if (uwsgi.so_sndbuf) { socklen_t sndbuf = (socklen_t) uwsgi.so_sndbuf; if (setsockopt(serverfd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(socklen_t)) < 0) { uwsgi_error("SO_SNDBUF setsockopt()"); uwsgi_nuclear_blast(); return -1; } } if (uwsgi.so_rcvbuf) { socklen_t rcvbuf = (socklen_t) uwsgi.so_rcvbuf; if (setsockopt(serverfd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(socklen_t)) < 0) { uwsgi_error("SO_RCVBUF setsockopt()"); uwsgi_nuclear_blast(); return -1; } } #ifdef __linux__ long somaxconn = uwsgi_num_from_file("/proc/sys/net/core/somaxconn", 1); if (somaxconn > 0 && uwsgi.listen_queue > somaxconn) { uwsgi_log("Listen queue size is greater than the system max net.core.somaxconn (%li).\n", somaxconn); uwsgi_nuclear_blast(); return -1; } #endif } return serverfd; } int bind_to_unix_dgram(char *socket_name) { int serverfd; struct sockaddr_un *uws_addr; socklen_t len; serverfd = create_server_socket(AF_UNIX, SOCK_DGRAM); if (serverfd < 0) return -1; if (unlink(socket_name) != 0 && errno != ENOENT) { uwsgi_error("error removing unix socket, unlink()"); } uws_addr = uwsgi_calloc(sizeof(struct sockaddr_un)); uws_addr->sun_family = AF_UNIX; memcpy(uws_addr->sun_path, socket_name, UMIN(strlen(socket_name), 102)); len = strlen(socket_name); #ifdef __HAIKU__ if (bind(serverfd, (struct sockaddr *) uws_addr, sizeof(struct sockaddr_un))) { #else if (bind(serverfd, (struct sockaddr *) uws_addr, len + ((void *) uws_addr->sun_path - (void *) uws_addr)) != 0) { #endif uwsgi_error("bind()"); uwsgi_nuclear_blast(); return -1; } return serverfd; } int bind_to_unix(char *socket_name, int listen_queue, int chmod_socket, int abstract_socket) { int serverfd; struct sockaddr_un *uws_addr; socklen_t len; // leave 1 byte for abstract namespace (108 linux -> 104 bsd/mac) if (strlen(socket_name) > 102) { uwsgi_log("invalid socket name\n"); uwsgi_nuclear_blast(); return -1; } if (socket_name[0] == '@') { abstract_socket = 1; } else if (strlen(socket_name) > 1 && socket_name[0] == '\\' && socket_name[1] == '0') { abstract_socket = 1; } uws_addr = malloc(sizeof(struct sockaddr_un)); if (uws_addr == NULL) { uwsgi_error("malloc()"); uwsgi_nuclear_blast(); return -1; } memset(uws_addr, 0, sizeof(struct sockaddr_un)); serverfd = create_server_socket(AF_UNIX, SOCK_STREAM); if (serverfd < 0) { free(uws_addr); return -1; } if (abstract_socket == 0) { if (unlink(socket_name) != 0 && errno != ENOENT) { uwsgi_error("error removing unix socket, unlink()"); } } if (abstract_socket == 1) { uwsgi_log("setting abstract socket mode (warning: only Linux supports this)\n"); } uws_addr->sun_family = AF_UNIX; if (socket_name[0] == '@') { memcpy(uws_addr->sun_path + abstract_socket, socket_name + 1, UMIN(strlen(socket_name + 1), 101)); len = strlen(socket_name) + 1; } else if (strlen(socket_name) > 1 && socket_name[0] == '\\' && socket_name[1] == '0') { memcpy(uws_addr->sun_path + abstract_socket, socket_name + 2, UMIN(strlen(socket_name + 2), 101)); len = strlen(socket_name + 1) + 1; } else if (abstract_socket) { memcpy(uws_addr->sun_path + 1, socket_name, UMIN(strlen(socket_name), 101)); len = strlen(socket_name) + 1; } else { memcpy(uws_addr->sun_path + abstract_socket, socket_name, UMIN(strlen(socket_name), 102)); len = strlen(socket_name); } #ifdef __HAIKU__ if (bind(serverfd, (struct sockaddr *) uws_addr, sizeof(struct sockaddr_un))) { #else if (bind(serverfd, (struct sockaddr *) uws_addr, len + ((void *) uws_addr->sun_path - (void *) uws_addr)) != 0) { #endif uwsgi_error("bind()"); uwsgi_nuclear_blast(); return -1; } if (listen(serverfd, listen_queue) != 0) { uwsgi_error("listen()"); uwsgi_nuclear_blast(); return -1; } // chmod unix socket for lazy users if (chmod_socket == 1 && abstract_socket == 0) { if (uwsgi.chmod_socket_value) { if (chmod(socket_name, uwsgi.chmod_socket_value) != 0) { uwsgi_error("chmod()"); } } else { uwsgi_log("chmod() socket to 666 for lazy and brave users\n"); if (chmod(socket_name, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) != 0) { uwsgi_error("chmod()"); } } } free(uws_addr); return serverfd; } int bind_to_udp(char *socket_name, int multicast, int broadcast) { int serverfd; struct sockaddr_in uws_addr; char *udp_port; int bcast = 1; struct ip_mreq mc; udp_port = strchr(socket_name, ':'); if (udp_port == NULL) { return -1; } udp_port[0] = 0; if (socket_name[0] == 0 && multicast) { uwsgi_log("invalid multicast address\n"); return -1; } memset(&uws_addr, 0, sizeof(struct sockaddr_in)); uws_addr.sin_family = AF_INET; uws_addr.sin_port = htons(atoi(udp_port + 1)); if (!broadcast && !multicast) { char quad[4]; char *first_part = strchr(socket_name, '.'); if (first_part && first_part - socket_name < 4) { memset(quad, 0, 4); memcpy(quad, socket_name, first_part - socket_name); if (atoi(quad) >= 224 && atoi(quad) <= 239) { multicast = 1; } } if (!strcmp(socket_name, "255.255.255.255")) { broadcast = 1; } } if (broadcast) { uws_addr.sin_addr.s_addr = INADDR_BROADCAST; } else if (socket_name[0] != 0) { uws_addr.sin_addr.s_addr = inet_addr(socket_name); } else { uws_addr.sin_addr.s_addr = INADDR_ANY; } serverfd = create_server_socket(AF_INET, SOCK_DGRAM); if (serverfd < 0) return -1; if (multicast) { // if multicast is enabled remember to bind to INADDR_ANY uws_addr.sin_addr.s_addr = INADDR_ANY; mc.imr_multiaddr.s_addr = inet_addr(socket_name); mc.imr_interface.s_addr = INADDR_ANY; } if (broadcast) { if (setsockopt(serverfd, SOL_SOCKET, SO_BROADCAST, &bcast, sizeof(bcast))) { perror("setsockopt"); close(serverfd); return -1; } } if (bind(serverfd, (struct sockaddr *) &uws_addr, sizeof(uws_addr)) != 0) { uwsgi_error("bind()"); close(serverfd); return -1; } if (multicast) { uwsgi_log("[uwsgi-mcast] joining multicast group: %s:%d\n", socket_name, ntohs(uws_addr.sin_port)); if (setsockopt(serverfd, IPPROTO_IP, IP_MULTICAST_LOOP, &uwsgi.multicast_loop, sizeof(uwsgi.multicast_loop))) { uwsgi_error("setsockopt()"); } if (setsockopt(serverfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mc, sizeof(mc))) { uwsgi_error("setsockopt()"); } if (setsockopt(serverfd, IPPROTO_IP, IP_MULTICAST_TTL, &uwsgi.multicast_ttl, sizeof(uwsgi.multicast_ttl))) { uwsgi_error("setsockopt()"); } } udp_port[0] = ':'; return serverfd; } static int uwsgi_connect_do(char *socket_name, int timeout, int async) { char *tcp_port = strchr(socket_name, ':'); if (tcp_port) { tcp_port[0] = 0; tcp_port++; return connect_to_tcp(socket_name, atoi(tcp_port), timeout, async); } return connect_to_unix(socket_name, timeout, async); } int uwsgi_connectn(char *socket_name, uint16_t len, int timeout, int async) { char *zeroed_socket_name = uwsgi_concat2n(socket_name, len, "", 0); int fd = uwsgi_connect_do(zeroed_socket_name, timeout, async); free(zeroed_socket_name); return fd; } int uwsgi_connect(char *socket_name, int timeout, int async) { char *zeroed_socket_name = uwsgi_str(socket_name); int fd = uwsgi_connect_do(zeroed_socket_name, timeout, async); free(zeroed_socket_name); return fd; } int uwsgi_connect_udp(char *socket_name) { int fd = -1; char *zeroed_socket_name = uwsgi_str(socket_name); char *udp_port = strchr(zeroed_socket_name, ':'); if (!udp_port) goto end; *udp_port = 0; udp_port++; fd = connect_to_udp(zeroed_socket_name, atoi(udp_port)); end: free(zeroed_socket_name); return fd; } static int connect_to_unix(char *socket_name, int timeout, int async) { struct pollfd uwsgi_poll; struct sockaddr_un uws_addr; socklen_t un_size = sizeof(struct sockaddr_un); memset(&uws_addr, 0, sizeof(struct sockaddr_un)); uws_addr.sun_family = AF_UNIX; if (socket_name[0] == '@') { un_size = sizeof(uws_addr.sun_family) + strlen(socket_name) + 1; memcpy(uws_addr.sun_path + 1, socket_name + 1, UMIN(strlen(socket_name + 1), 101)); } else if (strlen(socket_name) > 1 && socket_name[0] == '\\' && socket_name[1] == '0') { un_size = sizeof(uws_addr.sun_family) + strlen(socket_name + 1) + 1; memcpy(uws_addr.sun_path + 1, socket_name + 2, UMIN(strlen(socket_name + 2), 101)); } else { memcpy(uws_addr.sun_path, socket_name, UMIN(strlen(socket_name), 102)); } #if defined(__linux__) && defined(SOCK_NONBLOCK) && !defined(OBSOLETE_LINUX_KERNEL) uwsgi_poll.fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0); #else uwsgi_poll.fd = socket(AF_UNIX, SOCK_STREAM, 0); #endif if (uwsgi_poll.fd < 0) { uwsgi_error("socket()"); return -1; } uwsgi_poll.events = POLLIN; if (timed_connect(&uwsgi_poll, (const struct sockaddr *) &uws_addr, un_size, timeout, async)) { // avoid error storm //uwsgi_error("connect()"); close(uwsgi_poll.fd); return -1; } return uwsgi_poll.fd; } static int connect_to_tcp(char *socket_name, int port, int timeout, int async) { struct pollfd uwsgi_poll; struct sockaddr_in uws_addr; memset(&uws_addr, 0, sizeof(struct sockaddr_in)); uws_addr.sin_family = AF_INET; uws_addr.sin_port = htons(port); if (socket_name[0] == 0) { uws_addr.sin_addr.s_addr = INADDR_ANY; } else { uws_addr.sin_addr.s_addr = inet_addr(socket_name); } #if defined(__linux__) && defined(SOCK_NONBLOCK) && !defined(OBSOLETE_LINUX_KERNEL) uwsgi_poll.fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); #else uwsgi_poll.fd = socket(AF_INET, SOCK_STREAM, 0); #endif if (uwsgi_poll.fd < 0) { uwsgi_error("connect_to_tcp()/socket()"); return -1; } uwsgi_poll.events = POLLIN; if (timed_connect(&uwsgi_poll, (const struct sockaddr *) &uws_addr, sizeof(struct sockaddr_in), timeout, async)) { //uwsgi_error("connect()"); close(uwsgi_poll.fd); return -1; } return uwsgi_poll.fd; } static int connect_to_udp(char *socket_name, int port) { struct sockaddr_in uws_addr; memset(&uws_addr, 0, sizeof(struct sockaddr_in)); uws_addr.sin_family = AF_INET; uws_addr.sin_port = htons(port); if (socket_name[0] == 0) { uws_addr.sin_addr.s_addr = INADDR_ANY; } else { uws_addr.sin_addr.s_addr = inet_addr(socket_name); } int fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { uwsgi_error("connect_to_udp()/socket()"); return -1; } if (connect(fd, (const struct sockaddr *) &uws_addr, sizeof(struct sockaddr_in))) { close(fd); return -1; } return fd; } char *generate_socket_name(char *socket_name) { char *asterisk = strchr(socket_name, '*'); char *tcp_port; int i; char *ptr = socket_name; // ltrim spaces for (i = 0; i < (int) strlen(socket_name); i++) { if (isspace((int) socket_name[i])) { ptr++; } else { break; } } socket_name = ptr; if (socket_name[0] == 0) { uwsgi_log("invalid/empty uwsgi socket name\n"); exit(1); } tcp_port = strchr(socket_name, ':'); if (!tcp_port) return socket_name; if (asterisk) { #ifndef UWSGI_HAS_IFADDRS uwsgi_log("your system does not support ifaddrs subsystem\n"); #else char *new_socket; #ifdef UWSGI_DEBUG uwsgi_log("generate_socket_name(%s)\n", socket_name); #endif // get all the AF_INET addresses available struct ifaddrs *ifap = NULL, *ifa, *ifaf; if (getifaddrs(&ifap)) { uwsgi_error("getifaddrs()"); uwsgi_nuclear_blast(); } // here socket_name will be truncated asterisk[0] = 0; #ifdef UWSGI_DEBUG uwsgi_log("asterisk found\n"); #endif char new_addr[16]; struct sockaddr_in *sin; ifa = ifap; while (ifa) { memset(new_addr, 0, 16); if (!ifa->ifa_addr) goto next; sin = (struct sockaddr_in *) ifa->ifa_addr; if (inet_ntop(AF_INET, (void *) &sin->sin_addr.s_addr, new_addr, 16)) { if (!strncmp(socket_name, new_addr, strlen(socket_name))) { asterisk[0] = '*'; new_socket = uwsgi_concat3(new_addr, ":", tcp_port + 1); uwsgi_log("[uwsgi-autoip] found %s for %s on interface %s\n", new_socket, socket_name, ifa->ifa_name); freeifaddrs(ifap); return new_socket; } } next: ifaf = ifa; ifa = ifaf->ifa_next; } uwsgi_log("unable to find a valid socket address\n"); #endif uwsgi_nuclear_blast(); } return socket_name; } socklen_t socket_to_un_addr(char *socket_name, struct sockaddr_un * sun_addr) { size_t len = strlen(socket_name); if (len > 102) { uwsgi_log("invalid UNIX socket address: %s\n", socket_name); uwsgi_nuclear_blast(); } memset(sun_addr, 0, sizeof(struct sockaddr_un)); sun_addr->sun_family = AF_UNIX; // abstract socket if (socket_name[0] == '@') { memcpy(sun_addr->sun_path + 1, socket_name + 1, UMIN(len - 1, 101)); len = strlen(socket_name) + 1; } else if (len > 1 && socket_name[0] == '\\' && socket_name[1] == '0') { memcpy(sun_addr->sun_path + 1, socket_name + 2, UMIN(len - 2, 101)); len = strlen(socket_name + 1) + 1; } else { memcpy(sun_addr->sun_path, socket_name, UMIN(len, 102)); } return sizeof(sun_addr->sun_family) + len; } socklen_t socket_to_in_addr(char *socket_name, char *port, int portn, struct sockaddr_in *sin_addr) { memset(sin_addr, 0, sizeof(struct sockaddr_in)); sin_addr->sin_family = AF_INET; if (port) { *port = 0; sin_addr->sin_port = htons(atoi(port + 1)); } else { sin_addr->sin_port = htons(portn); } if (socket_name[0] == 0) { sin_addr->sin_addr.s_addr = INADDR_ANY; } else { char *resolved = uwsgi_resolve_ip(socket_name); if (resolved) { sin_addr->sin_addr.s_addr = inet_addr(resolved); } else { sin_addr->sin_addr.s_addr = inet_addr(socket_name); } } if (port) { *port = ':'; } return sizeof(struct sockaddr_in); } int bind_to_tcp(char *socket_name, int listen_queue, char *tcp_port) { int serverfd; #ifdef AF_INET6 struct sockaddr_in6 uws_addr; #else struct sockaddr_in uws_addr; #endif int family = AF_INET; socklen_t addr_len = sizeof(struct sockaddr_in); #ifdef AF_INET6 if (socket_name[0] == '[' && tcp_port[-1] == ']') { family = AF_INET6; socket_to_in_addr6(socket_name, tcp_port, 0, &uws_addr); addr_len = sizeof(struct sockaddr_in6); } else { #endif socket_to_in_addr(socket_name, tcp_port, 0, (struct sockaddr_in *) &uws_addr); #ifdef AF_INET6 } #endif serverfd = create_server_socket(family, SOCK_STREAM); if (serverfd < 0) return -1; #ifdef __linux__ #ifndef IP_FREEBIND #define IP_FREEBIND 15 #endif if (uwsgi.freebind) { if (setsockopt(serverfd, SOL_IP, IP_FREEBIND, (const void *) &uwsgi.freebind, sizeof(int)) < 0) { uwsgi_error("IP_FREEBIND setsockopt()"); uwsgi_nuclear_blast(); return -1; } } #endif if (uwsgi.reuse_port) { #ifdef SO_REUSEPORT if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEPORT, (const void *) &uwsgi.reuse_port, sizeof(int)) < 0) { uwsgi_error("SO_REUSEPORT setsockopt()"); uwsgi_nuclear_blast(); return -1; } #else uwsgi_log("!!! your system does not support SO_REUSEPORT !!!\n"); #endif } if (uwsgi.tcp_fast_open) { #ifdef TCP_FASTOPEN #ifndef SOL_TCP #define SOL_TCP IPPROTO_TCP #endif if (setsockopt(serverfd, SOL_TCP, TCP_FASTOPEN, (const void *) &uwsgi.tcp_fast_open, sizeof(int)) < 0) { uwsgi_error("TCP_FASTOPEN setsockopt()"); } else { uwsgi_log("TCP_FASTOPEN enabled on %s\n", socket_name); } #else uwsgi_log("!!! your system does not support TCP_FASTOPEN !!!\n"); #endif } if (uwsgi.so_send_timeout) { struct timeval tv; tv.tv_sec = uwsgi.so_send_timeout; tv.tv_usec = 0; if (setsockopt(serverfd, SOL_SOCKET, SO_SNDTIMEO, (const void *) &tv, sizeof(struct timeval)) < 0) { uwsgi_error("SO_SNDTIMEO setsockopt()"); uwsgi_nuclear_blast(); return -1; } } if (!uwsgi.no_defer_accept) { #ifdef __linux__ if (setsockopt(serverfd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &uwsgi.socket_timeout, sizeof(int))) { uwsgi_error("TCP_DEFER_ACCEPT setsockopt()"); } // OSX has no SO_ACCEPTFILTER !!! #elif defined(__freebsd__) struct accept_filter_arg afa; strcpy(afa.af_name, "dataready"); afa.af_arg[0] = 0; if (setsockopt(serverfd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(struct accept_filter_arg))) { uwsgi_error("SO_ACCEPTFILTER setsockopt()"); } #endif } if (uwsgi.so_keepalive) { if (setsockopt(serverfd, SOL_SOCKET, SO_KEEPALIVE, &uwsgi.so_keepalive, sizeof(int))) { uwsgi_error("SO_KEEPALIVE setsockopt()"); } } if (bind(serverfd, (struct sockaddr *) &uws_addr, addr_len) != 0) { if (errno == EADDRINUSE) { uwsgi_log("probably another instance of uWSGI is running on the same address (%s).\n", socket_name); } uwsgi_error("bind()"); uwsgi_nuclear_blast(); return -1; } if (listen(serverfd, listen_queue) != 0) { uwsgi_error("listen()"); uwsgi_nuclear_blast(); return -1; } if (tcp_port) tcp_port[0] = ':'; return serverfd; } // set non-blocking socket void uwsgi_socket_nb(int fd) { int arg; arg = fcntl(fd, F_GETFL, NULL); if (arg < 0) { uwsgi_error("fcntl()"); return; } arg |= O_NONBLOCK; if (fcntl(fd, F_SETFL, arg) < 0) { uwsgi_error("fcntl()"); return; } } // set blocking socket void uwsgi_socket_b(int fd) { int arg; arg = fcntl(fd, F_GETFL, NULL); if (arg < 0) { uwsgi_error("fcntl()"); return; } arg &= (~O_NONBLOCK); if (fcntl(fd, F_SETFL, arg) < 0) { uwsgi_error("fcntl()"); return; } } int timed_connect(struct pollfd *fdpoll, const struct sockaddr *addr, int addr_size, int timeout, int async) { int ret; int soopt = 0; socklen_t solen = sizeof(int); int cnt; /* set non-blocking socket */ #if defined(__linux__) && defined(SOCK_NONBLOCK) && !defined(OBSOLETE_LINUX_KERNEL) // hmm, nothing to do, as we are already non-blocking #else int arg = fcntl(fdpoll->fd, F_GETFL, NULL); if (arg < 0) { uwsgi_error("fcntl()"); return -1; } arg |= O_NONBLOCK; if (fcntl(fdpoll->fd, F_SETFL, arg) < 0) { uwsgi_error("fcntl()"); return -1; } #endif #ifdef MSG_FASTOPEN if (addr->sa_family == AF_INET && uwsgi.tcp_fast_open_client) { ret = sendto(fdpoll->fd, "", 0, MSG_FASTOPEN, addr, addr_size); } else { #endif ret = connect(fdpoll->fd, addr, addr_size); #ifdef MSG_FASTOPEN } #endif if (async) { if (ret < 0 && errno != EINPROGRESS) { return -1; } return 0; } #if defined(__linux__) && defined(SOCK_NONBLOCK) && !defined(OBSOLETE_LINUX_KERNEL) uwsgi_socket_b(fdpoll->fd); #else /* re-set blocking socket */ arg &= (~O_NONBLOCK); if (fcntl(fdpoll->fd, F_SETFL, arg) < 0) { uwsgi_error("fcntl()"); return -1; } #endif if (ret < 0) { /* check what happened */ // in progress ? if (errno == EINPROGRESS) { if (timeout < 1) timeout = 3; fdpoll->events = POLLOUT; cnt = poll(fdpoll, 1, timeout * 1000); /* check for errors */ if (cnt < 0 && errno != EINTR) { uwsgi_error("poll()"); return -1; } /* something hapened on the socket ... */ else if (cnt > 0) { if (getsockopt(fdpoll->fd, SOL_SOCKET, SO_ERROR, (void *) (&soopt), &solen) < 0) { uwsgi_error("getsockopt()"); return -1; } /* is something bad ? */ if (soopt) { return -1; } } /* timeout */ else { return -1; } } else { return -1; } } return 0; } int uwsgi_count_sockets(struct uwsgi_socket *uwsgi_sock) { int count = 0; while (uwsgi_sock) { count++; uwsgi_sock = uwsgi_sock->next; } return count; } int uwsgi_get_socket_num(struct uwsgi_socket *uwsgi_sock) { int count = 0; struct uwsgi_socket *current_sock = uwsgi.sockets; while (current_sock) { if (uwsgi_sock == current_sock) { return count; } count++; current_sock = current_sock->next; } return -1; } int uwsgi_get_shared_socket_num(struct uwsgi_socket *uwsgi_sock) { int count = 0; struct uwsgi_socket *current_sock = uwsgi.shared_sockets; while (current_sock) { if (uwsgi_sock == current_sock) { return count; } count++; current_sock = current_sock->next; } return -1; } struct uwsgi_socket *uwsgi_new_shared_socket(char *name) { struct uwsgi_socket *uwsgi_sock = uwsgi.shared_sockets, *old_uwsgi_sock; if (!uwsgi_sock) { uwsgi.shared_sockets = uwsgi_malloc(sizeof(struct uwsgi_socket)); uwsgi_sock = uwsgi.shared_sockets; } else { while (uwsgi_sock) { old_uwsgi_sock = uwsgi_sock; uwsgi_sock = uwsgi_sock->next; } uwsgi_sock = uwsgi_malloc(sizeof(struct uwsgi_socket)); old_uwsgi_sock->next = uwsgi_sock; } memset(uwsgi_sock, 0, sizeof(struct uwsgi_socket)); uwsgi_sock->name = name; uwsgi_sock->fd = -1; return uwsgi_sock; } struct uwsgi_socket *uwsgi_new_socket(char *name) { struct uwsgi_socket *uwsgi_sock = uwsgi.sockets, *old_uwsgi_sock; struct sockaddr_in sin; socklen_t socket_type_len; if (!uwsgi_sock) { uwsgi.sockets = uwsgi_malloc(sizeof(struct uwsgi_socket)); uwsgi_sock = uwsgi.sockets; } else { while (uwsgi_sock) { old_uwsgi_sock = uwsgi_sock; uwsgi_sock = uwsgi_sock->next; } uwsgi_sock = uwsgi_malloc(sizeof(struct uwsgi_socket)); old_uwsgi_sock->next = uwsgi_sock; } memset(uwsgi_sock, 0, sizeof(struct uwsgi_socket)); uwsgi_sock->name = name; uwsgi_sock->fd = -1; if (!name) return uwsgi_sock; if (name[0] == '=') { int shared_socket = atoi(uwsgi_sock->name + 1); if (shared_socket >= 0) { struct uwsgi_socket *uss = uwsgi_get_shared_socket_by_num(shared_socket); if (!uss) { uwsgi_log("unable to use shared socket %d\n", shared_socket); exit(1); } uwsgi_sock->bound = 1; uwsgi_sock->shared = 1; uwsgi_sock->from_shared = shared_socket; return uwsgi_sock; } } if (!uwsgi_startswith(name, "fd://", 5)) { uwsgi_add_socket_from_fd(uwsgi_sock, atoi(name + 5)); return uwsgi_sock; } char *tcp_port = strrchr(name, ':'); if (tcp_port) { // INET socket, check for 0 port if (tcp_port[1] == 0 || tcp_port[1] == '0') { uwsgi_sock->fd = bind_to_tcp(name, uwsgi.listen_queue, tcp_port); uwsgi_sock->family = AF_INET; uwsgi_sock->bound = 1; uwsgi_sock->auto_port = 1; socket_type_len = sizeof(struct sockaddr_in); if (getsockname(uwsgi_sock->fd, (struct sockaddr *) &sin, &socket_type_len)) { uwsgi_error("getsockname()"); exit(1); } char *auto_port = uwsgi_num2str(ntohs(sin.sin_port)); uwsgi_sock->name = uwsgi_concat3n(name, tcp_port - name, ":", 1, auto_port, strlen(auto_port)); } // is it fd 0 ? else if (tcp_port[1] == ':') { uwsgi_sock->fd = 0; uwsgi_sock->family = AF_INET; uwsgi_sock->bound = 1; socket_type_len = sizeof(struct sockaddr_in); if (getsockname(0, (struct sockaddr *) &sin, &socket_type_len)) { uwsgi_error("getsockname()"); exit(1); } char *auto_port = uwsgi_num2str(ntohs(sin.sin_port)); char *auto_ip = inet_ntoa(sin.sin_addr); uwsgi_sock->name = uwsgi_concat3n(auto_ip, strlen(auto_ip), ":", 1, auto_port, strlen(auto_port)); free(auto_port); } } return uwsgi_sock; } void uwsgi_add_socket_from_fd(struct uwsgi_socket *uwsgi_sock, int fd) { socklen_t socket_type_len; union uwsgi_sockaddr_ptr gsa, isa; union uwsgi_sockaddr usa; int abstract = 0; socket_type_len = sizeof(struct sockaddr_un); gsa.sa = &usa.sa; if (!getsockname(fd, gsa.sa, &socket_type_len)) { if (socket_type_len <= 2) { // unbound socket return; } if (gsa.sa->sa_family == AF_UNIX) { if (usa.sa_un.sun_path[0] == 0) abstract = 1; // is it a zerg ? if (uwsgi_sock->name == NULL) { uwsgi_sock->fd = fd; uwsgi_sock->family = AF_UNIX; uwsgi_sock->bound = 1; uwsgi_sock->name = uwsgi_concat2(usa.sa_un.sun_path + abstract, ""); if (uwsgi.zerg) { uwsgi_log("uwsgi zerg socket %d attached to UNIX address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), usa.sa_un.sun_path + abstract, uwsgi_sock->fd); } else { uwsgi_log("uwsgi socket %d attached to UNIX address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), usa.sa_un.sun_path + abstract, uwsgi_sock->fd); } return; } if (!uwsgi_startswith(uwsgi_sock->name, "fd://", 5)) { if (atoi(uwsgi_sock->name + 5) == fd) { uwsgi_sock->fd = fd; uwsgi_sock->family = AF_UNIX; uwsgi_sock->bound = 1; uwsgi_sock->name = uwsgi_str(usa.sa_un.sun_path + abstract); uwsgi_log("uwsgi socket %d inherited UNIX address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd); } } else if (!strcmp(usa.sa_un.sun_path + abstract, uwsgi_sock->name + abstract)) { uwsgi_sock->fd = fd; uwsgi_sock->family = AF_UNIX; uwsgi_sock->bound = 1; uwsgi_log("uwsgi socket %d inherited UNIX address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd); } } else if (gsa.sa->sa_family == AF_INET) { char *computed_addr; char computed_port[6]; isa.sa_in = (struct sockaddr_in *) &usa; char ipv4a[INET_ADDRSTRLEN + 1]; memset(ipv4a, 0, INET_ADDRSTRLEN + 1); memset(computed_port, 0, 6); if (snprintf(computed_port, 6, "%d", ntohs(isa.sa_in->sin_port)) > 0) { if (inet_ntop(AF_INET, (const void *) &isa.sa_in->sin_addr.s_addr, ipv4a, INET_ADDRSTRLEN)) { if (!strcmp("0.0.0.0", ipv4a)) { computed_addr = uwsgi_concat2(":", computed_port); } else { computed_addr = uwsgi_concat3(ipv4a, ":", computed_port); } // is it a zerg ? if (uwsgi_sock->name == NULL) { uwsgi_sock->fd = fd; uwsgi_sock->family = AF_INET; uwsgi_sock->bound = 1; uwsgi_sock->name = uwsgi_concat2(computed_addr, ""); if (uwsgi.zerg) { uwsgi_log("uwsgi zerg socket %d attached to INET address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), computed_addr, uwsgi_sock->fd); } else { uwsgi_log("uwsgi socket %d attached to INET address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), computed_addr, uwsgi_sock->fd); } free(computed_addr); return; } char *asterisk = strchr(uwsgi_sock->name, '*'); int match = 1; if (asterisk) { asterisk[0] = 0; match = strncmp(computed_addr, uwsgi_sock->name, strlen(uwsgi_sock->name)); asterisk[0] = '*'; } else { if (!uwsgi_startswith(uwsgi_sock->name, "fd://", 5)) { if (atoi(uwsgi_sock->name + 5) == fd) { uwsgi_sock->fd = fd; uwsgi_sock->family = AF_INET; uwsgi_sock->bound = 1; uwsgi_sock->name = uwsgi_str(computed_addr); uwsgi_log("uwsgi socket %d inherited INET address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd); match = 1; } } else { match = strcmp(computed_addr, uwsgi_sock->name); } } if (!match) { uwsgi_sock->fd = fd; uwsgi_sock->family = AF_INET; uwsgi_sock->bound = 1; uwsgi_log("uwsgi socket %d inherited INET address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd); } free(computed_addr); } } } #ifdef AF_INET6 else if (gsa.sa->sa_family == AF_INET6) { char *computed_addr; char computed_port[6]; isa.sa_in6 = (struct sockaddr_in6 *) &usa; char ipv6a[INET6_ADDRSTRLEN + 1]; memset(ipv6a, 0, INET_ADDRSTRLEN + 1); memset(computed_port, 0, 6); int match = 0; if (snprintf(computed_port, 6, "%d", ntohs(isa.sa_in6->sin6_port)) > 0) { if (inet_ntop(AF_INET6, (const void *) &isa.sa_in6->sin6_addr.s6_addr, ipv6a, INET6_ADDRSTRLEN)) { uwsgi_log("ipv6a = %s\n", ipv6a); if (!strcmp("::", ipv6a)) { computed_addr = uwsgi_concat2("[::]:", computed_port); } else { computed_addr = uwsgi_concat4("[", ipv6a, "]:", computed_port); } // is it a zerg ? if (uwsgi_sock->name == NULL) { uwsgi_sock->fd = fd; uwsgi_sock->family = AF_INET6; uwsgi_sock->bound = 1; uwsgi_sock->name = uwsgi_concat2(computed_addr, ""); if (uwsgi.zerg) { uwsgi_log("uwsgi zerg socket %d attached to INET6 address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), computed_addr, uwsgi_sock->fd); } else { uwsgi_log("uwsgi socket %d attached to INET6 address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), computed_addr, uwsgi_sock->fd); } free(computed_addr); return; } if (!uwsgi_startswith(uwsgi_sock->name, "fd://", 5)) { if (atoi(uwsgi_sock->name + 5) == fd) { uwsgi_sock->fd = fd; uwsgi_sock->family = AF_INET6; uwsgi_sock->bound = 1; uwsgi_sock->name = uwsgi_str(computed_addr); uwsgi_log("uwsgi socket %d inherited INET address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd); match = 1; } } else { match = strcmp(computed_addr, uwsgi_sock->name); } if (!match) { uwsgi_sock->fd = fd; uwsgi_sock->family = AF_INET; uwsgi_sock->bound = 1; uwsgi_log("uwsgi socket %d inherited INET6 address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd); } free(computed_addr); } } } #endif } } void uwsgi_close_all_sockets() { struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (uwsgi_sock->bound) close(uwsgi_sock->fd); uwsgi_sock = uwsgi_sock->next; } } void uwsgi_close_all_unshared_sockets() { struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (uwsgi_sock->bound && !uwsgi_sock->shared) close(uwsgi_sock->fd); uwsgi_sock = uwsgi_sock->next; } } struct uwsgi_socket *uwsgi_del_socket(struct uwsgi_socket *uwsgi_sock) { struct uwsgi_socket *uwsgi_current_sock = uwsgi.sockets, *old_sock = NULL; while (uwsgi_current_sock) { if (uwsgi_current_sock == uwsgi_sock) { // parent instance ? if (old_sock == NULL) { uwsgi.sockets = uwsgi_current_sock->next; free(uwsgi_current_sock); return uwsgi.sockets; } else { old_sock->next = uwsgi_current_sock->next; free(uwsgi_current_sock); return old_sock->next; } } old_sock = uwsgi_current_sock; uwsgi_current_sock = uwsgi_current_sock->next; } return NULL; } int uwsgi_get_shared_socket_fd_by_num(int num) { int counter = 0; struct uwsgi_socket *found_sock = NULL, *uwsgi_sock = uwsgi.shared_sockets; while (uwsgi_sock) { if (counter == num) { found_sock = uwsgi_sock; break; } counter++; uwsgi_sock = uwsgi_sock->next; } if (found_sock) { return found_sock->fd; } return -1; } struct uwsgi_socket *uwsgi_get_shared_socket_by_num(int num) { int counter = 0; struct uwsgi_socket *found_sock = NULL, *uwsgi_sock = uwsgi.shared_sockets; while (uwsgi_sock) { if (counter == num) { found_sock = uwsgi_sock; break; } counter++; uwsgi_sock = uwsgi_sock->next; } if (found_sock) { return found_sock; } return NULL; } struct uwsgi_socket *uwsgi_get_socket_by_num(int num) { int counter = 0; struct uwsgi_socket *found_sock = NULL, *uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (counter == num) { found_sock = uwsgi_sock; break; } counter++; uwsgi_sock = uwsgi_sock->next; } if (found_sock) { return found_sock; } return NULL; } void uwsgi_add_sockets_to_queue(int queue, int async_id) { struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (uwsgi_sock->fd_threads && async_id > -1 && uwsgi_sock->fd_threads[async_id] > -1) { event_queue_add_fd_read(queue, uwsgi_sock->fd_threads[async_id]); } else if (uwsgi_sock->fd > -1) { event_queue_add_fd_read(queue, uwsgi_sock->fd); } uwsgi_sock = uwsgi_sock->next; } } void uwsgi_del_sockets_from_queue(int queue) { struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (uwsgi_sock->fd == -1) goto nextsock; event_queue_del_fd(queue, uwsgi_sock->fd, event_queue_read()); nextsock: uwsgi_sock = uwsgi_sock->next; } } int uwsgi_is_bad_connection(int fd) { int soopt = 0; socklen_t solen = sizeof(int); if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *) (&soopt), &solen) < 0) { return -1; } // will be 0 if all ok return soopt; } int uwsgi_socket_is_already_bound(char *name) { struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (uwsgi_sock->name && !strcmp(uwsgi_sock->name, name) && uwsgi_sock->bound) { return 1; } uwsgi_sock = uwsgi_sock->next; } return 0; } int uwsgi_socket_uniq(struct uwsgi_socket *list, struct uwsgi_socket *item) { int found = 0; if (list == item) return 0; struct uwsgi_socket *uwsgi_sock = list; while (uwsgi_sock && uwsgi_sock != item) { if (uwsgi_sock->fd == -1) goto nextsock; if (!strcmp(uwsgi_sock->name, item->name)) { found = 1; break; } nextsock: uwsgi_sock = uwsgi_sock->next; } return found; } void uwsgi_manage_zerg(int fd, int num_sockets, int *sockets) { struct sockaddr_un zsun; socklen_t zsun_len = sizeof(struct sockaddr_un); int zerg_client = accept(fd, (struct sockaddr *) &zsun, &zsun_len); if (zerg_client < 0) { uwsgi_error("zerg: accept()"); return; } if (!num_sockets) { num_sockets = uwsgi_count_sockets(uwsgi.sockets); } struct msghdr zerg_msg; void *zerg_msg_control = uwsgi_malloc(CMSG_SPACE(sizeof(int) * num_sockets)); struct iovec zerg_iov[2]; struct cmsghdr *cmsg; zerg_iov[0].iov_base = "uwsgi-zerg"; zerg_iov[0].iov_len = 10; zerg_iov[1].iov_base = &num_sockets; zerg_iov[1].iov_len = sizeof(int); zerg_msg.msg_name = NULL; zerg_msg.msg_namelen = 0; zerg_msg.msg_iov = zerg_iov; zerg_msg.msg_iovlen = 2; zerg_msg.msg_flags = 0; zerg_msg.msg_control = zerg_msg_control; zerg_msg.msg_controllen = CMSG_SPACE(sizeof(int) * num_sockets); cmsg = CMSG_FIRSTHDR(&zerg_msg); cmsg->cmsg_len = CMSG_LEN(sizeof(int) * num_sockets); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; unsigned char *zerg_fd_ptr = CMSG_DATA(cmsg); if (!sockets) { struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; int uniq_count = 0; while (uwsgi_sock) { if (uwsgi_sock->fd == -1) goto nextsock; if (!uwsgi_socket_uniq(uwsgi.sockets, uwsgi_sock)) { memcpy(zerg_fd_ptr, &uwsgi_sock->fd, sizeof(int)); zerg_fd_ptr += sizeof(int); uniq_count++; } nextsock: uwsgi_sock = uwsgi_sock->next; } zerg_iov[1].iov_base = &uniq_count; cmsg->cmsg_len = CMSG_LEN(sizeof(int) * uniq_count); } else { memcpy(zerg_fd_ptr, sockets, sizeof(int) * num_sockets); } if (sendmsg(zerg_client, &zerg_msg, 0) < 0) { uwsgi_error("sendmsg()"); } free(zerg_msg_control); close(zerg_client); } #ifdef AF_INET6 socklen_t socket_to_in_addr6(char *socket_name, char *port, int portn, struct sockaddr_in6 * sin_addr) { memset(sin_addr, 0, sizeof(struct sockaddr_in6)); sin_addr->sin6_family = AF_INET6; if (port) { *port = 0; sin_addr->sin6_port = htons(atoi(port + 1)); } else { sin_addr->sin6_port = htons(portn); } if (!strcmp(socket_name, "[::]")) { sin_addr->sin6_addr = in6addr_any; } else { char *sanitized_sn = uwsgi_concat2n(socket_name + 1, strlen(socket_name + 1) - 1, "", 0); char *resolved = uwsgi_resolve_ip(sanitized_sn); if (resolved) { inet_pton(AF_INET6, resolved, sin_addr->sin6_addr.s6_addr); } else { inet_pton(AF_INET6, sanitized_sn, sin_addr->sin6_addr.s6_addr); } free(sanitized_sn); } if (port) { *port = ':'; } return sizeof(struct sockaddr_in6); } #endif void uwsgi_setup_shared_sockets() { int i; struct uwsgi_socket *shared_sock = uwsgi.shared_sockets; while (shared_sock) { if (!uwsgi.is_a_reload) { char *tcp_port = strrchr(shared_sock->name, ':'); int current_defer_accept = uwsgi.no_defer_accept; if (shared_sock->no_defer) { uwsgi.no_defer_accept = 1; } if (tcp_port == NULL) { shared_sock->fd = bind_to_unix(shared_sock->name, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket); shared_sock->family = AF_UNIX; uwsgi_log("uwsgi shared socket %d bound to UNIX address %s fd %d\n", uwsgi_get_shared_socket_num(shared_sock), shared_sock->name, shared_sock->fd); if (uwsgi.chown_socket) { uwsgi_chown(shared_sock->name, uwsgi.chown_socket); } } else { #ifdef AF_INET6 if (shared_sock->name[0] == '[' && tcp_port[-1] == ']') { shared_sock->fd = bind_to_tcp(shared_sock->name, uwsgi.listen_queue, tcp_port); shared_sock->family = AF_INET6; // fix socket name shared_sock->name = uwsgi_getsockname(shared_sock->fd); uwsgi_log("uwsgi shared socket %d bound to TCP6 address %s fd %d\n", uwsgi_get_shared_socket_num(shared_sock), shared_sock->name, shared_sock->fd); } else { #endif shared_sock->fd = bind_to_tcp(shared_sock->name, uwsgi.listen_queue, tcp_port); shared_sock->family = AF_INET; // fix socket name shared_sock->name = uwsgi_getsockname(shared_sock->fd); uwsgi_log("uwsgi shared socket %d bound to TCP address %s fd %d\n", uwsgi_get_shared_socket_num(shared_sock), shared_sock->name, shared_sock->fd); #ifdef AF_INET6 } #endif } if (shared_sock->fd < 0) { uwsgi_log("unable to create shared socket on: %s\n", shared_sock->name); exit(1); } if (shared_sock->no_defer) { uwsgi.no_defer_accept = current_defer_accept; } } else { for (i = 3; i < (int) uwsgi.max_fd; i++) { char *sock = uwsgi_getsockname(i); if (sock) { if (!uwsgi_socket_strcmp(sock, shared_sock->name)) { if (strchr(sock, ':')) { uwsgi_log("uwsgi shared socket %d inherited TCP address %s fd %d\n", uwsgi_get_shared_socket_num(shared_sock), sock, i); shared_sock->family = AF_INET; } else { uwsgi_log("uwsgi shared socket %d inherited UNIX address %s fd %d\n", uwsgi_get_shared_socket_num(shared_sock), sock, i); shared_sock->family = AF_UNIX; } shared_sock->fd = i; } free(sock); } } } shared_sock->bound = 1; shared_sock = shared_sock->next; } struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (uwsgi_sock->shared) { shared_sock = uwsgi_get_shared_socket_by_num(uwsgi_sock->from_shared); if (!shared_sock) { uwsgi_log("unable to find shared socket %d\n", uwsgi_sock->from_shared); exit(1); } uwsgi_sock->fd = shared_sock->fd; uwsgi_sock->family = shared_sock->family; uwsgi_sock->name = shared_sock->name; uwsgi_log("uwsgi socket %d mapped to shared socket %d (%s) fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_get_shared_socket_num(shared_sock), shared_sock->name, uwsgi_sock->fd); } uwsgi_sock = uwsgi_sock->next; } } void uwsgi_map_sockets() { struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { struct uwsgi_string_list *usl = uwsgi.map_socket; int enabled = 1; while (usl) { char *colon = strchr(usl->value, ':'); if (!colon) { uwsgi_log("invalid socket mapping, must be socket:worker[,worker...]\n"); exit(1); } if ((int) uwsgi_str_num(usl->value, colon - usl->value) == uwsgi_get_socket_num(uwsgi_sock)) { enabled = 0; char *p, *ctx = NULL; uwsgi_foreach_token(colon + 1, ",", p, ctx) { int w = atoi(p); if (w < 1 || w > uwsgi.numproc) { uwsgi_log("invalid worker num: %d\n", w); exit(1); } if (w == uwsgi.mywid) { enabled = 1; uwsgi_log("mapped socket %d (%s) to worker %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi.mywid); break; } } } usl = usl->next; } if (!enabled) { close(uwsgi_sock->fd); uwsgi_remap_fd(uwsgi_sock->fd, "/dev/null"); uwsgi_sock->disabled = 1; } uwsgi_sock = uwsgi_sock->next; } uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (uwsgi_sock->disabled) { uwsgi_sock = uwsgi_del_socket(uwsgi_sock); } else { uwsgi_sock = uwsgi_sock->next; } } } void uwsgi_bind_sockets() { socklen_t socket_type_len; union uwsgi_sockaddr usa; union uwsgi_sockaddr_ptr gsa; struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (!uwsgi_sock->bound && !uwsgi_socket_is_already_bound(uwsgi_sock->name)) { char *tcp_port = strrchr(uwsgi_sock->name, ':'); int current_defer_accept = uwsgi.no_defer_accept; if (uwsgi_sock->no_defer) { uwsgi.no_defer_accept = 1; } if (tcp_port == NULL) { uwsgi_sock->fd = bind_to_unix(uwsgi_sock->name, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket); uwsgi_sock->family = AF_UNIX; if (uwsgi.chown_socket) { uwsgi_chown(uwsgi_sock->name, uwsgi.chown_socket); } uwsgi_log("uwsgi socket %d bound to UNIX address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd); struct stat st; if (uwsgi_sock->name[0] != '@' && !stat(uwsgi_sock->name, &st)) { uwsgi_sock->inode = st.st_ino; } } else { #ifdef AF_INET6 if (uwsgi_sock->name[0] == '[' && tcp_port[-1] == ']') { uwsgi_sock->fd = bind_to_tcp(uwsgi_sock->name, uwsgi.listen_queue, tcp_port); uwsgi_log("uwsgi socket %d bound to TCP6 address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd); uwsgi_sock->family = AF_INET6; } else { #endif uwsgi_sock->fd = bind_to_tcp(uwsgi_sock->name, uwsgi.listen_queue, tcp_port); uwsgi_log("uwsgi socket %d bound to TCP address %s fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd); uwsgi_sock->family = AF_INET; #ifdef AF_INET6 } #endif } if (uwsgi_sock->fd < 0 && !uwsgi_sock->per_core) { uwsgi_log("unable to create server socket on: %s\n", uwsgi_sock->name); exit(1); } uwsgi.no_defer_accept = current_defer_accept; } uwsgi_sock->bound = 1; uwsgi_sock = uwsgi_sock->next; } int zero_used = 0; uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (uwsgi_sock->bound && uwsgi_sock->fd == 0) { zero_used = 1; break; } uwsgi_sock = uwsgi_sock->next; } if (!zero_used) { socket_type_len = sizeof(struct sockaddr_un); gsa.sa = (struct sockaddr *) &usa; if (!uwsgi.skip_zero && !getsockname(0, gsa.sa, &socket_type_len)) { if (gsa.sa->sa_family == AF_UNIX) { uwsgi_sock = uwsgi_new_socket(uwsgi_getsockname(0)); uwsgi_sock->family = AF_UNIX; uwsgi_sock->fd = 0; uwsgi_sock->bound = 1; uwsgi_log("uwsgi socket %d inherited UNIX address %s fd 0\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name); if (!uwsgi.is_a_reload) { if (uwsgi.chown_socket) { uwsgi_chown(uwsgi_sock->name, uwsgi.chown_socket); } if (uwsgi.chmod_socket) { if (uwsgi.chmod_socket_value) { if (chmod(uwsgi_sock->name, uwsgi.chmod_socket_value) != 0) { uwsgi_error("inherit fd0: chmod()"); } } else { uwsgi_log("chmod() fd0 socket to 666 for lazy and brave users\n"); if (chmod(uwsgi_sock->name, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) != 0) { uwsgi_error("inherit fd0: chmod()"); } } } } } else { uwsgi_sock = uwsgi_new_socket(uwsgi_getsockname(0)); uwsgi_sock->family = AF_INET; uwsgi_sock->fd = 0; uwsgi_sock->bound = 1; uwsgi_log("uwsgi socket %d inherited INET address %s fd 0\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name); } } else if (!uwsgi.honour_stdin) { int fd = open("/dev/null", O_RDONLY); if (fd < 0) { uwsgi_error_open("/dev/null"); uwsgi_log("WARNING: unable to remap stdin, /dev/null not available\n"); goto stdin_done; } if (fd != 0) { if (dup2(fd, 0) < 0) { uwsgi_error("dup2()"); exit(1); } close(fd); } } else if (uwsgi.honour_stdin) { if (!tcgetattr(0, &uwsgi.termios)) { uwsgi.restore_tc = 1; } } } stdin_done: if (uwsgi.chown_socket) { if (!uwsgi.master_as_root) { uwsgi_as_root(); } } // check for auto_port socket uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (uwsgi_sock->auto_port) { #ifdef AF_INET6 if (uwsgi_sock->family == AF_INET6) { uwsgi_log("uwsgi socket %d bound to TCP6 address %s (port auto-assigned) fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd); } else { #endif uwsgi_log("uwsgi socket %d bound to TCP address %s (port auto-assigned) fd %d\n", uwsgi_get_socket_num(uwsgi_sock), uwsgi_sock->name, uwsgi_sock->fd); #ifdef AF_INET6 } #endif } uwsgi_sock = uwsgi_sock->next; } } void uwsgi_set_sockets_protocols() { struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { char *requested_protocol = uwsgi_sock->proto_name; if (uwsgi_sock->lazy) goto setup_proto; if (!uwsgi_sock->bound || uwsgi_sock->fd == -1) goto nextsock; if (!uwsgi_sock->per_core) { uwsgi_sock->arg = fcntl(uwsgi_sock->fd, F_GETFL, NULL); if (uwsgi_sock->arg < 0) { uwsgi_error("fcntl()"); exit(1); } uwsgi_sock->arg |= O_NONBLOCK; if (fcntl(uwsgi_sock->fd, F_SETFL, uwsgi_sock->arg) < 0) { uwsgi_error("fcntl()"); exit(1); } } setup_proto: if (!requested_protocol) requested_protocol = uwsgi.protocol; uwsgi_socket_setup_protocol(uwsgi_sock, requested_protocol); nextsock: uwsgi_sock = uwsgi_sock->next; } } void uwsgi_tcp_nodelay(int fd) { #ifdef TCP_NODELAY int flag = 1; if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int))) { uwsgi_error("uwsgi_tcp_nodelay()/setsockopt()"); } #endif } int uwsgi_accept(int server_fd) { struct sockaddr_un client_src; memset(&client_src, 0, sizeof(struct sockaddr_un)); socklen_t client_src_len = 0; #if defined(__linux__) && defined(SOCK_NONBLOCK) && !defined(OBSOLETE_LINUX_KERNEL) return accept4(server_fd, (struct sockaddr *) &client_src, &client_src_len, SOCK_NONBLOCK); #elif defined(__linux__) int client_fd = accept(server_fd, (struct sockaddr *) &client_src, &client_src_len); if (client_fd >= 0) { uwsgi_socket_nb(client_fd); } return client_fd; #else return accept(server_fd, (struct sockaddr *) &client_src, &client_src_len); #endif } struct uwsgi_protocol *uwsgi_register_protocol(char *name, void (*func)(struct uwsgi_socket *)) { struct uwsgi_protocol *old_up = NULL, *up = uwsgi.protocols; while(up) { if (!strcmp(name, up->name)) { goto found; } old_up = up; up = up->next; } up = uwsgi_calloc(sizeof(struct uwsgi_protocol)); up->name = name; if (old_up) { old_up->next = up; } else { uwsgi.protocols = up; } found: up->func = func; return up; } int uwsgi_socket_passcred(int fd) { #ifdef SO_PASSCRED int optval = 1; if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) < 0) { uwsgi_error("uwsgi_socket_passcred()/setsockopt()"); return -1; } return 0; #else return -1; #endif } void uwsgi_protocols_register() { uwsgi_register_protocol("uwsgi", uwsgi_proto_uwsgi_setup); uwsgi_register_protocol("puwsgi", uwsgi_proto_puwsgi_setup); uwsgi_register_protocol("http", uwsgi_proto_http_setup); uwsgi_register_protocol("http11", uwsgi_proto_http11_setup); #ifdef UWSGI_SSL uwsgi_register_protocol("suwsgi", uwsgi_proto_suwsgi_setup); uwsgi_register_protocol("https", uwsgi_proto_https_setup); #endif uwsgi_register_protocol("fastcgi", uwsgi_proto_fastcgi_setup); uwsgi_register_protocol("fastcgi-nph", uwsgi_proto_fastcgi_nph_setup); uwsgi_register_protocol("scgi", uwsgi_proto_scgi_setup); uwsgi_register_protocol("scgi-nph", uwsgi_proto_scgi_nph_setup); uwsgi_register_protocol("raw", uwsgi_proto_raw_setup); }