int init_listener(struct Listener *listener, const struct Table_head *tables) { int sockfd; int on = 1; listener->table = table_lookup(tables, listener->table_name); if (listener->table == NULL) { fprintf(stderr, "Table \"%s\" not defined\n", listener->table_name); return -1; } init_table(listener->table); /* If no port was specified on the fallback address, inherit the address * from the listening address */ if (listener->fallback_address && address_port(listener->fallback_address) == 0) address_set_port(listener->fallback_address, address_port(listener->address)); sockfd = socket(address_sa(listener->address)->sa_family, SOCK_STREAM, 0); if (sockfd < 0) { err("socket failed: %s", strerror(errno)); return -2; } /* set SO_REUSEADDR on server socket to facilitate restart */ setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); if (bind(sockfd, address_sa(listener->address), address_sa_len(listener->address)) < 0) { err("bind failed: %s", strerror(errno)); close(sockfd); return -3; } if (listen(sockfd, SOMAXCONN) < 0) { err("listen failed: %s", strerror(errno)); close(sockfd); return -4; } struct ev_io *listener_watcher = &listener->watcher; ev_io_init(listener_watcher, accept_cb, sockfd, EV_READ); listener->watcher.data = listener; ev_io_start(EV_DEFAULT, listener_watcher); return sockfd; }
int valid_listener(const struct Listener *listener) { if (listener->address == NULL) { fprintf(stderr, "No address specified\n"); return 0; } if (!address_is_sockaddr(listener->address)) { fprintf(stderr, "Address not specified as IP/socket\n"); return 0; } switch (address_sa(listener->address)->sa_family) { case AF_UNIX: break; case AF_INET: /* fall through */ case AF_INET6: if (address_port(listener->address) == 0) { fprintf(stderr, "No port specified\n"); return 0; } break; default: fprintf(stderr, "Invalid address family\n"); return 0; } if (listener->protocol != tls_protocol && listener->protocol != http_protocol) { fprintf(stderr, "Invalid protocol\n"); return 0; } return 1; }
int main() { /* using volatile variables so we can example core dumps */ for (volatile unsigned int i = 0; i < sizeof(good) / sizeof(struct Test); i++) { int port; char buffer[255]; struct Address *addr = new_address(good[i].input); assert(addr != NULL); assert(address_compare(addr, addr) == 0); assert(address_compare(NULL, addr) < 0); assert(address_compare(addr, NULL) > 0); assert(address_len(addr) > 0); if (good[i].expected_type & TYPE_HOSTNAME) { assert(address_is_hostname(addr)); assert(!address_is_sockaddr(addr)); assert(!address_is_wildcard(addr)); assert(address_hostname(addr) != NULL); assert(address_sa(addr) == NULL); assert(address_sa_len(addr) == 0); } else if (good[i].expected_type & TYPE_SOCKADDR) { assert(!address_is_hostname(addr)); assert(address_is_sockaddr(addr)); assert(!address_is_wildcard(addr)); assert(address_hostname(addr) == NULL); assert(address_sa(addr) != NULL); assert(address_sa_len(addr) > 0); } else if (good[i].expected_type & TYPE_WILDCARD) { assert(!address_is_hostname(addr)); assert(!address_is_sockaddr(addr)); assert(address_is_wildcard(addr)); assert(address_hostname(addr) == NULL); assert(address_sa(addr) == NULL); assert(address_sa_len(addr) == 0); } display_address(addr, buffer, sizeof(buffer)); if (strcmp(buffer, good[i].output)) { fprintf(stderr, "display_address(%p) returned \"%s\", expected \"%s\"\n", addr, buffer, good[i].output); return 1; } assert(display_address(addr, NULL, 0) == NULL); port = address_port(addr); if (good[i].port != port) { fprintf(stderr, "address_port(%p) return %d, expected %d\n", addr, port, good[i].port); return 1; } address_set_port(addr, port); if (good[i].port != port) { fprintf(stderr, "address_port(%p) return %d, expected %d\n", addr, port, good[i].port); return 1; } free(addr); } for (volatile unsigned int i = 0; i < sizeof(bad) / sizeof(const char *); i++) { struct Address *addr = new_address(bad[i]); if (addr != NULL) { fprintf(stderr, "Accepted bad hostname \"%s\"\n", bad[i]); return 1; } } assert(compare_address_strings("unix:/dev/log", "127.0.0.1") < 0); assert(compare_address_strings("unix:/dev/log", "unix:/dev/logsocket") < 0); assert(compare_address_strings("0.0.0.0", "127.0.0.1") < 0); assert(compare_address_strings("127.0.0.1", "0.0.0.0") > 0); assert(compare_address_strings("127.0.0.1", "127.0.0.1") == 0); assert(compare_address_strings("127.0.0.1:80", "127.0.0.1:81") < 0); assert(compare_address_strings("*:80", "*:81") < 0); assert(compare_address_strings("*:81", "*:80") > 0); assert(compare_address_strings("example.com", "example.net") < 0); assert(compare_address_strings("example.net", "example.com") > 0); assert(compare_address_strings("example.com", "example.com.net") < 0); assert(compare_address_strings("example.com.net", "example.com") > 0); assert(compare_address_strings("example.com", "example.com:80") < 0); assert(compare_address_strings("example.com:80", "example.com") > 0); assert(compare_address_strings(NULL, "example.com") < 0); assert(compare_address_strings("example.com", NULL) > 0); assert(compare_address_strings("example.com", "::") < 0); assert(compare_address_strings("::", "example.com") > 0); assert(compare_address_strings("0.0.0.0", "*") < 0); assert(compare_address_strings("*", "0.0.0.0") > 0); do { struct Address *addr = new_address("*"); assert(addr != NULL); assert(address_len(addr) > 0); free(addr); } while (0); return 0; }
static int init_listener(struct Listener *listener, const struct Table_head *tables, struct ev_loop *loop) { struct Table *table = table_lookup(tables, listener->table_name); if (table == NULL) { err("Table \"%s\" not defined", listener->table_name); return -1; } init_table(table); listener->table = table_ref_get(table); /* If no port was specified on the fallback address, inherit the address * from the listening address */ if (listener->fallback_address && address_port(listener->fallback_address) == 0) address_set_port(listener->fallback_address, address_port(listener->address)); int sockfd = socket(address_sa(listener->address)->sa_family, SOCK_STREAM, 0); if (sockfd < 0) { err("socket failed: %s", strerror(errno)); return -2; } /* set SO_REUSEADDR on server socket to facilitate restart */ int on = 1; setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); int result = bind(sockfd, address_sa(listener->address), address_sa_len(listener->address)); if (result < 0 && errno == EACCES) { /* Retry using binder module */ close(sockfd); sockfd = bind_socket(address_sa(listener->address), address_sa_len(listener->address)); if (sockfd < 0) { char address[128]; err("binder failed to bind to %s", display_address(listener->address, address, sizeof(address))); close(sockfd); return -3; } } else if (result < 0) { char address[128]; err("bind %s failed: %s", display_address(listener->address, address, sizeof(address)), strerror(errno)); close(sockfd); return -3; } if (listen(sockfd, SOMAXCONN) < 0) { err("listen failed: %s", strerror(errno)); close(sockfd); return -4; } int flags = fcntl(sockfd, F_GETFL, 0); fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); listener_ref_get(listener); ev_io_init(&listener->watcher, accept_cb, sockfd, EV_READ); listener->watcher.data = listener; listener->backoff_timer.data = listener; ev_io_start(loop, &listener->watcher); return sockfd; }