예제 #1
0
/* ***************************************************
 * Function: handle_fin
 * ***************************************************
 * This function is called when we receive a FIN (or actually
 * when we process a FIN in-order from the receive buffer).  It
 * simply updates the states variables and calls stcp_fin_received.
 * 
 */
static void handle_fin(mysocket_t sd, context_t *ctx)
{
   	size_t bytes_in_transit = ctx->nxt_seq_num - ctx->seq_base;
   	our_dprintf("FIN PACKET RECEIVED. ACK SEN. Window Start:%d Window End:%d\n",
   				 ctx->seq_base, ctx->nxt_seq_num);
    
    /* This is a special case, we sent a FIN first but we received another 
     * FIN before we got an ACK for the first FIN.  If this is the case, I just
     * treat that second FIN as an ACK for the first FIN (though this would not be
     * necessarily true if both sides were to send FINs simulatenously). We were
     * not asked to deal with simulatenous shut-down so I just do it this clean
     * way */
    if (ctx->connection_state == CSTATE_FIN_WAIT1) {
    	assert(((ctx->seq_base + 1) == ctx->nxt_seq_num) || !DEBUG);
    	ctx->seq_base = ctx->nxt_seq_num;
    	remove_until_seq(ctx);
    	ctx->connection_state = CSTATE_TIME_WAIT;
    }	
    else if (ctx->connection_state == CSTATE_FIN_WAIT2) {
		assert(bytes_in_transit==0 || !DEBUG);
		ctx->connection_state = CSTATE_TIME_WAIT;
	}
	else  {
		assert(ctx->connection_state = CSTATE_ESTABLISHED || !DEBUG);
		assert(bytes_in_transit==0 || !DEBUG);
		ctx->connection_state = CSTATE_CLOSE_WAIT;
	}
	stcp_fin_received(sd);
}
예제 #2
0
/* 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);
    int tcplen;
    char payload[MAXLEN];
    STCPHeader *in_header;
    void *packtosend;
    char *indicpt;
    char tempbuff[WINLEN];
    stcp_event_type_t eventflag;

    while (!ctx->done)
    {
        unsigned int event;

        eventflag = ANY_EVENT;

        /* set timeout if there is any unack'd data; if not, just make it NULL */
        struct timespec timestart;
        struct timespec *timeout;


        if (ctx->send_unack < ctx->send_next) {
            timestart = ((packet_t *)list_get_at(ctx->unackd_packets, 0))->start_time;
            timeout = &timestart;

            /* constructs the timeout with absolute time by adding the RTO */
            timeout->tv_sec += ctx->rto.tv_sec;
            timeout->tv_nsec += ctx->rto.tv_nsec;

            /* ensures no nanosecond overflow */
            if (timeout->tv_nsec >= 1000000000) {
                timeout->tv_sec  += timeout->tv_nsec / 1000000000;
                timeout->tv_nsec = timeout->tv_nsec % 1000000000;
            }
            if (timeout->tv_sec <= time(NULL))
                /*earliest unacked packet has timed out, unless it's currently sitting in buffer */
                eventflag = NETWORK_DATA|TIMEOUT;
        }
        else {
            timeout = NULL;
            DEBUG("No timeout set\n");
        }



        /* see stcp_api.h or stcp_api.c for details of this function */
        /* XXX: you will need to change some of these arguments! */
        event = stcp_wait_for_event(sd, eventflag, timeout);

        /* check whether it was the network, app, or a close request */
        if (event & APP_DATA)
        {
            DEBUG("Application Data\n");
            /* the application has requested that data be sent */
            /* we should send as long as send_wind > 0 */
            int open_window = ctx->send_wind - (ctx->send_next - ctx->send_unack);
            if(open_window > 0)
            {
                int send_size;

                /* only read in as much from app as we can send */
                if(open_window > MAXLEN) send_size = MAXLEN;
                else send_size = open_window;

                void* buffer = (char *) calloc(1, send_size);

                tcplen = stcp_app_recv(sd, buffer, send_size);

                if( tcplen > 0 ) {
                    DEBUG("Application data size: %d\n", tcplen);
                    /*create and send packet*/
                    packtosend = (void *)make_stcp_packet(TH_ACK, ctx->send_next, ctx->recv_next, tcplen);
                    memcpy(packtosend + sizeof(STCPHeader), buffer, tcplen);
                    stcp_network_send(sd, packtosend, sizeof(STCPHeader) + tcplen, NULL);
                    DEBUG("Packet of payload size %d, ack number %d, seq number %d sent to network\n", tcplen, ctx->recv_next, ctx->send_next);
                    packet_t_create(ctx, packtosend, sizeof(STCPHeader) + tcplen); /* now a packet has been pushed onto the unacked queue */
                    /* update window length and send_next */
                    ctx->send_next += tcplen;
                }
                free(buffer);
                buffer = NULL;
                free(packtosend);
                packtosend = NULL;
            }
            else DEBUG("Could not get application data\n");
        }

        if (event & NETWORK_DATA)
        {
            DEBUG("Network Data\n");
            in_header = malloc(sizeof(STCPHeader));

            /* network data transmission */
            int data_size = recv_packet(sd, ctx, payload, MAXLEN, in_header);

            DEBUG("Received net data size is %d\n", data_size);


            /* send ACK as long as it's not past our window, and actually contained data */
            if(data_size > 0 || data_size == -2) { /* -2 indicates it received old data, which we should not send to the application */
                packtosend = (void *)make_stcp_packet(TH_ACK, ctx->send_next, ctx->recv_next, 0);
                stcp_network_send(sd, packtosend, sizeof(STCPHeader), NULL);
                free(packtosend);
                packtosend = NULL;
            }



            /* send payload to application, if it's valid */
            if(data_size > 0) {
                DEBUG("Sent data of size %d to application\n", data_size);
                stcp_app_send(sd, ctx->recv_buffer, data_size);


                /* slide the window over */
                indicpt = strchr(ctx->recv_indicator, '\0');
                data_size = indicpt - ctx->recv_indicator;
                memcpy(tempbuff, ctx->recv_buffer + data_size, WINLEN - data_size);
                memset(ctx->recv_buffer, '\0', WINLEN);
                memcpy(ctx->recv_buffer, tempbuff, WINLEN - data_size);

                /* slide window indicator over */
                memcpy(tempbuff, indicpt, WINLEN - data_size);
                memset(ctx->recv_indicator, '\0', WINLEN);
                memcpy(ctx->recv_indicator, tempbuff, WINLEN - data_size);
            }

            /* deal with connection teardown, if need be */
            if (in_header->th_flags & TH_ACK) {
                /* go from FIN-WAIT1 --> FIN-WAIT2 */
                if(ctx->connection_state == CSTATE_FIN_WAIT1) {
                    DEBUG("State: FIN-WAIT2\n");
                    ctx->connection_state = CSTATE_FIN_WAIT2;
                }
                /* go from LAST-ACK --> CLOSED */
                if(ctx->connection_state == CSTATE_LAST_ACK) {
                    DEBUG("State: CLOSED\n");
                    ctx->connection_state = CSTATE_CLOSED;
                    free(in_header);
                    in_header = NULL;
                    break;
                }
                /* go from CLOSING --> CLOSED */
                if(ctx->connection_state == CSTATE_CLOSING) {
                    DEBUG("State: CLOSED\n");
                    ctx->connection_state = CSTATE_CLOSED;
                    free(in_header);
                    in_header = NULL;
                    break;
                }
            }
            /* branching for the receipt of a FIN packet */
            if (in_header->th_flags & TH_FIN) {
                DEBUG("Received FIN packet\n");
                /* Acknowledge FIN, which counts as a byte */
                ctx->recv_next++;
                packtosend = (void *)make_stcp_packet(TH_ACK, ctx->send_next, ctx->recv_next, 0);
                stcp_network_send(sd, packtosend, sizeof(STCPHeader), NULL);

                /* go into CLOSE-WAIT */
                if (ctx->connection_state == CSTATE_ESTABLISHED) {
                    DEBUG("State: CLOSE_WAIT\n");
                    /* inform app of FIN */
                    stcp_fin_received(sd);

                    ctx->connection_state = CSTATE_CLOSE_WAIT;
                }
                /* go from FIN-WAIT2 --> CLOSED */
                if (ctx->connection_state == CSTATE_FIN_WAIT2) {
                    DEBUG("State: CLOSED\n");
                    ctx->connection_state = CSTATE_CLOSED;
                    free(in_header);
                    in_header = NULL;
                    break;
                }
                /* go from FIN-WAIT1 --> CLOSING */
                if (ctx->connection_state == CSTATE_FIN_WAIT1) {
                    DEBUG("State: CLOSING\n");
                    /* inform app of FIN */
                    stcp_fin_received(sd);

                    ctx->connection_state = CSTATE_CLOSING;
                }
                free(in_header);
                in_header = NULL;
            }
        }

        if (event & APP_CLOSE_REQUESTED)
        {
            DEBUG("Application close requested\n");
            if(ctx->connection_state == CSTATE_ESTABLISHED)
            {
                /* need to send all outstanding data first */
                DEBUG("Sending FIN packet with seq %d, ack %d\n", ctx->send_next, ctx->recv_next);
                STCPHeader *header = make_stcp_packet(TH_FIN, ctx->send_next, ctx->recv_next, 0);
                stcp_network_send(sd, header, sizeof(STCPHeader), NULL);
                ctx->send_unack += 1;
                packet_t_create(ctx, header, sizeof(STCPHeader));
                free(header);
                header = NULL;
                /* go into FIN-WAIT1 */
                ctx->connection_state = CSTATE_FIN_WAIT1;
                DEBUG("State: FIN-WAIT1\n");
            }
            if(ctx->connection_state == CSTATE_CLOSE_WAIT)
            {
                DEBUG("Sending FIN packet with seq %d, ack %d\n", ctx->send_next, ctx->recv_next);
                STCPHeader *header = make_stcp_packet(TH_FIN, ctx->send_next, ctx->recv_next, 0);
                stcp_network_send(sd, header, sizeof(STCPHeader), NULL);
                packet_t_create(ctx, header, sizeof(STCPHeader));
                ctx->send_next += 1;
                free(header);
                header = NULL;
                /* go from CLOSE-WAIT --> LAST-ACK */
                ctx->connection_state = CSTATE_LAST_ACK;
                DEBUG("State: LAST-ACK\n");
            }
        }
        if (event == TIMEOUT)
        {
            int giveup = 0;
            /* TIMEOUT--resend all packets in ctx->unackd_packets */
            packet_t *resendpack;
            list_iterator_start(ctx->unackd_packets);
            while (list_iterator_hasnext(ctx->unackd_packets)) {
                resendpack = (packet_t *)list_iterator_next(ctx->unackd_packets);
                if (resendpack->retry_count > 6) {
                    /*close the connection*/
                    DEBUG("Too many retries");
                    errno = ECONNABORTED;
                    giveup = 1;
                }
                /* increment retries */
                resendpack->retry_count++;
                clock_gettime(CLOCK_REALTIME, &(resendpack->start_time));
                ((STCPHeader *)(resendpack->packet))->th_ack = htonl(ctx->recv_next);
                stcp_network_send(sd, resendpack->packet, resendpack->packet_size, NULL);
                DEBUG("Resent packet with sequence number %d\n", ntohl(((STCPHeader *)(resendpack->packet))->th_seq));
            }
            list_iterator_stop(ctx->unackd_packets);
            if (giveup)
                break;
        }
    }
}
예제 #3
0
int handle_cstate_est_recv(mysocket_t sd, context_t * ctx){

    our_dprintf("* IN EST REC\n");
    size_t len =  sizeof(struct tcphdr) + STCP_MSS;
    uint8_t buff[len];
    uint32_t data_len, data_index;
    size_t delta, recv_len, recv_packet_len;
    recv_len = stcp_network_recv(sd, buff, len);
    struct tcphdr * tcp_packet  = (struct tcphdr *) buff;
    size_t hdr_size = tcp_packet->th_off * 4;
    recv_packet_len = recv_len - 4 * tcp_packet->th_off;

    /* check if any data was ack'd */
    if (tcp_packet->th_flags & TH_ACK) {
        if (ntohl(tcp_packet->th_ack) < ctx->sent_last_byte_acked || ntohl(tcp_packet->th_ack) > ctx->sent_last_byte_written+1){
            our_dprintf("bad ack, expected %u, received %u. returning \n", ctx->sent_last_byte_sent+1, tcp_packet->th_ack);
            return -1;
        }
        ctx->sent_last_byte_acked = ntohl(tcp_packet->th_ack);
        //our_dprintf("****got an ack: %u\n", tcp_packet->th_ack);
    }
    /* check to see if the seq number is appropriate */
    if (ntohl(tcp_packet->th_seq) != ctx->recd_next_byte_expected){
        //our_dprintf("unexpected seq. rec seq : %u, expected : %u\n", tcp_packet->th_seq, ctx->recd_next_byte_expected);

        /* if part of the data is below the seq window */
        if ((ntohl(tcp_packet->th_seq) < ctx->recd_next_byte_expected) && 
            (ntohl(tcp_packet->th_seq) + recv_packet_len > ctx->recd_next_byte_expected)){
            //our_dprintf("some data salvageable\n");
            /* some of the data should be salvaged */
            data_len = ntohl(tcp_packet->th_seq) + recv_packet_len - ctx->recd_next_byte_expected;
            data_index = recv_packet_len - data_len;
        } else if (0) {
            /* placeholder for if data overflows upper bound of sliding window */

        } else {
            //our_dprintf("bad packet\n");
            return 0;
        }
    } else {
        data_len = recv_packet_len;
        data_index = 0;
    }
    uint8_t * data = buff + hdr_size; 
    uint32_t wind_index = ((ctx->recd_last_byte_recd + 1) - ctx->initial_recd_seq_num) % MAX_WINDOW_SIZE;  
    //our_dprintf("window index %u, data len %u\n", wind_index, data_len); 
    //our_dprintf("received data: %s\n", data);
    if (wind_index + data_len > MAX_WINDOW_SIZE){
        /* we're wrapping the buffer */
        delta = MAX_WINDOW_SIZE - wind_index;
        //our_dprintf("wrapping recv buff \n");
        /*copy data to ctx->buffer and send it to app */ 
        memcpy(ctx->recv_wind + wind_index, data + data_index, delta); 
        stcp_app_send( sd, ctx->recv_wind + wind_index, delta);

        memcpy(ctx->recv_wind, data + delta + data_index, data_len - delta);
        stcp_app_send( sd, ctx->recv_wind, data_len - delta);
        
    } else {
        /* we're not wrapping the buffer */
        //our_dprintf("don't need to wrap, data len %d\n", data_len);
        /*copy data to ctx->buffer and send it to app */
        memcpy(ctx->recv_wind + wind_index, data + data_index, data_len);
        stcp_app_send( sd, ctx->recv_wind + wind_index, data_len);
    }

    ctx->recd_last_byte_recd += data_len;
    ctx->recd_next_byte_expected += data_len;
    ctx->recd_last_byte_read += data_len;

    if (data_len > 0 ) {
        //our_dprintf("acking %u bytes\n", data_len);
        send_syn_ack_fin(sd, ctx, SEND_ACK, 0, ctx->recd_next_byte_expected);
    } else {
        //our_dprintf("** flags %u\n", tcp_packet->th_flags);
    }
    

    if (tcp_packet->th_flags & TH_FIN) {
        stcp_fin_received(sd);
        if (data_len == 0){
            ctx->recd_last_byte_recd++;
            ctx->recd_next_byte_expected++;
            ctx->recd_last_byte_read++;
        }
        send_syn_ack_fin(sd, ctx, SEND_ACK, 0, ctx->recd_next_byte_expected);
        ctx->connection_state = CSTATE_CLOSE_WAIT;
        close_tcp_conn(sd, ctx);
    }
    return 0;
}