Exemplo n.º 1
0
static int udp_v4_get_port(struct sock *sk, unsigned short snum)
{
	struct hlist_node *node;
	struct sock *sk2;
	struct inet_sock *inet = inet_sk(sk);

	write_lock_bh(&udp_hash_lock);
	if (!snum) {
		int i, low, high, remaining;
		unsigned rover, best, best_size_so_far;

		inet_get_local_port_range(&low, &high);
		remaining = (high - low) + 1;

		best_size_so_far = UINT_MAX;
		best = rover = net_random() % remaining + low;

		if (!udp_lport_inuse(rover) &&
		    !inet_is_reserved_local_port(rover))
			goto gotit;

		/* 1st pass: look for empty (or shortest) hash chain */
		for (i = 0; i < UDP_HTABLE_SIZE; i++) {
			struct hlist_head *list;
			int size = 0;

			list = &udp_hash[rover & (UDP_HTABLE_SIZE - 1)];
			if (hlist_empty(list) &&
			    !inet_is_reserved_local_port(rover))
				goto gotit;

			sk_for_each(sk2, node, list)
				if (++size >= best_size_so_far)
					goto next;
			best_size_so_far = size;
			best = rover;
		next:
			/* fold back if end of range */
			if (++rover > high)
				rover = low + ((rover - low)
				            & (UDP_HTABLE_SIZE - 1));
		}
		/* 2nd pass: find hole in shortest hash chain */
		rover = best;
		for (i = 0; i < (1 << 16) / UDP_HTABLE_SIZE; i++) {
			if (!udp_lport_inuse(rover) &&
			    !inet_is_reserved_local_port(rover))
				goto gotit;
			rover += UDP_HTABLE_SIZE;
			if (rover > high)
				rover = low + ((rover - low)
				            & (UDP_HTABLE_SIZE - 1));
		}
		/* All ports in use! */
		goto fail;

gotit:
		snum = rover;
	} else {
Exemplo n.º 2
0
/* Obtain a reference to a local port for the given sock,
 * if snum is zero it means select any available local port.
 */
int inet_csk_get_port(struct sock *sk, unsigned short snum)
{	
	struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo;
	struct inet_bind_hashbucket *head;
	struct inet_bind_bucket *tb;
	int ret, attempts = 5;
	
	struct net *net = sock_net(sk);
	int smallest_size = -1, smallest_rover;
	//kuid_t uid = sock_i_uid(sk);

	//local_bh_disable();
	if (!snum) {
		int remaining, rover, low, high;

again:
		inet_get_local_port_range(net,&low, &high);
		remaining = (high - low) + 1;
		smallest_rover = rover = net_random() % remaining + low;

		smallest_size = -1;
		do {
			if (inet_is_reserved_local_port(net,rover))
				goto next_nolock;
			head = &hashinfo->bhash[inet_bhashfn(net, rover, hashinfo->bhash_size)];
			//spin_lock(&head->lock);
			inet_bind_bucket_for_each(tb, &head->chain)
				if (net_eq(ib_net(tb), net) && tb->port == rover) {
					if (((tb->fastreuse > 0 && sk->sk_reuse && sk->sk_state != TCP_LISTEN) 
						|| (tb->fastreuseport > 0 && sk->sk_reuseport ))  //  && uid_eq(tb->fastuid, uid)
						&& (tb->num_owners < smallest_size || smallest_size == -1)) {
						smallest_size = tb->num_owners;
						smallest_rover = rover;
						if ((atomic_read(&hashinfo->bsockets) > (high - low) + 1) 
							&& (!inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb, false))) {
							snum = smallest_rover;
							goto tb_found;
						}
					}
					if (!inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb, false)) {
						snum = rover;
						goto tb_found;
					}
					goto next;
				}
				
			break;
		next:
			//spin_unlock(&head->lock);
		next_nolock:
			if (++rover > high)
				rover = low;
		} while (--remaining > 0);

		/* Exhausted local port range during search?  It is not
		 * possible for us to be holding one of the bind hash
		 * locks if this test triggers, because if 'remaining'
		 * drops to zero, we broke out of the do/while loop at
		 * the top level, not from the 'break;' statement.
		 */
		ret = 1;
		if (remaining <= 0) {
			if (smallest_size != -1) {
				snum = smallest_rover;
				goto have_snum;
			}
			goto fail;
		}
		/* OK, here is the one we will use.  HEAD is
		 * non-NULL and we hold it's mutex.
		 */
		snum = rover;
	} else {