source: mainline/uspace/srv/net/tl/tcp/tqueue.c@ 4f3f6285

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 4f3f6285 was 4f3f6285, checked in by Jiri Svoboda <jiri@…>, 14 years ago

Missing fields due to calling wrong function.

  • Property mode set to 100644
File size: 8.0 KB
RevLine 
[c5808b41]1/*
2 * Copyright (c) 2011 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup tcp
30 * @{
31 */
32
33/**
[032bbe7]34 * @file TCP transmission queue
[c5808b41]35 */
36
[6df418c4]37#include <adt/list.h>
[7cf7ded]38#include <errno.h>
39#include <fibril_synch.h>
[c5808b41]40#include <byteorder.h>
41#include <io/log.h>
[32105348]42#include <macros.h>
43#include <mem.h>
[6df418c4]44#include <stdlib.h>
[32105348]45#include "conn.h"
[c5808b41]46#include "header.h"
[8218b6b]47#include "ncsim.h"
[c5808b41]48#include "rqueue.h"
49#include "segment.h"
[6df418c4]50#include "seq_no.h"
[c5808b41]51#include "tqueue.h"
52#include "tcp_type.h"
53
[7cf7ded]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)
[6df418c4]61{
62 tqueue->conn = conn;
[7cf7ded]63 tqueue->timer = fibril_timer_create();
64 if (tqueue->timer == NULL)
65 return ENOMEM;
66
[6df418c4]67 list_initialize(&tqueue->list);
[7cf7ded]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 }
[6df418c4]78}
79
[c5808b41]80void tcp_tqueue_ctrl_seg(tcp_conn_t *conn, tcp_control_t ctrl)
81{
82 tcp_segment_t *seg;
83
84 log_msg(LVL_DEBUG, "tcp_tqueue_ctrl_seg(%p, %u)", conn, ctrl);
85
86 seg = tcp_segment_make_ctrl(ctrl);
87 tcp_tqueue_seg(conn, seg);
88}
89
90void tcp_tqueue_seg(tcp_conn_t *conn, tcp_segment_t *seg)
91{
[6df418c4]92 tcp_segment_t *rt_seg;
93 tcp_tqueue_entry_t *tqe;
94
[c5808b41]95 log_msg(LVL_DEBUG, "tcp_tqueue_seg(%p, %p)", conn, seg);
[6df418c4]96
97 /*
98 * Add segment to retransmission queue
99 */
100
101 if (seg->len > 0) {
102 rt_seg = tcp_segment_dup(seg);
103 if (rt_seg == NULL) {
104 log_msg(LVL_ERROR, "Memory allocation failed.");
105 /* XXX Handle properly */
106 return;
107 }
108
109 tqe = calloc(1, sizeof(tcp_tqueue_entry_t));
110 if (tqe == NULL) {
111 log_msg(LVL_ERROR, "Memory allocation failed.");
112 /* XXX Handle properly */
113 return;
114 }
115
[7cf7ded]116 tqe->conn = conn;
[6df418c4]117 tqe->seg = rt_seg;
118 list_append(&tqe->link, &conn->retransmit.list);
[7cf7ded]119
120 /* Set retransmission timer */
121 tcp_tqueue_timer_set(conn);
[6df418c4]122 }
[c5808b41]123
[7cf7ded]124 tcp_prepare_transmit_segment(conn, seg);
125}
126
127void tcp_prepare_transmit_segment(tcp_conn_t *conn, tcp_segment_t *seg)
128{
[32105348]129 /*
130 * Always send ACK once we have received SYN, except for RST segments.
131 * (Spec says we should always send ACK once connection has been
132 * established.)
133 */
134 if (tcp_conn_got_syn(conn) && (seg->ctrl & CTL_RST) == 0)
135 seg->ctrl |= CTL_ACK;
136
137 seg->seq = conn->snd_nxt;
[c5808b41]138 conn->snd_nxt += seg->len;
[32105348]139
[4f3f6285]140 tcp_conn_transmit_segment(conn, seg);
[c5808b41]141}
142
[32105348]143/** Transmit data from the send buffer.
144 *
145 * @param conn Connection
146 */
147void tcp_tqueue_new_data(tcp_conn_t *conn)
148{
[d9ce049]149 size_t avail_wnd;
[8c7a054]150 size_t xfer_seqlen;
151 size_t snd_buf_seqlen;
[32105348]152 size_t data_size;
[8c7a054]153 tcp_control_t ctrl;
154
[32105348]155 tcp_segment_t *seg;
156
157 log_msg(LVL_DEBUG, "tcp_tqueue_new_data()");
158
[d9ce049]159 /* Number of free sequence numbers in send window */
160 avail_wnd = (conn->snd_una + conn->snd_wnd) - conn->snd_nxt;
[8c7a054]161 snd_buf_seqlen = conn->snd_buf_used + (conn->snd_buf_fin ? 1 : 0);
[d9ce049]162
[8c7a054]163 xfer_seqlen = min(snd_buf_seqlen, avail_wnd);
164 log_msg(LVL_DEBUG, "snd_buf_seqlen = %zu, SND.WND = %zu, "
165 "xfer_seqlen = %zu", snd_buf_seqlen, conn->snd_wnd,
166 xfer_seqlen);
[32105348]167
[8c7a054]168 if (xfer_seqlen == 0)
[32105348]169 return;
170
171 /* XXX Do not always send immediately */
172
[8c7a054]173 data_size = xfer_seqlen - (conn->snd_buf_fin ? 1 : 0);
174 if (conn->snd_buf_fin && data_size + 1 == xfer_seqlen) {
175 /* We are sending out FIN */
176 ctrl = CTL_FIN;
[f343a16]177 tcp_conn_fin_sent(conn);
[8c7a054]178 } else {
179 ctrl = 0;
180 }
181
182 seg = tcp_segment_make_data(ctrl, conn->snd_buf, data_size);
[32105348]183 if (seg == NULL) {
184 log_msg(LVL_ERROR, "Memory allocation failure.");
185 return;
186 }
187
188 /* Remove data from send buffer */
189 memmove(conn->snd_buf, conn->snd_buf + data_size,
190 conn->snd_buf_used - data_size);
191 conn->snd_buf_used -= data_size;
[8c7a054]192 conn->snd_buf_fin = false;
[32105348]193
194 tcp_tqueue_seg(conn, seg);
195}
196
[d9ce049]197/** Remove ACKed segments from retransmission queue and possibly transmit
198 * more data.
[4c55a64]199 *
200 * This should be called when SND.UNA is updated due to incoming ACK.
201 */
[d9ce049]202void tcp_tqueue_ack_received(tcp_conn_t *conn)
[4c55a64]203{
[6df418c4]204 link_t *cur, *next;
205
206 log_msg(LVL_DEBUG, "tcp_tqueue_ack_received(%p)", conn);
207
208 cur = conn->retransmit.list.head.next;
209
210 while (cur != &conn->retransmit.list.head) {
211 next = cur->next;
212
213 tcp_tqueue_entry_t *tqe = list_get_instance(cur,
214 tcp_tqueue_entry_t, link);
215
216 if (seq_no_segment_acked(conn, tqe->seg, conn->snd_una)) {
217 /* Remove acknowledged segment */
218 list_remove(cur);
219
220 if ((tqe->seg->ctrl & CTL_FIN) != 0) {
221 /* Our FIN has been acked */
222 conn->fin_is_acked = true;
223 }
224
225 tcp_segment_delete(tqe->seg);
226 free(tqe);
[7cf7ded]227
228 /* Reset retransmission timer */
229 tcp_tqueue_timer_set(conn);
[6df418c4]230 }
231
232 cur = next;
233 }
[d9ce049]234
[7cf7ded]235 /* Clear retransmission timer if the queue is empty. */
236 if (list_empty(&conn->retransmit.list))
237 tcp_tqueue_timer_clear(conn);
238
[6df418c4]239 /* Possibly transmit more data */
[d9ce049]240 tcp_tqueue_new_data(conn);
[4c55a64]241}
242
[7cf7ded]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
[c5808b41]257void tcp_transmit_segment(tcp_sockpair_t *sp, tcp_segment_t *seg)
258{
259 log_msg(LVL_DEBUG, "tcp_transmit_segment(%p, %p)", sp, seg);
[7cf7ded]260
261 log_msg(LVL_DEBUG, "SEG.SEQ=%" PRIu32 ", SEG.WND=%" PRIu32,
262 seg->seq, seg->wnd);
[c5808b41]263/*
264 tcp_pdu_prepare(conn, seg, &data, &len);
265 tcp_pdu_transmit(data, len);
266*/
[7cf7ded]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);
[c5808b41]317}
318
319/**
320 * @}
321 */
Note: See TracBrowser for help on using the repository browser.