Esempio n. 1
0
/*
 * Closes the connection held by the PCB.
 * Return 1 on success, 0 on error.
 */
int
tcp_close (tcp_socket_t *s)
{
	mutex_lock (&s->lock);

	tcp_debug ("tcp_close: sock $%x state=%S\n", s, tcp_state_name (s->state));

	switch (s->state) {
	default: /* Has already been closed. */
		tcp_queue_free (s);
		mutex_unlock (&s->lock);
		return 1;
	case LISTEN:
	case SYN_SENT:
		tcp_queue_free (s);
		mutex_unlock (&s->lock);
		mutex_lock (&s->ip->lock);
		tcp_socket_remove (s->state == LISTEN ?
			&s->ip->tcp_listen_sockets : &s->ip->tcp_sockets, s);
		mutex_unlock (&s->ip->lock);
		return 1;
	case SYN_RCVD:
	case ESTABLISHED:
	case CLOSE_WAIT:
		break;
	}
	for (;;) {
		if (tcp_enqueue_option4 (s, TCP_FIN, 0))
			break;
		mutex_wait (&s->lock);
	}
	s->state = (s->state == CLOSE_WAIT) ? LAST_ACK : FIN_WAIT_1;

    if (s->unsent || (s->flags & TF_ACK_NOW)) {
#if TCP_LOCK_STYLE <= TCP_LOCK_SURE
    mutex_unlock (&s->lock);
#endif
	tcp_output (s);
#if TCP_LOCK_STYLE <= TCP_LOCK_SURE
    mutex_lock (&s->lock);
#endif
    }//if (s->unsent || (s->flags & TF_ACK_NOW))

	while (s->state != CLOSED) {
		if (s->state == TIME_WAIT && ! s->unsent) {
			tcp_queue_free (s);
			mutex_unlock (&s->lock);
			mutex_lock (&s->ip->lock);
			tcp_socket_remove (&s->ip->tcp_closing_sockets, s);
			mutex_unlock (&s->ip->lock);
			return 1;
		}
		mutex_wait (&s->lock);
	}
	mutex_unlock (&s->lock);
	return 1;
}
Esempio n. 2
0
static inline void
set_tcp_state(struct ip_vs_proto_data *pd, struct ip_vs_conn *cp,
	      int direction, struct tcphdr *th)
{
	int state_idx;
	int new_state = IP_VS_TCP_S_CLOSE;
	int state_off = tcp_state_off[direction];

	/*
	 *    Update state offset to INPUT_ONLY if necessary
	 *    or delete NO_OUTPUT flag if output packet detected
	 */
	if (cp->flags & IP_VS_CONN_F_NOOUTPUT) {
		if (state_off == TCP_DIR_OUTPUT)
			cp->flags &= ~IP_VS_CONN_F_NOOUTPUT;
		else
			state_off = TCP_DIR_INPUT_ONLY;
	}

	if ((state_idx = tcp_state_idx(th)) < 0) {
		IP_VS_DBG(8, "tcp_state_idx=%d!!!\n", state_idx);
		goto tcp_state_out;
	}

	new_state =
		pd->tcp_state_table[state_off+state_idx].next_state[cp->state];

  tcp_state_out:
	if (new_state != cp->state) {
		struct ip_vs_dest *dest = cp->dest;

		IP_VS_DBG_BUF(8, "%s %s [%c%c%c%c] %s:%d->"
			      "%s:%d state: %s->%s conn->refcnt:%d\n",
			      pd->pp->name,
			      ((state_off == TCP_DIR_OUTPUT) ?
			       "output " : "input "),
			      th->syn ? 'S' : '.',
			      th->fin ? 'F' : '.',
			      th->ack ? 'A' : '.',
			      th->rst ? 'R' : '.',
			      IP_VS_DBG_ADDR(cp->daf, &cp->daddr),
			      ntohs(cp->dport),
			      IP_VS_DBG_ADDR(cp->af, &cp->caddr),
			      ntohs(cp->cport),
			      tcp_state_name(cp->state),
			      tcp_state_name(new_state),
			      atomic_read(&cp->refcnt));

		if (dest) {
			if (!(cp->flags & IP_VS_CONN_F_INACTIVE) &&
			    !tcp_state_active(new_state)) {
				atomic_dec(&dest->activeconns);
				atomic_inc(&dest->inactconns);
				cp->flags |= IP_VS_CONN_F_INACTIVE;
			} else if ((cp->flags & IP_VS_CONN_F_INACTIVE) &&
				   tcp_state_active(new_state)) {
				atomic_inc(&dest->activeconns);
				atomic_dec(&dest->inactconns);
				cp->flags &= ~IP_VS_CONN_F_INACTIVE;
			}
		}
	}

	if (likely(pd))
		cp->timeout = pd->timeout_table[cp->state = new_state];
	else	/* What to do ? */
		cp->timeout = tcp_timeouts[cp->state = new_state];
}