2 * Copyright (c) 2011 Jiri Svoboda
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
34 * @file TCP transmission queue
39 #include <fibril_synch.h>
40 #include <byteorder.h>
55 #define RETRANSMIT_TIMEOUT (2*1000*1000)
57 static void retransmit_timeout_func(void *arg
);
58 static void tcp_tqueue_timer_set(tcp_conn_t
*conn
);
59 static void tcp_tqueue_timer_clear(tcp_conn_t
*conn
);
61 int tcp_tqueue_init(tcp_tqueue_t
*tqueue
, tcp_conn_t
*conn
)
64 tqueue
->timer
= fibril_timer_create();
65 if (tqueue
->timer
== NULL
)
68 list_initialize(&tqueue
->list
);
73 void tcp_tqueue_clear(tcp_tqueue_t
*tqueue
)
75 tcp_tqueue_timer_clear(tqueue
->conn
);
78 void tcp_tqueue_fini(tcp_tqueue_t
*tqueue
)
80 if (tqueue
->timer
!= NULL
) {
81 fibril_timer_destroy(tqueue
->timer
);
86 void tcp_tqueue_ctrl_seg(tcp_conn_t
*conn
, tcp_control_t ctrl
)
90 log_msg(LOG_DEFAULT
, LVL_DEBUG
, "tcp_tqueue_ctrl_seg(%p, %u)", conn
, ctrl
);
92 seg
= tcp_segment_make_ctrl(ctrl
);
93 tcp_tqueue_seg(conn
, seg
);
96 void tcp_tqueue_seg(tcp_conn_t
*conn
, tcp_segment_t
*seg
)
98 tcp_segment_t
*rt_seg
;
99 tcp_tqueue_entry_t
*tqe
;
101 log_msg(LOG_DEFAULT
, LVL_DEBUG
, "%s: tcp_tqueue_seg(%p, %p)", conn
->name
, conn
,
105 * Add segment to retransmission queue
109 rt_seg
= tcp_segment_dup(seg
);
110 if (rt_seg
== NULL
) {
111 log_msg(LOG_DEFAULT
, LVL_ERROR
, "Memory allocation failed.");
112 /* XXX Handle properly */
116 tqe
= calloc(1, sizeof(tcp_tqueue_entry_t
));
118 log_msg(LOG_DEFAULT
, LVL_ERROR
, "Memory allocation failed.");
119 /* XXX Handle properly */
125 rt_seg
->seq
= conn
->snd_nxt
;
127 list_append(&tqe
->link
, &conn
->retransmit
.list
);
129 /* Set retransmission timer */
130 tcp_tqueue_timer_set(conn
);
133 tcp_prepare_transmit_segment(conn
, seg
);
136 void tcp_prepare_transmit_segment(tcp_conn_t
*conn
, tcp_segment_t
*seg
)
139 * Always send ACK once we have received SYN, except for RST segments.
140 * (Spec says we should always send ACK once connection has been
143 if (tcp_conn_got_syn(conn
) && (seg
->ctrl
& CTL_RST
) == 0)
144 seg
->ctrl
|= CTL_ACK
;
146 seg
->seq
= conn
->snd_nxt
;
147 conn
->snd_nxt
+= seg
->len
;
149 tcp_conn_transmit_segment(conn
, seg
);
152 /** Transmit data from the send buffer.
154 * @param conn Connection
156 void tcp_tqueue_new_data(tcp_conn_t
*conn
)
160 size_t snd_buf_seqlen
;
167 log_msg(LOG_DEFAULT
, LVL_DEBUG
, "%s: tcp_tqueue_new_data()", conn
->name
);
169 /* Number of free sequence numbers in send window */
170 avail_wnd
= (conn
->snd_una
+ conn
->snd_wnd
) - conn
->snd_nxt
;
171 snd_buf_seqlen
= conn
->snd_buf_used
+ (conn
->snd_buf_fin
? 1 : 0);
173 xfer_seqlen
= min(snd_buf_seqlen
, avail_wnd
);
174 log_msg(LOG_DEFAULT
, LVL_DEBUG
, "%s: snd_buf_seqlen = %zu, SND.WND = %zu, "
175 "xfer_seqlen = %zu", conn
->name
, snd_buf_seqlen
, conn
->snd_wnd
,
178 if (xfer_seqlen
== 0)
181 /* XXX Do not always send immediately */
183 send_fin
= conn
->snd_buf_fin
&& xfer_seqlen
== snd_buf_seqlen
;
184 data_size
= xfer_seqlen
- (send_fin
? 1 : 0);
187 log_msg(LOG_DEFAULT
, LVL_DEBUG
, "%s: Sending out FIN.", conn
->name
);
188 /* We are sending out FIN */
194 seg
= tcp_segment_make_data(ctrl
, conn
->snd_buf
, data_size
);
196 log_msg(LOG_DEFAULT
, LVL_ERROR
, "Memory allocation failure.");
200 /* Remove data from send buffer */
201 memmove(conn
->snd_buf
, conn
->snd_buf
+ data_size
,
202 conn
->snd_buf_used
- data_size
);
203 conn
->snd_buf_used
-= data_size
;
206 conn
->snd_buf_fin
= false;
208 fibril_condvar_broadcast(&conn
->snd_buf_cv
);
211 tcp_conn_fin_sent(conn
);
213 tcp_tqueue_seg(conn
, seg
);
216 /** Remove ACKed segments from retransmission queue and possibly transmit
219 * This should be called when SND.UNA is updated due to incoming ACK.
221 void tcp_tqueue_ack_received(tcp_conn_t
*conn
)
225 log_msg(LOG_DEFAULT
, LVL_DEBUG
, "%s: tcp_tqueue_ack_received(%p)", conn
->name
,
228 cur
= conn
->retransmit
.list
.head
.next
;
230 while (cur
!= &conn
->retransmit
.list
.head
) {
233 tcp_tqueue_entry_t
*tqe
= list_get_instance(cur
,
234 tcp_tqueue_entry_t
, link
);
236 if (seq_no_segment_acked(conn
, tqe
->seg
, conn
->snd_una
)) {
237 /* Remove acknowledged segment */
240 if ((tqe
->seg
->ctrl
& CTL_FIN
) != 0) {
241 log_msg(LOG_DEFAULT
, LVL_DEBUG
, "Fin has been acked");
242 log_msg(LOG_DEFAULT
, LVL_DEBUG
, "SND.UNA=%" PRIu32
243 " SEG.SEQ=%" PRIu32
" SEG.LEN=%" PRIu32
,
244 conn
->snd_una
, tqe
->seg
->seq
, tqe
->seg
->len
);
245 /* Our FIN has been acked */
246 conn
->fin_is_acked
= true;
249 tcp_segment_delete(tqe
->seg
);
252 /* Reset retransmission timer */
253 tcp_tqueue_timer_set(conn
);
259 /* Clear retransmission timer if the queue is empty. */
260 if (list_empty(&conn
->retransmit
.list
))
261 tcp_tqueue_timer_clear(conn
);
263 /* Possibly transmit more data */
264 tcp_tqueue_new_data(conn
);
267 void tcp_conn_transmit_segment(tcp_conn_t
*conn
, tcp_segment_t
*seg
)
269 log_msg(LOG_DEFAULT
, LVL_DEBUG
, "%s: tcp_conn_transmit_segment(%p, %p)",
270 conn
->name
, conn
, seg
);
272 seg
->wnd
= conn
->rcv_wnd
;
274 if ((seg
->ctrl
& CTL_ACK
) != 0)
275 seg
->ack
= conn
->rcv_nxt
;
279 tcp_transmit_segment(&conn
->ident
, seg
);
282 void tcp_transmit_segment(tcp_sockpair_t
*sp
, tcp_segment_t
*seg
)
284 log_msg(LOG_DEFAULT
, LVL_DEBUG
, "tcp_transmit_segment(f:(%x,%u),l:(%x,%u), %p)",
285 sp
->foreign
.addr
.ipv4
, sp
->foreign
.port
,
286 sp
->local
.addr
.ipv4
, sp
->local
.port
, seg
);
288 log_msg(LOG_DEFAULT
, LVL_DEBUG
, "SEG.SEQ=%" PRIu32
", SEG.WND=%" PRIu32
,
291 tcp_segment_dump(seg
);
293 tcp_pdu_prepare(conn, seg, &data, &len);
294 tcp_pdu_transmit(data, len);
296 // tcp_rqueue_bounce_seg(sp, seg);
297 // tcp_ncsim_bounce_seg(sp, seg);
301 if (tcp_pdu_encode(sp
, seg
, &pdu
) != EOK
) {
302 log_msg(LOG_DEFAULT
, LVL_WARN
, "Not enough memory. Segment dropped.");
306 tcp_transmit_pdu(pdu
);
310 static void retransmit_timeout_func(void *arg
)
312 tcp_conn_t
*conn
= (tcp_conn_t
*) arg
;
313 tcp_tqueue_entry_t
*tqe
;
314 tcp_segment_t
*rt_seg
;
317 log_msg(LOG_DEFAULT
, LVL_DEBUG
, "### %s: retransmit_timeout_func(%p)", conn
->name
, conn
);
319 fibril_mutex_lock(&conn
->lock
);
321 if (conn
->cstate
== st_closed
) {
322 log_msg(LOG_DEFAULT
, LVL_DEBUG
, "Connection already closed.");
323 fibril_mutex_unlock(&conn
->lock
);
324 tcp_conn_delref(conn
);
328 link
= list_first(&conn
->retransmit
.list
);
330 log_msg(LOG_DEFAULT
, LVL_DEBUG
, "Nothing to retransmit");
331 fibril_mutex_unlock(&conn
->lock
);
332 tcp_conn_delref(conn
);
336 tqe
= list_get_instance(link
, tcp_tqueue_entry_t
, link
);
338 rt_seg
= tcp_segment_dup(tqe
->seg
);
339 if (rt_seg
== NULL
) {
340 log_msg(LOG_DEFAULT
, LVL_ERROR
, "Memory allocation failed.");
341 fibril_mutex_unlock(&conn
->lock
);
342 tcp_conn_delref(conn
);
343 /* XXX Handle properly */
347 log_msg(LOG_DEFAULT
, LVL_DEBUG
, "### %s: retransmitting segment", conn
->name
);
348 tcp_conn_transmit_segment(tqe
->conn
, rt_seg
);
350 /* Reset retransmission timer */
351 tcp_tqueue_timer_set(tqe
->conn
);
353 fibril_mutex_unlock(&conn
->lock
);
354 tcp_conn_delref(conn
);
357 /** Set or re-set retransmission timer */
358 static void tcp_tqueue_timer_set(tcp_conn_t
*conn
)
360 log_msg(LOG_DEFAULT
, LVL_DEBUG
, "### %s: tcp_tqueue_timer_set()", conn
->name
);
362 /* Clear first to make sure we update refcnt correctly */
363 tcp_tqueue_timer_clear(conn
);
365 tcp_conn_addref(conn
);
366 fibril_timer_set(conn
->retransmit
.timer
, RETRANSMIT_TIMEOUT
,
367 retransmit_timeout_func
, (void *) conn
);
370 /** Clear retransmission timer */
371 static void tcp_tqueue_timer_clear(tcp_conn_t
*conn
)
373 log_msg(LOG_DEFAULT
, LVL_DEBUG
, "### %s: tcp_tqueue_timer_clear()", conn
->name
);
375 if (fibril_timer_clear(conn
->retransmit
.timer
) == fts_active
)
376 tcp_conn_delref(conn
);