コード例 #1
0
ファイル: transport.c プロジェクト: petergrabowski/networks
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;

}
コード例 #2
0
ファイル: transport.c プロジェクト: jianglanic/STCP
static void transport_send_data(mysocket_t sd, char* data, int len, context_t* ctx)//LAN
{
    strncpy(send_buffer, data);
    ctx.next_seq += len;
    ssize_t result = stcp_network_send(sd, send_buffer, sizeof(send_buffer), NULL);
    //send real app data or stub data   
    
}
コード例 #3
0
ファイル: transport.c プロジェクト: firehazard/Router
/* ***************************************************
 * Function: network_send
 * ***************************************************
 * Wrapper function for sending network data.  It converts header fields
 * into network byte-order but then changes them back before returning
 * in case the caller plans to use that packet later on.
 */
ssize_t network_send(mysocket_t sd, const void *src, size_t src_len)
{
	struct tcphdr* hdr = (struct tcphdr *)src;
	hdr->th_ack = htonl(hdr->th_ack);
	hdr->th_seq = htonl(hdr->th_seq);
	hdr->th_win = htons(hdr->th_win);
	hdr->th_flags = hdr->th_flags;
	hdr->th_off = hdr->th_off;	
	ssize_t result;
	while ((result = stcp_network_send(sd, src, src_len, NULL))<0);
	hdr->th_ack = ntohl(hdr->th_ack);
	hdr->th_seq = ntohl(hdr->th_seq);
	hdr->th_win = ntohs(hdr->th_win);
	return result;	
}
コード例 #4
0
ファイル: transport.c プロジェクト: jianglanic/STCP
static void transport_send_head(mysocket_t sd, int hflag, context_t* ctx)//LAN
{
    struct tcphdr head;
    //fill a ACK header
    head.th_flags = hflag;
    head.th_seq = ;//unsent seq number
    head.th_ack = ctx->next_seq;//ctx->next_seq;
    head.th_win = ;//???
    head.th_seq = htons(head.th_seq);
    head.th_ack = htons(head.th_ack);
    head.th_win = htons(head.th_win);
    ssize_t result = stcp_network_send(sd, send_buffer, sizeof(struct tcphdr), NULL);
    //use htonl htons to codec
    
}
コード例 #5
0
ファイル: transport.c プロジェクト: petergrabowski/networks
int send_syn_ack_fin(mysocket_t sd, context_t * ctx, uint8_t to_send_flags, 
    tcp_seq seq_num, tcp_seq ack_num) {

    size_t len =  sizeof(struct tcphdr);
    uint8_t buff[len];

    struct tcphdr * tcp_packet  = (struct tcphdr *) buff;

    /* th_sport, th_dport, th_sum are set by network layer */
    /* th_urg is ignored by stcp*/

    if (to_send_flags & SEND_SYN) {
        tcp_packet->th_seq = htonl(seq_num);
        tcp_packet->th_flags |= TH_SYN;
        ctx->sent_last_byte_written = seq_num;
        ctx->sent_last_byte_sent = seq_num;
    } else {
        tcp_packet->th_seq = htonl(ctx->sent_last_byte_sent + 1);
    }

    if (to_send_flags & SEND_ACK) {
        tcp_packet->th_ack = htonl(ack_num);
        tcp_packet->th_flags |= TH_ACK;
        //our_dprintf("sending ack %u\n", ack_num);
    } 

    if (to_send_flags & SEND_FIN) {
        tcp_packet->th_flags |= TH_FIN;
        ctx->sent_last_byte_sent++;
        ctx->sent_last_byte_written++;
    }

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

    /* set adv window size */
    tcp_packet->th_win = htons(calc_adv_wind(ctx));
    ctx->sent_adv_window = calc_adv_wind(ctx);
    /* send the newly constructed packet */ 
    ssize_t n = stcp_network_send(sd, buff , len, 0);
    if (n == -1){
        fprintf(stderr,"error: client bad send\n");
        return -1;
    }

    return 0;
}
コード例 #6
0
ファイル: transport.c プロジェクト: jsachs/uchi_networks
/* 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;
        }
    }
}
コード例 #7
0
ファイル: transport.c プロジェクト: jsachs/uchi_networks
/* initialise the transport layer, and start the main loop, handling
 * any data from the peer or the application.  this function should not
 * return until the connection is closed.
 */
void transport_init(mysocket_t sd, bool_t is_active)
{
    context_t *ctx;
    uint8_t flags;
    int tcplen;

    ctx = (context_t *) calloc(1, sizeof(context_t));
    assert(ctx);

    /* ensures this array begins as entirely null characters */
    memset(ctx->recv_indicator, '\0', WINLEN);

    char buffer[sizeof(STCPHeader) + MAXLEN];

    generate_initial_seq_num(ctx);

    ctx->connection_state = CSTATE_CLOSED;
    list_t unackd;
    ctx->unackd_packets = &unackd;
    list_init(ctx->unackd_packets);

    /* used for setting timeouts */
    struct timespec timestart;
    struct timespec *timeout;

    /* XXX: you should send a SYN packet here if is_active, or wait for one
     * to arrive if !is_active.  after the handshake completes, unblock the
     * application with stcp_unblock_application(sd).  you may also use
     * this to communicate an error condition back to the application, e.g.
     * if connection fails; to do so, just set errno appropriately (e.g. to
     * ECONNREFUSED, etc.) before calling the function.
     */
    if(is_active)
    {
        ctx->send_unack = ctx->initial_sequence_num;

        STCPHeader *header = make_stcp_packet(TH_SYN, ctx->send_unack, 0, 0);
        /* first step in the handshake: sending a SYN packet */
        tcplen = stcp_network_send(sd, header, sizeof(STCPHeader), NULL);
        ctx->send_next = ctx->send_unack;
        /* this ensures the SYN packet will be resent if it is dropped/times out */
        packet_t_create(ctx, header, sizeof(STCPHeader));
        DEBUG("Sent SYN packet with seq number %d\n", ntohl(header->th_seq));

        if(tcplen < 0) {
            DEBUG("SYN send failed");
            errno = ECONNREFUSED;
        }
        else
        {
            ctx->send_next++;
            ctx->connection_state = CSTATE_SYN_SENT;
            /* the client now waits for a SYN/ACK */
            while(ctx->connection_state == CSTATE_SYN_SENT)
            {
                timestart = ((packet_t *)list_get_at(ctx->unackd_packets, 0))->start_time;
                timeout = &timestart;

                timeout->tv_sec += ctx->rto.tv_sec;
                timeout->tv_nsec += ctx->rto.tv_nsec;

                if (timeout->tv_nsec >= 1000000000) {
                    timeout->tv_sec  += timeout->tv_nsec / 1000000000;
                    timeout->tv_nsec = timeout->tv_nsec % 1000000000;
                }

                unsigned int event = stcp_wait_for_event(sd, NETWORK_DATA, timeout); /* yes we need to add timeout later */

                if(event & NETWORK_DATA)
                {
                    /* we now expect the next packet to be a SYN-ACK */
                    tcplen = recv_packet(sd, ctx, NULL, 0,  header);
                    flags = (TH_SYN|TH_ACK);
                    if( tcplen < 0 || !((header->th_flags & TH_SYN)&&(header->th_flags & TH_ACK))) {
                        DEBUG("Did not receive SYN/ACK\n");
                        continue;
                    }
                    else
                    {
                        DEBUG("packet received with seq %d and ack %d\n", ntohl(header->th_seq), ntohl(header->th_ack));
                        if(ntohl(header->th_ack) == ctx->send_next) {
                            header = make_stcp_packet(TH_ACK, ctx->send_next, ctx->recv_next, 0);
                            tcplen = stcp_network_send(sd, header, sizeof(STCPHeader), NULL);
                            /* the client now sends an ACK packet, and goes to the ESTABLISHED state */
                            DEBUG("Sent ACK packet with seq number %d\n", ntohl(header->th_seq));
                            if(tcplen < 0) {
                                DEBUG("ACK send failed");
                                errno = ECONNABORTED;
                                break;
                            }
                            ctx->connection_state = CSTATE_ESTABLISHED;
                            free(header);
                            header = NULL;
                        }
                    }
                }
            }
        }
    }
    if(!is_active)
    {
        /* wait for a SYN packet */
        while(ctx->connection_state == CSTATE_CLOSED)
        {
            ctx->send_unack = ctx->initial_sequence_num;
            ctx->send_next = ctx->send_unack;
            unsigned int event = stcp_wait_for_event(sd, NETWORK_DATA|TIMEOUT, NULL);

            if(event & NETWORK_DATA) {
                STCPHeader *header = (STCPHeader *) malloc(sizeof(STCPHeader));
                tcplen = recv_packet(sd, ctx, NULL, 0, header);
                if(tcplen < 0 || header->th_flags != TH_SYN) {
                    DEBUG("Did not receive SYN packet\n");
                    continue;
                }
                else
                {
                    DEBUG("Received SYN with seq number %d\n", ntohl(header->th_seq));
                    ctx->connection_state = CSTATE_SYN_RECEIVED;
                    header = make_stcp_packet(TH_SYN|TH_ACK, ctx->send_unack, ctx->recv_next, 0);
                    tcplen = stcp_network_send(sd, header, sizeof(STCPHeader), NULL);
                    packet_t_create(ctx, header, sizeof(STCPHeader));
                    /* send out a SYN/ACK packet to the initiating client */
                    DEBUG("SYN/ACK sent with ack number %d and seq number %d\n", htonl(header->th_ack), htonl(header->th_seq));
                    if(tcplen < 0) {
                        DEBUG("SYN/ACK send failed");
                        errno = ECONNABORTED;
                        break;
                    }
                    /* ensures the SYN-ACK will be resent if it is not ACK'd */
                    packet_t_create(ctx, header, sizeof(STCPHeader));
                    ctx->send_next++;
                }
            }
        }
        while(ctx->connection_state == CSTATE_SYN_RECEIVED)
        {
            timestart = ((packet_t *)list_get_at(ctx->unackd_packets, 0))->start_time;
            timeout = &timestart;

            timeout->tv_sec += ctx->rto.tv_sec;
            timeout->tv_nsec += ctx->rto.tv_nsec;

            if (timeout->tv_nsec >= 1000000000) {
                timeout->tv_sec  += timeout->tv_nsec / 1000000000;
                timeout->tv_nsec = timeout->tv_nsec % 1000000000;
            }

            unsigned int event = stcp_wait_for_event(sd, NETWORK_DATA, timeout);
            if(event & NETWORK_DATA) {
                STCPHeader *header = (STCPHeader *) buffer;
                tcplen = recv_packet(sd, ctx, NULL, 0, header);
                if(tcplen < 0 || !(header->th_flags & TH_ACK)) {
                    DEBUG("Did not receive ACK packet\n");
                    continue;
                }
                /* if it's the right ACK packet, go to the ESTABLISHED state */
                if(ntohl(header->th_ack) == ctx->send_next) {
                    DEBUG("Received ACK with ack number %d\n", ntohl(header->th_ack));
                    ctx->connection_state = CSTATE_ESTABLISHED;
                }
            }
        }
    }
    if(ctx->connection_state == CSTATE_ESTABLISHED)
        DEBUG("State: seq %d ack %d send window %d\n", ctx->send_next, ctx->recv_next, ctx->send_wind);


    /* unblocks the application */
    /* relays possible error conditions */
    stcp_unblock_application(sd);

    control_loop(sd, ctx);

    /* do any cleanup here */
    free(ctx);
}