Changeset 7cf7ded in mainline


Ignore:
Timestamp:
2011-11-15T23:50:57Z (12 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
4f3f6285
Parents:
8218b6b
Message:

TCP retransmission (WIP). Allow setting timer in timer handler.
Simulate packet drop. Fixes.

Location:
uspace
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/generic/fibril_synch.c

    r8218b6b r7cf7ded  
    474474                    timer->delay);
    475475                if (rc == ETIMEOUT) {
     476                        timer->state = fts_fired;
     477                        fibril_mutex_unlock(&timer->lock);
    476478                        timer->fun(timer->arg);
    477                         timer->state = fts_fired;
     479                        fibril_mutex_lock(&timer->lock);
    478480                }
    479481        }
  • uspace/srv/net/tl/tcp/conn.c

    r8218b6b r7cf7ded  
    6969{
    7070        tcp_conn_t *conn = NULL;
     71        bool tqueue_inited = false;
    7172
    7273        /* Allocate connection structure */
     
    105106
    106107        /* Initialize retransmission queue */
    107         tcp_tqueue_init(&conn->retransmit, conn);
     108        if (tcp_tqueue_init(&conn->retransmit, conn) != EOK)
     109                goto error;
     110
     111        tqueue_inited = true;
    108112
    109113        conn->cstate = st_listen;
     
    116120
    117121error:
     122        if (tqueue_inited)
     123                tcp_tqueue_fini(&conn->retransmit);
    118124        if (conn != NULL && conn->rcv_buf != NULL)
    119125                free(conn->rcv_buf);
     
    180186                break;
    181187        default:
     188                log_msg(LVL_ERROR, "Connection state %d", conn->cstate);
    182189                assert(false);
    183190        }
     
    264271                return true;
    265272        case st_closed:
     273                log_msg(LVL_WARN, "state=%d", (int) conn->cstate);
    266274                assert(false);
    267275        }
     
    347355
    348356        if ((seg->ctrl & CTL_RST) != 0) {
    349                 log_msg(LVL_DEBUG, "Connection reset.");
     357                log_msg(LVL_DEBUG, "Connection reset. -> Closed");
    350358                /* XXX Signal user error */
    351359                conn->cstate = st_closed;
     
    413421        log_msg(LVL_DEBUG, "tcp_conn_sa_seq(%p, %p)", conn, seg);
    414422
    415         /* XXX Discard old duplicates */
     423        /* Discard unacceptable segments ("old duplicates") */
     424        if (!seq_no_segment_acceptable(conn, seg)) {
     425                log_msg(LVL_DEBUG, "Replying ACK to unacceptable segment.");
     426                tcp_tqueue_ctrl_seg(conn, CTL_ACK);
     427                tcp_segment_delete(seg);
     428                return;
     429        }
    416430
    417431        /* Queue for processing */
     
    463477static cproc_t tcp_conn_seg_proc_syn(tcp_conn_t *conn, tcp_segment_t *seg)
    464478{
    465         /* TODO */
    466         return cp_continue;
     479        if ((seg->ctrl & CTL_SYN) == 0)
     480                return cp_continue;
     481
     482        /*
     483         * Assert SYN is in receive window, otherwise this step should not
     484         * be reached.
     485         */
     486        assert(seq_no_in_rcv_wnd(conn, seg->seq));
     487
     488        log_msg(LVL_WARN, "SYN is in receive window, should send reset. XXX");
     489
     490        /*
     491         * TODO
     492         *
     493         * Send a reset, resond "reset" to all outstanding RECEIVEs and SEND,
     494         * flush segment queues. Send unsolicited "connection reset" signal
     495         * to user, connection -> closed state, delete TCB, return.
     496         */
     497        return cp_done;
    467498}
    468499
     
    790821{
    791822        log_msg(LVL_DEBUG, "tcp_conn_seg_proc_fin(%p, %p)", conn, seg);
     823        log_msg(LVL_DEBUG, " seg->len=%zu, seg->ctl=%u", (size_t) seg->len,
     824            (unsigned) seg->ctrl);
    792825
    793826        /* Only process FIN if no text is left in segment. */
     
    896929         * incoming segments queue.
    897930         */
    898         if (seg->len > 0)
     931        if (seg->len > 0) {
     932                log_msg(LVL_DEBUG, "Re-insert segment %p. seg->len=%zu",
     933                    seg, (size_t) seg->len);
    899934                tcp_iqueue_insert_seg(&conn->incoming, seg);
    900         else
     935        } else {
    901936                tcp_segment_delete(seg);
     937        }
    902938}
    903939
     
    927963                tcp_conn_sa_queue(conn, seg); break;
    928964        case st_closed:
     965                log_msg(LVL_DEBUG, "state=%d", (int) conn->cstate);
    929966                assert(false);
    930967        }
  • uspace/srv/net/tl/tcp/ncsim.c

    r8218b6b r7cf7ded  
    4848#include "ncsim.h"
    4949#include "rqueue.h"
     50#include "segment.h"
    5051#include "tcp_type.h"
    5152
     
    7374        link_t *link;
    7475
    75         log_msg(LVL_DEBUG, "tcp_ncsim_insert_seg()");
     76        log_msg(LVL_DEBUG, "tcp_ncsim_bounce_seg()");
     77        tcp_rqueue_bounce_seg(sp, seg);
     78        return;
     79
     80        if (0 /*random() % 4 == 3*/) {
     81                /* Drop segment */
     82                log_msg(LVL_ERROR, "NCSim dropping segment");
     83                tcp_segment_delete(seg);
     84                return;
     85        }
    7686
    7787        sqe = calloc(1, sizeof(tcp_squeue_entry_t));
  • uspace/srv/net/tl/tcp/seq_no.c

    r8218b6b r7cf7ded  
    8888}
    8989
     90/** Determine if sequence number is in receive window. */
     91bool seq_no_in_rcv_wnd(tcp_conn_t *conn, uint32_t sn)
     92{
     93        return seq_no_le_lt(conn->rcv_nxt, sn, conn->rcv_nxt + conn->rcv_wnd);
     94}
     95
    9096/** Determine segment has new window update.
    9197 *
  • uspace/srv/net/tl/tcp/seq_no.h

    r8218b6b r7cf7ded  
    4141extern bool seq_no_ack_acceptable(tcp_conn_t *, uint32_t);
    4242extern bool seq_no_ack_duplicate(tcp_conn_t *, uint32_t);
     43extern bool seq_no_in_rcv_wnd(tcp_conn_t *, uint32_t);
    4344extern bool seq_no_new_wnd_update(tcp_conn_t *, tcp_segment_t *);
    4445extern bool seq_no_segment_acked(tcp_conn_t *, tcp_segment_t *, uint32_t);
  • uspace/srv/net/tl/tcp/state.c

    r8218b6b r7cf7ded  
    112112        log_msg(LVL_DEBUG, "tcp_uc_receive()");
    113113
     114        /*
     115         * XXX Handle all states for all user calls properly, return
     116         * errors as appropriate.
     117         */
     118        if (conn->cstate == st_closed)
     119                return;
     120
     121
    114122        fibril_mutex_lock(&conn->rcv_buf_lock);
    115123
     
    186194
    187195        conn = tcp_conn_find(sp);
    188         if (conn != NULL) {
     196        if (conn != NULL && conn->cstate != st_closed) {
    189197                tcp_conn_segment_arrived(conn, seg);
    190198        } else {
  • uspace/srv/net/tl/tcp/tcp_type.h

    r8218b6b r7cf7ded  
    9494} tcp_sockpair_t;
    9595
     96/** Connection incoming segments queue */
    9697typedef struct {
    9798        struct tcp_conn *conn;
     
    99100} tcp_iqueue_t;
    100101
     102/** Retransmission queue */
    101103typedef struct {
    102104        struct tcp_conn *conn;
    103105        list_t list;
     106
     107        /** Retransmission timer */
     108        fibril_timer_t *timer;
    104109} tcp_tqueue_t;
    105110
    106111typedef struct tcp_conn {
     112        char *name;
    107113        link_t link;
    108114
     
    221227} tcp_iqueue_entry_t;
    222228
    223 typedef struct {
    224         link_t link;
     229/** Retransmission queue entry */
     230typedef struct {
     231        link_t link;
     232        tcp_conn_t *conn;
    225233        tcp_segment_t *seg;
    226234} tcp_tqueue_entry_t;
  • uspace/srv/net/tl/tcp/test.c

    r8218b6b r7cf7ded  
    5959        sock.addr.ipv4 = 0x7f000001;
    6060        tcp_uc_open(80, &sock, ap_passive, &conn);
     61        conn->name = (char *) "S";
    6162
    6263        while (true) {
     
    7374        }
    7475
    75         async_usleep(1000*1000);
     76        async_usleep(/*10**/1000*1000);
    7677
    7778        printf("test_srv() close connection\n");
     
    9495        async_usleep(1000*1000*3);
    9596        tcp_uc_open(1024, &sock, ap_active, &conn);
     97        conn->name = (char *) "C";
    9698
    9799        async_usleep(1000*1000*10);
    98100        tcp_uc_send(conn, (void *)msg, str_size(msg), 0);
    99101
    100         async_usleep(1000*1000*3);
     102        async_usleep(1000*1000*3/**20*2*/);
    101103        tcp_uc_close(conn);
    102104}
  • uspace/srv/net/tl/tcp/tqueue.c

    r8218b6b r7cf7ded  
    3636
    3737#include <adt/list.h>
     38#include <errno.h>
     39#include <fibril_synch.h>
    3840#include <byteorder.h>
    3941#include <io/log.h>
     
    5052#include "tcp_type.h"
    5153
    52 void tcp_tqueue_init(tcp_tqueue_t *tqueue, tcp_conn_t *conn)
     54#define RETRANSMIT_TIMEOUT      (2*1000*1000)
     55
     56static void retransmit_timeout_func(void *arg);
     57static void tcp_tqueue_timer_set(tcp_conn_t *conn);
     58static void tcp_tqueue_timer_clear(tcp_conn_t *conn);
     59
     60int tcp_tqueue_init(tcp_tqueue_t *tqueue, tcp_conn_t *conn)
    5361{
    5462        tqueue->conn = conn;
     63        tqueue->timer = fibril_timer_create();
     64        if (tqueue->timer == NULL)
     65                return ENOMEM;
     66
    5567        list_initialize(&tqueue->list);
     68
     69        return EOK;
     70}
     71
     72void tcp_tqueue_fini(tcp_tqueue_t *tqueue)
     73{
     74        if (tqueue->timer != NULL) {
     75                fibril_timer_destroy(tqueue->timer);
     76                tqueue->timer = NULL;
     77        }
    5678}
    5779
     
    92114                }
    93115
     116                tqe->conn = conn;
    94117                tqe->seg = rt_seg;
    95118                list_append(&tqe->link, &conn->retransmit.list);
    96         }
    97 
     119
     120                /* Set retransmission timer */
     121                tcp_tqueue_timer_set(conn);
     122        }
     123
     124        tcp_prepare_transmit_segment(conn, seg);
     125}
     126
     127void tcp_prepare_transmit_segment(tcp_conn_t *conn, tcp_segment_t *seg)
     128{
    98129        /*
    99130         * Always send ACK once we have received SYN, except for RST segments.
     
    105136
    106137        seg->seq = conn->snd_nxt;
    107         seg->wnd = conn->rcv_wnd;
    108 
    109         log_msg(LVL_DEBUG, "SEG.SEQ=%" PRIu32 ", SEG.WND=%" PRIu32,
    110             seg->seq, seg->wnd);
    111 
    112         if ((seg->ctrl & CTL_ACK) != 0)
    113                 seg->ack = conn->rcv_nxt;
    114         else
    115                 seg->ack = 0;
    116 
    117138        conn->snd_nxt += seg->len;
    118139
     
    204225                        tcp_segment_delete(tqe->seg);
    205226                        free(tqe);
     227
     228                        /* Reset retransmission timer */
     229                        tcp_tqueue_timer_set(conn);
    206230                }
    207231
    208232                cur = next;
    209233        }
     234
     235        /* Clear retransmission timer if the queue is empty. */
     236        if (list_empty(&conn->retransmit.list))
     237                tcp_tqueue_timer_clear(conn);
    210238
    211239        /* Possibly transmit more data */
     
    213241}
    214242
     243void tcp_conn_transmit_segment(tcp_conn_t *conn, tcp_segment_t *seg)
     244{
     245        log_msg(LVL_DEBUG, "tcp_conn_transmit_segment(%p, %p)", conn, seg);
     246
     247        seg->wnd = conn->rcv_wnd;
     248
     249        if ((seg->ctrl & CTL_ACK) != 0)
     250                seg->ack = conn->rcv_nxt;
     251        else
     252                seg->ack = 0;
     253
     254        tcp_transmit_segment(&conn->ident, seg);
     255}
     256
    215257void tcp_transmit_segment(tcp_sockpair_t *sp, tcp_segment_t *seg)
    216258{
    217259        log_msg(LVL_DEBUG, "tcp_transmit_segment(%p, %p)", sp, seg);
     260
     261        log_msg(LVL_DEBUG, "SEG.SEQ=%" PRIu32 ", SEG.WND=%" PRIu32,
     262            seg->seq, seg->wnd);
    218263/*
    219264        tcp_pdu_prepare(conn, seg, &data, &len);
    220265        tcp_pdu_transmit(data, len);
    221266*/
    222         //tcp_rqueue_bounce_seg(sp, seg);
    223         tcp_ncsim_bounce_seg(sp, seg);
     267        tcp_rqueue_bounce_seg(sp, seg);
     268//      tcp_ncsim_bounce_seg(sp, seg);
     269}
     270
     271static void retransmit_timeout_func(void *arg)
     272{
     273        tcp_conn_t *conn = (tcp_conn_t *) arg;
     274        tcp_tqueue_entry_t *tqe;
     275        tcp_segment_t *rt_seg;
     276        link_t *link;
     277
     278        log_msg(LVL_DEBUG, "### %s: retransmit_timeout_func(%p)", conn->name, conn);
     279        link = list_first(&conn->retransmit.list);
     280        if (link == NULL) {
     281                log_msg(LVL_DEBUG, "Nothing to retransmit");
     282                return;
     283        }
     284
     285        tqe = list_get_instance(link, tcp_tqueue_entry_t, link);
     286
     287        rt_seg = tcp_segment_dup(tqe->seg);
     288        if (rt_seg == NULL) {
     289                log_msg(LVL_ERROR, "Memory allocation failed.");
     290                /* XXX Handle properly */
     291                return;
     292        }
     293
     294        log_msg(LVL_DEBUG, "### %s: retransmitting segment", conn->name);
     295        tcp_conn_transmit_segment(tqe->conn, rt_seg);
     296
     297        /* Reset retransmission timer */
     298        tcp_tqueue_timer_set(tqe->conn);
     299}
     300
     301/** Set or re-set retransmission timer */
     302static void tcp_tqueue_timer_set(tcp_conn_t *conn)
     303{
     304        log_msg(LVL_DEBUG, "### %s: tcp_tqueue_timer_set()", conn->name);
     305
     306        (void) retransmit_timeout_func;
     307        fibril_timer_set(conn->retransmit.timer, RETRANSMIT_TIMEOUT,
     308            retransmit_timeout_func, (void *) conn);
     309}
     310
     311/** Clear retransmission timer */
     312static void tcp_tqueue_timer_clear(tcp_conn_t *conn)
     313{
     314        log_msg(LVL_DEBUG, "### %s: tcp_tqueue_timer_clear()", conn->name);
     315
     316        fibril_timer_clear(conn->retransmit.timer);
    224317}
    225318
  • uspace/srv/net/tl/tcp/tqueue.h

    r8218b6b r7cf7ded  
    3939#include "tcp_type.h"
    4040
    41 extern void tcp_tqueue_init(tcp_tqueue_t *, tcp_conn_t *);
     41extern int tcp_tqueue_init(tcp_tqueue_t *, tcp_conn_t *);
     42extern void tcp_tqueue_fini(tcp_tqueue_t *);
    4243extern void tcp_tqueue_ctrl_seg(tcp_conn_t *, tcp_control_t);
    4344extern void tcp_tqueue_seg(tcp_conn_t *, tcp_segment_t *);
    4445extern void tcp_tqueue_new_data(tcp_conn_t *);
    4546extern void tcp_tqueue_ack_received(tcp_conn_t *);
     47extern void tcp_prepare_transmit_segment(tcp_conn_t *, tcp_segment_t *);
     48extern void tcp_conn_transmit_segment(tcp_conn_t *, tcp_segment_t *);
    4649extern void tcp_transmit_segment(tcp_sockpair_t *, tcp_segment_t *);
    4750extern void tcp_header_setup(tcp_conn_t *, tcp_segment_t *, tcp_header_t *);
Note: See TracChangeset for help on using the changeset viewer.