Пример #1
0
/* ***************************************************
 * Function: init_ctx
 * ***************************************************
 * 	Initiate the connection context structure
 */
static context_t* init_ctx(bool_t is_active)
{
	srand((unsigned)time(0));
	context_t *ctx = (context_t *) calloc(1, sizeof(context_t));
	assert(ctx);
	ctx->connection_state = CSTATE_CLOSED;
	generate_initial_seq_num(ctx);
	if (is_active){
		/* Because time(0) can be the same for client/server due to low
		 * granularity, call it again for one side */
		generate_initial_seq_num(ctx); 
	}
	init_window(&(ctx->sbuffer));
	init_window(&(ctx->rbuffer));
	ctx->estimated_rtt = 0;
	ctx->devrtt = 0;
	ctx->rto = INIT_RTO;
	return ctx;
}
Пример #2
0
/* 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;
    int res;
    ctx = (context_t *) calloc(1, sizeof(context_t));
    assert(ctx);

    generate_initial_seq_num(ctx);
    ctx->connection_state = CSTATE_CLOSED;
    
    ctx->send_wind = (uint8_t *) malloc(MAX_WINDOW_SIZE);
    memset(ctx->send_wind, 0, MAX_WINDOW_SIZE);

    ctx->recv_wind = (uint8_t *) malloc(MAX_WINDOW_SIZE);
    memset(ctx->recv_wind, 0, MAX_WINDOW_SIZE);
    res = open_tcp_conn(sd, ctx, is_active);

    /* 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.
     */

    stcp_unblock_application(sd);


    if (ctx->connection_state == CSTATE_ESTABLISHED){
        control_loop(sd, ctx);
    } else if (ctx->connection_state == CSTATE_FIN_WAIT_1){
        close_tcp_conn(sd, ctx);
    } else if (ctx->connection_state == CSTATE_CLOSED) {
        ;
    }else {
        our_dprintf("bad state in transport init");
        assert(0);
    }

    /* do any cleanup here */
    free(ctx->send_wind);
    free(ctx->recv_wind);
    free(ctx);
}
Пример #3
0
/* 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;

    ctx = (context_t *) calloc(1, sizeof(context_t));
    assert(ctx);
    
 
    generate_initial_seq_num(ctx);
    ctx->connection_state = CSTATE_CLOSED;
    //init all buffer

    /* 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 (!transport_3way_handshake(sd, ctx))
    {
        stcp_unblock_application(sd);
        free(ctx);
        return;
    }

    //init send and recv buffer here
    
    
    
    ctx->connection_state = CSTATE_ESTABLISHED;
    stcp_unblock_application(sd);

    control_loop(sd, ctx);

    /* do any cleanup here */
    free(ctx);
}
Пример #4
0
/* 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);
}