Changeset 0093ab6 in mainline


Ignore:
Timestamp:
2011-09-21T19:56:41Z (12 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
032bbe7
Parents:
4c55a64
Message:

Parts of data reception. Trimming segment to receive window.

Location:
uspace/srv/net/tl/tcp
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/net/tl/tcp/conn.c

    r4c55a64 r0093ab6  
    3838#include <errno.h>
    3939#include <io/log.h>
     40#include <macros.h>
    4041#include <stdlib.h>
    4142#include "conn.h"
     
    4647#include "tqueue.h"
    4748
     49#define RCV_BUF_SIZE 4096
     50
    4851LIST_INITIALIZE(conn_list);
    4952
     
    5457        tcp_conn_t *conn;
    5558
     59        /* Allocate connection structure */
    5660        conn = calloc(1, sizeof(tcp_conn_t));
    5761        if (conn == NULL)
    5862                return NULL;
    5963
     64        /* Allocate receive buffer */
     65        conn->rcv_buf_size = RCV_BUF_SIZE;
     66        conn->rcv_buf_used = 0;
     67        conn->rcv_buf = calloc(1, conn->rcv_buf_size);
     68        if (conn->rcv_buf == NULL) {
     69                free(conn);
     70                return NULL;
     71        }
     72
     73        /* Set up receive window. */
     74        conn->rcv_wnd = conn->rcv_buf_size;
     75
     76        /* Initialize incoming segment queue */
    6077        tcp_iqueue_init(&conn->incoming, conn);
    6178
     
    175192
    176193        tcp_tqueue_ctrl_seg(conn, CTL_SYN | CTL_ACK /* XXX */);
     194
     195        tcp_segment_delete(seg);
    177196}
    178197
     
    225244                tcp_tqueue_ctrl_seg(conn, CTL_SYN | CTL_ACK /* XXX */);
    226245        }
     246
     247        tcp_segment_delete(seg);
    227248}
    228249
     
    288309static cproc_t tcp_conn_seg_proc_ack_est(tcp_conn_t *conn, tcp_segment_t *seg)
    289310{
     311        log_msg(LVL_DEBUG, "tcp_conn_seg_proc_ack_est(%p, %p)", conn, seg);
     312
     313        log_msg(LVL_DEBUG, "SEG.ACK=%u, SND.UNA=%u, SND.NXT=%u",
     314            (unsigned)seg->ack, (unsigned)conn->snd_una,
     315            (unsigned)conn->snd_nxt);
     316
    290317        if (!seq_no_ack_acceptable(conn, seg->ack)) {
     318                log_msg(LVL_DEBUG, "ACK not acceptable.");
    291319                if (!seq_no_ack_duplicate(conn, seg->ack)) {
     320                        log_msg(LVL_WARN, "Not acceptable, not duplicate. "
     321                            "Send ACK and drop.");
    292322                        /* Not acceptable, not duplicate. Send ACK and drop. */
    293323                        tcp_tqueue_ctrl_seg(conn, CTL_ACK);
    294324                        tcp_segment_delete(seg);
    295325                        return cp_done;
     326                } else {
     327                        log_msg(LVL_DEBUG, "Ignoring duplicate ACK.");
    296328                }
    297329        } else {
     
    401433}
    402434
     435/** Process segment text. */
    403436static cproc_t tcp_conn_seg_proc_text(tcp_conn_t *conn, tcp_segment_t *seg)
    404437{
     438        size_t text_size;
     439        size_t xfer_size;
     440
     441        log_msg(LVL_DEBUG, "tcp_conn_seg_proc_text(%p, %p)", conn, seg);
     442
    405443        switch (conn->cstate) {
    406444        case st_established:
     
    422460        }
    423461
    424         /* TODO Process segment text */
     462        /*
     463         * Process segment text
     464         */
     465        assert(seq_no_segment_ready(conn, seg));
     466
     467        /* Trim anything outside our receive window */
     468        tcp_conn_trim_seg_to_wnd(conn, seg);
     469
     470        /* Determine how many bytes to copy */
     471        text_size = tcp_segment_text_size(seg);
     472        xfer_size = min(text_size, conn->rcv_buf_size - conn->rcv_buf_used);
     473
     474        /* Copy data to receive buffer */
     475        tcp_segment_text_copy(seg, conn->rcv_buf, xfer_size);
     476
     477        /* Advance RCV.NXT */
     478        conn->rcv_nxt += xfer_size;
     479
     480        /* Update receive window. XXX Not an efficient strategy. */
     481        conn->rcv_wnd -= xfer_size;
     482
     483        /* XXX Signal user that some data arrived. */
     484
     485        /* Send ACK */
     486        if (xfer_size > 0)
     487                tcp_tqueue_ctrl_seg(conn, CTL_ACK);
     488
     489        /* Anything left in the segment? (text, FIN) */
     490        if (xfer_size < seg->len) {
     491                /*
     492                 * Some text or control remains. Insert remainder back
     493                 * into the incoming queue.
     494                 */
     495                tcp_conn_trim_seg_to_wnd(conn, seg);
     496                tcp_iqueue_insert_seg(&conn->incoming, seg);
     497
     498                return cp_done;
     499        }
     500
    425501        return cp_continue;
    426502}
     
    472548        if (tcp_conn_seg_proc_fin(conn, seg) == cp_done)
    473549                return;
     550
     551        tcp_segment_delete(seg);
    474552}
    475553
     
    498576}
    499577
     578void tcp_conn_trim_seg_to_wnd(tcp_conn_t *conn, tcp_segment_t *seg)
     579{
     580        uint32_t left, right;
     581
     582        seq_no_seg_trim_calc(conn, seg, &left, &right);
     583        tcp_segment_trim(seg, left, right);
     584}
     585
    500586void tcp_unexpected_segment(tcp_sockpair_t *sp, tcp_segment_t *seg)
    501587{
  • uspace/srv/net/tl/tcp/conn.h

    r4c55a64 r0093ab6  
    4343extern tcp_conn_t *tcp_conn_find(tcp_sockpair_t *);
    4444extern void tcp_conn_segment_arrived(tcp_conn_t *, tcp_segment_t *);
     45extern void tcp_conn_trim_seg_to_wnd(tcp_conn_t *, tcp_segment_t *);
    4546extern void tcp_unexpected_segment(tcp_sockpair_t *, tcp_segment_t *);
    4647extern void tcp_sockpair_flipped(tcp_sockpair_t *, tcp_sockpair_t *);
  • uspace/srv/net/tl/tcp/header.c

    r4c55a64 r0093ab6  
    6161
    6262        /* XXX This will only work as long as we don't have any header options */
    63         phdr->tcp_length = sizeof(tcp_header_t) + tcp_segment_data_len(seg);
     63        phdr->tcp_length = sizeof(tcp_header_t) + tcp_segment_text_size(seg);
    6464}
    6565
  • uspace/srv/net/tl/tcp/segment.c

    r4c55a64 r0093ab6  
    3535 */
    3636
     37#include <mem.h>
    3738#include <stdlib.h>
    3839#include "segment.h"
     
    7980}
    8081
    81 size_t tcp_segment_data_len(tcp_segment_t *seg)
     82/** Trim segment to the specified interval.
     83 *
     84 * Trim any text or control whose sequence number is outside of [lo, hi)
     85 * interval.
     86 */
     87void tcp_segment_trim(tcp_segment_t *seg, uint32_t left, uint32_t right)
     88{
     89        uint32_t t_size;
     90
     91        assert(left + right <= seg->len);
     92
     93        /* Special case, entire segment trimmed from left */
     94        if (left == seg->len) {
     95                seg->seq = seg->seq + seg->len;
     96                seg->len = 0;
     97                return;
     98        }
     99
     100        /* Special case, entire segment trimmed from right */
     101        if (right == seg->len) {
     102                seg->len = 0;
     103                return;
     104        }
     105
     106        /* General case */
     107
     108        t_size = tcp_segment_text_size(seg);
     109
     110        if (left > 0 && (seg->ctrl & CTL_SYN) != 0) {
     111                /* Trim SYN */
     112                seg->ctrl &= ~CTL_SYN;
     113                seg->seq++;
     114                seg->len--;
     115                left--;
     116        }
     117
     118        if (right > 0 && (seg->ctrl & CTL_FIN) != 0) {
     119                /* Trim FIN */
     120                seg->ctrl &= ~CTL_FIN;
     121                seg->len--;
     122                right--;
     123        }
     124
     125        if (left > 0 || right > 0) {
     126                /* Trim segment text */
     127                assert(left + right <= t_size);
     128
     129                seg->data += left;
     130                seg->len -= left + right;
     131        }
     132}
     133
     134/** Copy out text data from segment.
     135 *
     136 */
     137void tcp_segment_text_copy(tcp_segment_t *seg, void *buf, size_t size)
     138{
     139        assert(size <= tcp_segment_text_size(seg));
     140        memcpy(buf, seg->data, size);
     141}
     142
     143/** Return number of bytes in segment text. */
     144size_t tcp_segment_text_size(tcp_segment_t *seg)
    82145{
    83146        return seg->len - seq_no_control_len(seg->ctrl);
  • uspace/srv/net/tl/tcp/segment.h

    r4c55a64 r0093ab6  
    3636#define SEGMENT_H
    3737
     38#include <sys/types.h>
    3839#include "tcp_type.h"
    3940
     
    4243extern tcp_segment_t *tcp_segment_make_ctrl(tcp_control_t);
    4344extern tcp_segment_t *tcp_segment_make_rst(tcp_segment_t *);
    44 extern size_t tcp_segment_data_len(tcp_segment_t *);
     45extern void tcp_segment_trim(tcp_segment_t *, uint32_t, uint32_t);
     46extern void tcp_segment_text_copy(tcp_segment_t *, void *, size_t);
     47extern size_t tcp_segment_text_size(tcp_segment_t *);
    4548
    4649
  • uspace/srv/net/tl/tcp/seq_no.c

    r4c55a64 r0093ab6  
    7171 *
    7272 * ACK is duplicate if it refers to a sequence number that has
    73  * aleady been acked (SEG.ACK < SND.UNA).
     73 * aleady been acked (SEG.ACK <= SND.UNA).
    7474 */
    7575bool seq_no_ack_duplicate(tcp_conn_t *conn, uint32_t seg_ack)
     
    8181         * equivalent of SEG.ACK < SND.UNA. Thus we do it
    8282         * on a best-effort basis, based on the difference.
    83          * [-2^31, 0) means less-than, [0, 2^31) means greater-than.
     83         * [-2^31, 0) means less-than, 0 means equal, [0, 2^31)
     84         * means greater-than. Less-than or equal means duplicate.
    8485         */
    8586        diff = seg_ack - conn->snd_una;
    86         return (diff & (0x1 << 31)) != 0;
     87        return diff == 0 || (diff & (0x1 << 31)) != 0;
    8788}
    8889
     
    176177}
    177178
     179/** Calculate the amount of trim needed to fit segment in receive window. */
     180extern void seq_no_seg_trim_calc(tcp_conn_t *conn, tcp_segment_t *seg,
     181    uint32_t *left, uint32_t *right)
     182{
     183        assert(seq_no_segment_acceptable(conn, seg));
     184
     185        /*
     186         * If RCV.NXT is between SEG.SEQ and RCV.NXT+RCV.WND, then
     187         * left trim amount is positive
     188         */
     189        if (seq_no_lt_le(seg->seq, conn->rcv_nxt,
     190            conn->rcv_nxt + conn->rcv_wnd)) {
     191                *left = conn->rcv_nxt - seg->seq;
     192        } else {
     193                *left = 0;
     194        }
     195
     196        /*
     197         * If SEG.SEQ+SEG.LEN is between SEG.SEQ and RCV.NXT+RCV.WND,
     198         * then right trim is zero.
     199         */
     200        if (seq_no_lt_le(seg->seq - 1, seg->seq + seg->len,
     201            conn->rcv_nxt + conn->rcv_wnd)) {
     202                *right = 0;
     203        } else {
     204                *right = (seg->seq + seg->len) -
     205                    (conn->rcv_nxt + conn->rcv_wnd);
     206        }
     207}
     208
    178209/**
    179210 * @}
  • uspace/srv/net/tl/tcp/seq_no.h

    r4c55a64 r0093ab6  
    4646extern bool seq_no_segment_ready(tcp_conn_t *, tcp_segment_t *);
    4747extern bool seq_no_segment_acceptable(tcp_conn_t *, tcp_segment_t *);
     48extern void seq_no_seg_trim_calc(tcp_conn_t *, tcp_segment_t *, uint32_t *,
     49    uint32_t *);
    4850
    4951extern uint32_t seq_no_control_len(tcp_control_t);
  • uspace/srv/net/tl/tcp/tcp_type.h

    r4c55a64 r0093ab6  
    109109        tcp_iqueue_t incoming;
    110110
     111        /** Receive buffer */
     112        uint8_t *rcv_buf;
     113        /** Receive buffer size */
     114        size_t rcv_buf_size;
     115        size_t rcv_buf_used;
     116
    111117        /** Send unacknowledged */
    112118        uint32_t snd_una;
     
    153159        uint32_t up;
    154160
    155         /** Segment data */
     161        /** Segment data, may be moved when trimming segment */
    156162        void *data;
     163        /** Segment data, original pointer used to free data */
     164        void *dfptr;
    157165} tcp_segment_t;
    158166
Note: See TracChangeset for help on using the changeset viewer.