Esempio n. 1
0
/* ***************************************************
 * Function: control_loop
 * ***************************************************
 * control_loop() is the main STCP loop; it repeatedly waits for one of the
 * following to happen:
 *   - incoming data from the peer
 *   - new data from the application (via mywrite())
 *   - the socket to be closed (via myclose())
 *   - a timeout
 */
static void control_loop(mysocket_t sd, context_t *ctx)
{
    assert(ctx);
	unsigned int event = 0;
	bool fin_retry = false; /* TRUE = APP_CLOSE_REQUESTED but window was full */
    while (!ctx->done)
    {
    	size_t bytes_in_transit = ctx->nxt_seq_num - ctx->seq_base;
  		size_t win_space = ctx->recv_win - bytes_in_transit;
    	event = control_wait(sd, ctx, fin_retry);
		if (event & NETWORK_DATA) {
		   handle_network_data(sd, ctx);
		}
		if ((event & APP_DATA) && !fin_retry) {
			handle_app_data(sd, ctx); 
		}
		if (event == TIMEOUT){
			handle_timeout(sd, ctx);

		}
		if ((event & APP_CLOSE_REQUESTED) || fin_retry) {
   			if (win_space>0){
				send_fin(sd, ctx);
				fin_retry = false;
   			}
   			else {
   				our_dprintf("App requested FIN but window is full\n");
   				fin_retry = true;	
   			}
		 }
    }
}
Esempio n. 2
0
//正常关闭RUDP SOCKET
void RUDPSocket::close()
{
    switch(state_)
    {
    case RUDP_CONNECTING:
    case RUDP_CONNECTED:
        if(event_handler_ != NULL)
        {
            event_handler_->rudp_close_event(rudp_id_);
        }

        //发送SYN
        RUDP_INFO("close rudp socket, state = RUDP_FIN_STATE, rudp id = " << rudp_id_);
        set_state(RUDP_FIN_STATE);
        
        RUDP_DEBUG("send fin, rudp socket id = " << rudp_id_);
        send_fin();
        set_timer(ccc_.get_rtt() + TIMER_MIN_DELAY);

        send_count_ ++;
        break;

    case RUDP_FIN2_STATE:
        set_state(RUDP_CLOSE);
        break;
    }
}
Esempio n. 3
0
int32_t RUDPSocket::handle_timeout(const void *act, uint32_t timer_id)
{
    if(timer_id_ != timer_id)
        return 0;

    timer_id_= 0;

    //解决状态定时的问题,尤其是报文发送
    switch(state_)
    {
    case RUDP_CONNECTING:
        if(send_count_ < SYN_MAX_COUNT)
        {
            send_syn();
            set_timer(CONNECT_DELAY);
            RUDP_DEBUG("resend syn, rudp socket id = " << rudp_id_);
            send_count_ ++;
        }
        else //连接超时
        {
            RUDP_INFO("connecting timeout! state = RUDP_FIN2_STATE, rudp id = " << rudp_id_);
            set_state(RUDP_FIN2_STATE);

            if(event_handler_ != NULL)
                event_handler_->rudp_exception_event(rudp_id_);
            else
            {
                RUDP_INFO("state = RUDP_CLOSE, rudp id = " << rudp_id_);
                set_state(RUDP_CLOSE);
            }
        }
        break;

    case RUDP_FIN_STATE:
        if(send_count_ < FIN_MAX_COUNT)
        {
            RUDP_DEBUG("resend fin, rudp socket id = " << rudp_id_);
            send_fin();
            set_timer(ccc_.get_rtt() + TIMER_MIN_DELAY);
            send_count_ ++;
        }
        else
        {
            RUDP_INFO("fin timeout, state = RUDP_CLOSE, rudp id = " << rudp_id_);
            set_state(RUDP_CLOSE);
        }
        break;
    }

    return 0;
}
Esempio n. 4
0
//强制关闭RUDP SOCKET
void RUDPSocket::force_close()
{
    switch(state_)
    {
    case RUDP_CONNECTING:
    case RUDP_CONNECTED:
        RUDP_DEBUG("send fin, rudp socket id = " << rudp_id_);
        for(uint8_t i = 0; i < 6; i ++) //直接发送3个fin
            send_fin();

    case RUDP_FIN2_STATE:
        RUDP_INFO("state = RUDP_CLOSE");
        set_state(RUDP_CLOSE);
        break;
    }
}
Esempio n. 5
0
File: soccr.c Progetto: Snorch/criu
int libsoccr_restore(struct libsoccr_sk *sk,
		struct libsoccr_sk_data *data, unsigned data_size)
{
	int mstate = 1 << data->state;

	if (libsoccr_set_sk_data_noq(sk, data, data_size))
		return -1;

	if (libsoccr_restore_queue(sk, data, sizeof(*data), TCP_RECV_QUEUE, sk->recv_queue))
		return -1;

	if (libsoccr_restore_queue(sk, data, sizeof(*data), TCP_SEND_QUEUE, sk->send_queue))
		return -1;

	if (data->flags & SOCCR_FLAGS_WINDOW) {
		struct tcp_repair_window wopt = {
			.snd_wl1 = data->snd_wl1,
			.snd_wnd = data->snd_wnd,
			.max_window = data->max_window,
			.rcv_wnd = data->rcv_wnd,
			.rcv_wup = data->rcv_wup,
		};

		if (mstate & (RCVQ_FIRST_FIN | RCVQ_SECOND_FIN)) {
			wopt.rcv_wup--;
			wopt.rcv_wnd++;
		}

		if (setsockopt(sk->fd, SOL_TCP, TCP_REPAIR_WINDOW, &wopt, sizeof(wopt))) {
			logerr("Unable to set window parameters");
			return -1;
		}
	}

	/*
	 * To restore a half closed sockets, fin packets has to be restored in
	 * recv and send queues. Here shutdown() is used to restore a fin
	 * packet in the send queue and a fake fin packet is send to restore it
	 * in the recv queue.
	 */
	if (mstate & SNDQ_FIRST_FIN)
		restore_fin_in_snd_queue(sk->fd, mstate & SNDQ_FIN_ACKED);

	/* Send a fin packet to the socket to restore it in a receive queue. */
	if (mstate & (RCVQ_FIRST_FIN | RCVQ_SECOND_FIN))
		if (send_fin(sk, data, data_size, TH_ACK | TH_FIN) < 0)
			return -1;

	if (mstate & SNDQ_SECOND_FIN)
		restore_fin_in_snd_queue(sk->fd, mstate & SNDQ_FIN_ACKED);

	if (mstate & RCVQ_FIN_ACKED)
		data->inq_seq++;

	if (mstate & SNDQ_FIN_ACKED) {
		data->outq_seq++;
		if (send_fin(sk, data, data_size, TH_ACK) < 0)
			return -1;
	}

	return 0;
}

static int __send_queue(struct libsoccr_sk *sk, int queue, char *buf, __u32 len)
{
	int ret, err = -1, max_chunk;
	int off;

	max_chunk = len;
	off = 0;

	do {
		int chunk = len;

		if (chunk > max_chunk)
			chunk = max_chunk;

		ret = send(sk->fd, buf + off, chunk, 0);
		if (ret <= 0) {
			if (max_chunk > 1024) {
				/*
				 * Kernel not only refuses the whole chunk,
				 * but refuses to split it into pieces too.
				 *
				 * When restoring recv queue in repair mode
				 * kernel doesn't try hard and just allocates
				 * a linear skb with the size we pass to the
				 * system call. Thus, if the size is too big
				 * for slab allocator, the send just fails
				 * with ENOMEM.
				 *
				 * In any case -- try smaller chunk, hopefully
				 * there's still enough memory in the system.
				 */
				max_chunk >>= 1;
				continue;
			}

			logerr("Can't restore %d queue data (%d), want (%d:%d:%d)",
				  queue, ret, chunk, len, max_chunk);
			goto err;
		}
		off += ret;
		len -= ret;
	} while (len);
Esempio n. 6
0
int send_data(int socket_desc, int sock_id, int pnum, struct sockaddr_in* to)
{
    //Find out how many packets we have to send
    int packets_to_send = state[sock_id].last_packet[pnum]-state[sock_id].curr[pnum]->num;
    if (packets_to_send>state[sock_id].window_size[pnum])
        packets_to_send = state[sock_id].window_size[pnum];

    int i;
    for (i=0; i<packets_to_send; i++)
    {
        //Move to next packet in queue
        state[sock_id].curr[pnum] = state[sock_id].curr[pnum]->next;
        //Create a full RUDP packet
        smalloc(struct entire_rudp_packet, erp);

        erp->rh.seqno = htonl(state[sock_id].curr[pnum]->seqno);
        erp->rh.type = htons(RUDP_DATA);
        erp->rh.version = htons(RUDP_VERSION);

        erp->rpb.len = state[sock_id].curr[pnum]->rp.len;        
        erp->rpb.data = (char*)malloc(erp->rpb.len);
        memcpy(erp->rpb.data,state[sock_id].curr[pnum]->rp.data,erp->rpb.len);

        //Actually send packet
        int nbytes = sizeof(struct rudp_hdr)+erp->rpb.len+16;
        size_t size = sizeof(struct sockaddr_in);

        if (sendto(socket_desc,(void*)erp,nbytes,0,(struct sockaddr*)to,size)==-1)
            return -1;

        fprintf(stderr,"Sent a DATA packet with seqno %d\r\n",ntohl(erp->rh.seqno));

        //Decrease window size by 1
        state[sock_id].window_size[pnum] -= 1;

        //Get the time at which the timeout handler for the packet should be called
        smalloc(struct timeval,current_time);
        if (gettimeofday(current_time,NULL)<0)
        {
            perror("rudp_event_handler: gettimeofday");
            return -1;
        }
        current_time->tv_usec += RUDP_TIMEOUT*2000;

        //Create an argument for the event_timeout function
        state[sock_id].curr[pnum]->tap = (struct timeout_arg*)malloc(sizeof(struct timeout_arg));   
        state[sock_id].curr[pnum]->tap->seqno = ntohl(erp->rh.seqno);
        state[sock_id].curr[pnum]->tap->sock_id = sock_id;
        state[sock_id].curr[pnum]->tap->socket_desc = socket_desc;
        state[sock_id].curr[pnum]->timed_out = 0;

        state[sock_id].curr[pnum]->tap->to = (struct sockaddr_in*)malloc(sizeof(struct sockaddr_in));
        memcpy(state[sock_id].curr[pnum]->tap->to,to,sizeof(struct sockaddr_in*));
        state[sock_id].curr[pnum]->tap->to->sin_addr = to->sin_addr;

        //Actually register the timeout handlet
        event_timeout(*current_time,udp_timeoutf,(void*)(state[sock_id].curr[pnum]->tap),"packet timeout");
    }

    //Send a FIN if no data was left
    if (packets_to_send<1) send_fin(socket_desc,sock_id,pnum,to);
    return 0;
}