Esempio n. 1
0
/* ***************************************************
 * Function: transport_init
 * ***************************************************
 * 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 = init_ctx(is_active);
	bool success = false;
    if (is_active) {
		success = active_init(sd, ctx);		
    }
    else {
    	success = passive_init(sd, ctx);    	
    }
	if (success){  	
  	    ctx->connection_state = CSTATE_ESTABLISHED;
	    stcp_unblock_application(sd);
	    control_loop(sd, ctx);
	}
	else {
		errno = ETIMEDOUT;
		stcp_unblock_application(sd);
	}
	teardown_resources(ctx);
	/* Wait for potential pending processes in 
	 * other side (this is to fix a bug in the starter code) */
	sleep(1);		
	our_dprintf("Exiting Loop!\n");
}
Esempio n. 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;

    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);
}
Esempio n. 3
0
/* transport layer thread; transport_init() should not return until the
 * transport layer finishes (i.e. the connection is over).
 */
static void *transport_thread_func(void *arg_ptr)
{
    mysock_context_t *ctx = (mysock_context_t *) arg_ptr;
    char eof_packet;

    assert(ctx);
    ASSERT_VALID_MYSOCKET_DESCRIPTOR(ctx, ctx->my_sd);

    /* enter the STCP control loop.  transport_init() doesn't return until the
     * connection's finished.  that function should first signal establishment
     * of the connection after SYN/SYN-ACK (or an error condition if the
     * connection couldn't be established) to the application by using
     * stcp_unblock_application(); as the name suggests, this unblocks the
     * calling code.  transport_init() then handles the connection,
     * returning only after the connection is closed.
     */
    transport_init(ctx->my_sd, ctx->is_active);

    /* transport_init() has returned; both sides have closed the connection,
     * do some final cleanup here...
     */

    PTHREAD_CALL(pthread_mutex_lock(&ctx->blocking_lock));
    if (ctx->blocking)
    {
        /* if we're still blocked, STCP must not have indicated the
         * connection completed.  pass the error up to the application.
         */
        if (errno == 0 || errno == EINTR)
        {
            /* this is a bit of a kludge--this should really be set by STCP
             * itself, but it's a reasonable guess if for some reason (e.g.
             * oversight) the transport layer hasn't announced why it
             * bailed out...
             */
            errno = (ctx->is_active) ? ECONNREFUSED : ECONNABORTED;
        }
        PTHREAD_CALL(pthread_mutex_unlock(&ctx->blocking_lock));
        stcp_unblock_application(ctx->my_sd);
    }
    else
    {
        PTHREAD_CALL(pthread_mutex_unlock(&ctx->blocking_lock));
    }

    /* force final myread() to return 0 bytes (this should have been done
     * by the transport layer already in response to the peer's FIN).
     */
    _mysock_enqueue_buffer(ctx, &ctx->app_send_queue, &eof_packet, 0);
    return NULL;
}
Esempio n. 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;
    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);
}
Esempio n. 5
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);
}