i++; } assert(&e->node == list); assert(i == n); i = 0; LIST_FOR_EACH_REVERSE (e, node, list) { assert(i < n); assert(e->value == values[n - i - 1]); i++; } assert(&e->node == list); assert(i == n); assert(list_is_empty(list) == !n); assert(list_is_singleton(list) == (n == 1)); assert(list_is_short(list) == (n < 2)); assert(list_size(list) == n); } #if 0 /* Prints the values in 'list', plus 'name' as a title. */ static void print_list(const char *name, struct list *list) { struct element *e; printf("%s:", name); LIST_FOR_EACH (e, node, list) { printf(" %d", e->value); }
/* Based on network/socket.c:get_pasv_socket() but modified to try and bind to a * port range instead of any port. */ struct connection_state init_bittorrent_listening_socket(struct connection *conn) { struct bittorrent_connection *bittorrent = conn->info; struct sockaddr_in addr, addr2; uint16_t port, max_port; int len; /* XXX: Always add the connection to the list even if we fail so we can * safely assume it is in done_bittorrent_listening_socket(). */ add_to_list(bittorrent_connections, bittorrent); /* Has the socket already been initialized? */ if (!list_is_singleton(bittorrent_connections)) return connection_state(S_OK); /* We could have bailed out from an earlier attempt. */ if (bittorrent_socket != -1) close(bittorrent_socket); bittorrent_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (bittorrent_socket < 0) return connection_state_for_errno(errno); /* Set it non-blocking */ if (set_nonblocking_fd(bittorrent_socket) < 0) return connection_state_for_errno(errno); /* Bind it to some port */ port = get_opt_int("protocol.bittorrent.ports.min", NULL); max_port = get_opt_int("protocol.bittorrent.ports.max", NULL); memset(&addr, 0, sizeof(addr)); addr.sin_port = htons(port); /* Repeatedly try the configured port range. */ while (bind(bittorrent_socket, (struct sockaddr *) &addr, sizeof(addr))) { if (errno != EADDRINUSE) return connection_state_for_errno(errno); /* If all ports was in use fail with EADDRINUSE. */ if (++port > max_port) return connection_state_for_errno(errno); memset(&addr, 0, sizeof(addr)); addr.sin_port = htons(port); } /* Get the endpoint info about the new socket and save it */ memset(&addr2, 0, sizeof(addr2)); len = sizeof(addr2); if (getsockname(bittorrent_socket, (struct sockaddr *) &addr2, &len)) return connection_state_for_errno(errno); bittorrent->port = ntohs(addr2.sin_port); /* Go listen */ if (listen(bittorrent_socket, LISTEN_BACKLOG)) return connection_state_for_errno(errno); set_ip_tos_throughput(bittorrent_socket); set_handlers(bittorrent_socket, accept_bittorrent_peer_connection, NULL, NULL, NULL); return connection_state(S_OK); }