Пример #1
0
/* ***************************************************
 * Function: handle_app_data
 * ***************************************************
 * The application has new data to be sent out.  First make sure that
 * there is some space in the window.  Get maximum amount of data from 
 * the application, added it to the sender's buffer, and send it across
 * the network.
 */
static void handle_app_data(mysocket_t sd, context_t *ctx)
{
   size_t bytes_in_transit = ctx->nxt_seq_num - ctx->seq_base;
   size_t win_space = ctx->recv_win - bytes_in_transit;
   if (win_space>0){
       char *pkt = (char *)calloc(1,(TH_MIN_OFFSET*sizeof(uint32_t)) + STCP_MSS);
       struct tcphdr* hdr = (struct tcphdr*)pkt;
       hdr->th_off = TH_MIN_OFFSET;
       hdr->th_seq = ctx->nxt_seq_num;
       hdr->th_flags = 0;
       hdr->th_win = RWIN;
       /* Pick the minimum between space in the window and MSS */
       size_t data_max = MIN(STCP_MSS, win_space);	           
       size_t len = stcp_app_recv(sd, pkt + TCP_DATA_START(hdr), data_max); 	           
       ctx->nxt_seq_num += len; /*add len to obtain nxt_seq_num to be used */
       add_to_send_buffer(ctx,  pkt, (TH_MIN_OFFSET*sizeof(uint32_t)) + len);
 	   our_dprintf("Sending packet with seq: %d of size: %d\n", 
 	   				hdr->th_seq,(TH_MIN_OFFSET*sizeof(uint32_t)) + len);
  	   network_send(sd, pkt, (TH_MIN_OFFSET*sizeof(uint32_t)) + len);
       free(pkt);
   }
   else {
   		our_dprintf(".");           	
   }	
}
Пример #2
0
int handle_cstate_est_send(mysocket_t sd, context_t * ctx){
    //our_dprintf("*IN EST SEND\n");
    size_t eff_wind = calc_eff_window(ctx);
    size_t max_to_send = MIN(eff_wind, STCP_MSS);
    if (max_to_send == 0) {
        //our_dprintf("window too small to send min(%u, %u) \n", eff_wind, STCP_MSS);
        return 0;
    }
    //our_dprintf("max to send %u\n", max_to_send);
    /* receive data from app */
    size_t recd_app;
    uint8_t buff[max_to_send];
    recd_app = stcp_app_recv(sd, buff, max_to_send);

    /* construct header */
    uint32_t header_size = sizeof(struct tcphdr);
    uint8_t header_buf[header_size];
    memset(header_buf, 0, header_size);

    struct tcphdr * tcp_header = ( struct tcphdr *) header_buf;

    tcp_header->th_seq = htonl(ctx->sent_last_byte_sent + 1);
    tcp_header->th_flags |= TH_SYN;
    

    tcp_header->th_off = 5; /* no options, data begins 20 bytes into packet */

    /* set adv window size */
    tcp_header->th_win = htons(calc_adv_wind(ctx));
    ctx->sent_adv_window = calc_adv_wind(ctx);
    /* copy the data into the tcp buffer */

    uint32_t wind_index = ((ctx->sent_last_byte_written + 1) 
                - ctx->initial_sequence_num) % MAX_WINDOW_SIZE;
    our_dprintf("window index %u\n", wind_index);
    /* we're wrapping the buffer */
    if (wind_index + recd_app > MAX_WINDOW_SIZE) {
        size_t delta = MAX_WINDOW_SIZE - wind_index;
        our_dprintf("wrapping the buffer\n");
        /* fill the end of the buffer */
        memcpy(ctx->send_wind + wind_index, buff, delta);
        /* restart at the beginning of the buffer */
        memcpy(ctx->send_wind, buff+delta, recd_app - delta);

        stcp_network_send(sd, header_buf, header_size, ctx->send_wind + wind_index, delta, 
            ctx->send_wind, recd_app - delta, NULL);
    } else {
        /* don't need to wrap the buffer */
        our_dprintf("not wrapping the buffer\n");
        memcpy(ctx->send_wind + wind_index, buff, recd_app);
        stcp_network_send(sd, header_buf, header_size, (ctx->send_wind + wind_index), recd_app, NULL);
    }
    ctx->sent_last_byte_sent += recd_app;

    ctx->sent_last_byte_written += recd_app;
    return 0;

}
Пример #3
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;
        }
    }
}