コード例 #1
0
ファイル: peer.c プロジェクト: homerocda/librudp
void rudp_peer_reset(struct rudp_peer *peer)
{
    struct rudp_packet_chain *pc, *tmp;
    rudp_list_for_each_safe(struct rudp_packet_chain*, pc, tmp, &peer->sendq, chain_item)
    {
        rudp_list_remove(&pc->chain_item);
        rudp_packet_chain_free(peer->rudp, pc);
    }

    if ( peer->scheduled )
        ela_remove(peer->rudp->el, peer->service_source);
    peer->scheduled = 0;

    peer->abs_timeout_deadline = rudp_timestamp() + DROP_TIMEOUT;
    peer->in_seq_reliable = (uint16_t)-1;
    peer->in_seq_unreliable = 0;
    peer->out_seq_reliable = rudp_random(peer->rudp);
    peer->out_seq_unreliable = 0;
    peer->out_seq_acked = peer->out_seq_reliable - 1;
    peer->state = PEER_NEW;
    peer->last_out_time = rudp_timestamp();
    peer->srtt = 100;
    peer->rttvar = peer->srtt / 2;
    peer->rto = MAX_RTO;
    peer->must_ack = 0;
    peer->sendto_err = 0;
}
コード例 #2
0
ファイル: peer.c プロジェクト: homerocda/librudp
static void peer_service_schedule(struct rudp_peer *peer)
{
    // If nothing in sendq: reschedule service for later
    rudp_time_t delta = ACTION_TIMEOUT;

    // just abuse for_each to get head, if it exists
    struct rudp_packet_chain *head;
    rudp_list_for_each(struct rudp_packet_chain*, head, &peer->sendq, chain_item)
    {
        struct rudp_packet_header *header = &head->packet->header;

        if ( header->opt & RUDP_OPT_RETRANSMITTED )
            // already transmitted head, wait for rto
            delta = rudp_timestamp() - peer->last_out_time + peer->rto;
        else
            // transmit asap
            delta = 0;

        // We dont really want to iterate after head
        break;
    }

    rudp_time_t to_delta = peer->abs_timeout_deadline - rudp_timestamp();

    if ( to_delta < delta )
        delta = to_delta;

    if ( delta <= 0 )
        delta = 1;

    rudp_log_printf(peer->rudp, RUDP_LOG_DEBUG,
                    "%s:%d Idle, service scheduled for %d\n",
                    __FUNCTION__, __LINE__,
                    (int)delta);

    struct timeval tv;
    rudp_timestamp_to_timeval(&tv, delta);

    ela_set_timeout(peer->rudp->el, peer->service_source, &tv, ELA_EVENT_ONCE);
    ela_add(peer->rudp->el, peer->service_source);
    peer->scheduled = 1;
}
コード例 #3
0
ファイル: peer.c プロジェクト: homerocda/librudp
static
rudp_error_t peer_send_raw(
    struct rudp_peer *peer,
    const void *data, size_t len)
{
    peer->sendto_err = rudp_endpoint_send(
        peer->endpoint, &peer->address, data, len);

    peer->last_out_time = rudp_timestamp();
    return peer->sendto_err;
}
コード例 #4
0
ファイル: peer.c プロジェクト: homerocda/librudp
static
void peer_handle_pong(
    struct rudp_peer *peer,
    const struct rudp_packet_chain *pc)
{
    rudp_time_t orig, delta;
    memcpy(&orig, pc->packet->data.data, sizeof(orig));

    delta = rudp_timestamp() - orig;

    peer_update_rtt(peer, delta);
}
コード例 #5
0
ファイル: peer.c プロジェクト: homerocda/librudp
static void peer_ping(struct rudp_peer *peer)
{
    struct rudp_packet_chain *pc = rudp_packet_chain_alloc(
        peer->rudp,
        sizeof(struct rudp_packet_header) + sizeof(rudp_time_t)
        );
    struct rudp_packet_data *data = &pc->packet->data;

    rudp_log_printf(peer->rudp, RUDP_LOG_DEBUG,
                    "%s pushing PING\n", __FUNCTION__);

    rudp_time_t now = rudp_timestamp();
    data->header.command = RUDP_CMD_PING;
    memcpy(data->data, &now, sizeof(now));

    rudp_peer_send_reliable(peer, pc);
}
コード例 #6
0
ファイル: rudp.c プロジェクト: homerocda/librudp
rudp_error_t rudp_init(
    struct rudp *rudp,
    struct ela_el *el,
    const struct rudp_handler *handler)
{
    rudp->handler = handler;
    rudp->el = el;

    rudp_list_init(&rudp->free_packet_list);
    rudp->free_packets = 0;
    rudp->allocated_packets = 0;

    rudp->seed = rudp_timestamp();
    rudp_random(rudp);
    rudp_random(rudp);
    rudp_random(rudp);

    return 0;
}
コード例 #7
0
ファイル: peer.c プロジェクト: homerocda/librudp
rudp_error_t rudp_peer_send_close_noqueue(struct rudp_peer *peer)
{
    struct rudp_packet_header header = {
        .command = RUDP_CMD_CLOSE,
        .opt = 0,
    };

    header.opt = 0;
    header.reliable = htons(peer->out_seq_reliable);
    header.unreliable = htons(++(peer->out_seq_unreliable));

    rudp_log_printf(peer->rudp, RUDP_LOG_IO,
                    ">>> outgoing noqueue %s (%d) %04x:%04x\n",
                    rudp_command_name(header.command),
                    ntohs(header.reliable),
                    header.reliable,
                    ntohs(header.unreliable));

    return peer_send_raw(peer, &header, sizeof(header));
}

/* Worker functions */

static void peer_send_queue(struct rudp_peer *peer)
{
    struct rudp_packet_chain *pc, *tmp;
    rudp_list_for_each_safe(struct rudp_packet_chain*, pc, tmp, &peer->sendq, chain_item)
    {
        struct rudp_packet_header *header = &pc->packet->header;

        if ( peer->must_ack ) {
            header->opt |= RUDP_OPT_ACK;
            header->reliable_ack = htons(peer->in_seq_reliable);
//            peer->must_ack = 0;
        }

        rudp_log_printf(peer->rudp, RUDP_LOG_IO,
                        ">>>>>> %ssend %sreliable %s %04x:%04x %s %04x\n",
                        header->opt & RUDP_OPT_RETRANSMITTED ? "RE" : "",
                        header->opt & RUDP_OPT_RELIABLE ? "" : "un",
                        rudp_command_name(pc->packet->header.command),
                        ntohs(pc->packet->header.reliable),
                        ntohs(pc->packet->header.unreliable),
                        header->opt & RUDP_OPT_ACK ? "ack" : "noack",
                        ntohs(pc->packet->header.reliable_ack));

        peer_send_raw(peer, header, pc->len);

        if ( (header->opt & RUDP_OPT_RELIABLE)
             && (header->opt & RUDP_OPT_RETRANSMITTED) ) {
            peer_rto_backoff(peer);
            break;
        }

        if ( header->opt & RUDP_OPT_RELIABLE ) {
            header->opt |= RUDP_OPT_RETRANSMITTED;
//            break;
        } else {
            rudp_list_remove(&pc->chain_item);
            rudp_packet_chain_free(peer->rudp, pc);
        }
    }
}



/*
  Two reasons may bring us here:

  - There are some (un)reliable items in the send queue, either
    - we are retransmitting
    - we just enqueued something and we need to send

  - There is nothing in the send queue and we want to ensure the peer
    is still up
 */
static void peer_service(struct rudp_peer *peer)
{
    peer->scheduled = 0;

    if ( peer->abs_timeout_deadline < rudp_timestamp() ) {
        peer->handler->dropped(peer);
        return;
    }

    if ( rudp_list_empty(&peer->sendq) ) {
        /*
          Nothing was in the send queue, so we may be in a timeout
          situation. Handle retries and final timeout.
        */
        rudp_time_t out_delta = rudp_timestamp() - peer->last_out_time;
        if ( out_delta > ACTION_TIMEOUT )
            peer_ping(peer);
    }

    peer_send_queue(peer);

    peer_service_schedule(peer);
}
コード例 #8
0
ファイル: peer.c プロジェクト: homerocda/librudp
/*
  - socket watcher
     - endpoint packet reader
        - server packet handler
           - peer packet handler <===
 */
rudp_error_t rudp_peer_incoming_packet(
    struct rudp_peer *peer, struct rudp_packet_chain *pc)
{
    const struct rudp_packet_header *header = &pc->packet->header;

    rudp_log_printf(peer->rudp, RUDP_LOG_IO,
                    "<<< incoming [%d] %s %s (%d) %04x:%04x\n",
                    peer->state,
                    (header->opt & RUDP_OPT_RELIABLE)
                        ? "reliable" : "unreliable",
                    rudp_command_name(header->command), header->command,
                    ntohs(header->reliable), ntohs(header->unreliable));

    if ( header->opt & RUDP_OPT_ACK ) {
        rudp_log_printf(peer->rudp, RUDP_LOG_IO,
                        "    has ACK flag, %04x\n",
                        (int)ntohs(header->reliable_ack));
        int broken = peer_handle_ack(peer, ntohs(header->reliable_ack));
        if ( broken ) {
            rudp_log_printf(peer->rudp, RUDP_LOG_WARN,
                            "    broken ACK flag, ignoring packet\n");
            return EINVAL;
        }
    }

    enum packet_state state;

    if ( header->opt & RUDP_OPT_RELIABLE )
        state = peer_analyse_reliable(peer, ntohs(header->reliable));
    else
        state = peer_analyse_unreliable(peer, ntohs(header->reliable),
                                        ntohs(header->unreliable));

    switch ( state ) {
    case UNSEQUENCED:
        if (peer->state == PEER_NEW
            && header->command == RUDP_CMD_CONN_REQ) {
            // Server side, handling new client
            peer_handle_connreq(peer, header);
            peer->in_seq_reliable = ntohs(header->reliable);
            peer->state = PEER_RUN;
        } else if (peer->state == PEER_CONNECTING
                   && header->command == RUDP_CMD_CONN_RSP) {
            // Client side, handling new server
            peer->in_seq_reliable = ntohs(header->reliable);
            peer_handle_ack(peer, ntohs(header->reliable_ack));
            peer->state = PEER_RUN;
        } else {
            rudp_log_printf(peer->rudp, RUDP_LOG_WARN,
                            "    unsequenced packet in state %d, ignored\n",
                            peer->state);
        }
        break;
//        return RUDP_EINVAL;

    case RETRANSMITTED:
        peer->abs_timeout_deadline = rudp_timestamp() + DROP_TIMEOUT;
        break;

    case SEQUENCED:
        peer->abs_timeout_deadline = rudp_timestamp() + DROP_TIMEOUT;

        switch ( header->command )
        {
        case RUDP_CMD_CLOSE:
            peer->state = PEER_DEAD;
            peer->handler->dropped(peer);
            rudp_log_printf(peer->rudp, RUDP_LOG_INFO,
                            "      peer dropped\n");
            return 0;

            break;

        case RUDP_CMD_PING:
            if ( peer->state == PEER_RUN ) {
                rudp_log_printf(peer->rudp, RUDP_LOG_DEBUG,
                                "       ping\n");
                peer_handle_ping(peer, pc);
            } else {
                rudp_log_printf(peer->rudp, RUDP_LOG_WARN,
                                "       ping while not running\n");
            }
            break;

        case RUDP_CMD_PONG:
            if ( peer->state == PEER_RUN ) {
                rudp_log_printf(peer->rudp, RUDP_LOG_DEBUG,
                                "       pong\n");
                peer_handle_pong(peer, pc);
            } else {
                rudp_log_printf(peer->rudp, RUDP_LOG_WARN,
                                "       pong while not running\n");
            }
            break;

        case RUDP_CMD_NOOP:
        case RUDP_CMD_CONN_REQ:
        case RUDP_CMD_CONN_RSP:
             break;

        default:
            if ( peer->state != PEER_RUN ) {
                rudp_log_printf(peer->rudp, RUDP_LOG_WARN,
                                "       user payload while not running\n");
                break;
            }

            if ( header->command >= RUDP_CMD_APP )
                peer->handler->handle_packet(peer, pc);
        }
    }

    if ( header->opt & RUDP_OPT_RELIABLE ) {
        rudp_log_printf(peer->rudp, RUDP_LOG_DEBUG,
                        "       reliable packet, posting ack\n");
        peer_post_ack(peer);
    }
    
    peer_service_schedule(peer);

    return 0;
}
コード例 #9
0
ファイル: utils.c プロジェクト: AnwarMohamed/librudp
uint64_t rudp_random()
{
    srand(rudp_timestamp());    
    return rand();
}