/** * @skb_list can be invalid after the function call, don't try to use it. */ static void ss_do_send(struct sock *sk, SsSkbList *skb_list) { struct tcp_sock *tp = tcp_sk(sk); struct sk_buff *skb; int size, mss = tcp_send_mss(sk, &size, MSG_DONTWAIT); SS_DBG("%s: cpu=%d sk=%p queue_empty=%d send_head=%p" " sk_state=%d mss=%d size=%d\n", __func__, smp_processor_id(), sk, tcp_write_queue_empty(sk), tcp_send_head(sk), sk->sk_state, mss, size); if (unlikely(!ss_sock_active(sk))) return; ss_sock_cpu_check(sk); while ((skb = ss_skb_dequeue(skb_list))) { skb->ip_summed = CHECKSUM_PARTIAL; skb_shinfo(skb)->gso_segs = 0; /* * TODO Mark all data with PUSH to force receiver to consume * the data. Currently we do this for debugging purposes. * We need to do this only for complete messages/skbs. * Actually tcp_push() already does it for the last skb. * MSG_MORE should be used, probably by connection layer. */ tcp_mark_push(tp, skb); SS_DBG("%s: entail skb=%p data_len=%u len=%u\n", __func__, skb, skb->data_len, skb->len); ss_skb_entail(sk, skb); tp->write_seq += skb->len; TCP_SKB_CB(skb)->end_seq += skb->len; } SS_DBG("%s: sk=%p send_head=%p sk_state=%d\n", __func__, sk, tcp_send_head(sk), sk->sk_state); tcp_push(sk, MSG_DONTWAIT, mss, TCP_NAGLE_OFF|TCP_NAGLE_PUSH, size); }
/* * BST_TMR_DELAY_SOCK_SYNC timeout. * If sock is ready, get sock sync properties and post them to daemon */ static void delay_sock_bastet_timeout(struct sock *sk) { int err; struct bst_set_sock_sync_prop sock_p; struct bastet_sock *bsk = sk->bastet; /* Accurating time */ if (time_after(bsk->bastet_timeout, jiffies)) { sk_reset_timer(sk, &bsk->bastet_timer, bsk->bastet_timeout); return; } /* We must reset timer event, bastet_delay_sock_sync_notify depends on it * this code must be put after accurating time */ bsk->bastet_timer_event = BST_TMR_EVT_INVALID; /* In repair mode or userspace needs repair, do not sync sock */ if (unlikely(tcp_sk(sk)->repair || bsk->need_repair)) { BASTET_LOGE("sk: %p in repair mode", sk); return; } if (TCP_ESTABLISHED != sk->sk_state) { BASTET_LOGE("sk: %p sk_state is not TCP_ESTABLISHED", sk); return; } if (BST_SOCK_VALID != bsk->bastet_sock_state) { BASTET_LOGE("sk: %p state: %d not expected", sk, bsk->bastet_sock_state); return; } /* Sock owner has used since last setup */ if (time_after(bsk->last_sock_active_time_point + bsk->delay_sync_time_section, jiffies)) { setup_sock_sync_delay_timer(sk); return; } /* Sock owner has some data unacked, * Coming ack would trigger delay timer again */ if (!tcp_write_queue_empty(sk)) { BASTET_LOGI("sk: %p has sent data not acked", sk); post_indicate_packet(BST_IND_TRIGGER_THAW, &bsk->pid, sizeof(pid_t)); return; } /* Sock owner has some data to recv, do not sync. * If sock owner has none recv action, * delay timer should be stopped. */ if (!skb_queue_empty(&sk->sk_receive_queue)) { BASTET_LOGI("sk: %p has received data in queue", sk); bsk->last_sock_active_time_point = jiffies; setup_sock_sync_delay_timer(sk); post_indicate_packet(BST_IND_TRIGGER_THAW, &bsk->pid, sizeof(pid_t)); return; } memset(&sock_p, 0, sizeof(struct bst_set_sock_sync_prop)); bastet_get_comm_prop(sk, &sock_p.guide); bastet_get_sock_prop(sk, &sock_p.sync_prop); err = post_indicate_packet(BST_IND_SOCK_SYNC_PROP, &sock_p, sizeof(sock_p)); if (!err) { /* if post success */ bsk->bastet_sock_state = BST_SOCK_INVALID; } }