add keepalive
[cor.git] / net / cor / conn_trgt_sock.c
blobeb9566e43c0667517b0d676696dc9a9543b6ab2a
1 /**
2 * Connection oriented routing
3 * Copyright (C) 2007-2021 Michael Blizek
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA.
21 #include "cor.h"
24 static __u8 cor_flush_sock_managed_hdr(struct cor_conn *trgt_sock_lx,
25 __u8 *do_wake_sender)
27 __u32 hdr_rcvd = trgt_sock_lx->target.sock.rcvd;
28 if (hdr_rcvd < CONN_MNGD_HEADERLEN) {
29 __u32 len = CONN_MNGD_HEADERLEN - hdr_rcvd;
30 __u32 pulled;
31 __u16 hdr;
33 pulled = cor_databuf_trypull(trgt_sock_lx,
34 trgt_sock_lx->target.sock.rcv_hdr + hdr_rcvd,
35 len);
37 if (pulled > 0 && trgt_sock_lx->sourcetype == SOURCE_SOCK)
38 cor_update_src_sock_sndspeed(trgt_sock_lx, pulled);
40 trgt_sock_lx->target.sock.rcvd += pulled;
41 if (pulled > 0)
42 *do_wake_sender = 1;
44 if (pulled < len)
45 return RCV_BUF_STATE_INCOMPLETE;
47 BUG_ON(CONN_MNGD_HEADERLEN != 2);
49 hdr = cor_parse_u16(&(trgt_sock_lx->target.sock.rcv_hdr[0]));
51 trgt_sock_lx->target.sock.rcv_hdr_flags = hdr;
52 trgt_sock_lx->target.sock.rcv_data_len = 0;
54 if (likely((hdr & CONN_MNGD_HASDATA) != 0)) {
55 trgt_sock_lx->target.sock.rcv_data_len =
56 (hdr & CONN_MNGD_DATALEN) + 1;
57 } else {
58 if (unlikely((hdr & CONN_MNGD_KEEPALIVE_REQ) != 0))
59 trgt_sock_lx->target.sock.rcv_data_len += 4;
61 if (unlikely((hdr & CONN_MNGD_KEEPALIVE_RESP) != 0))
62 trgt_sock_lx->target.sock.rcv_data_len += 4;
66 return RCV_BUF_STATE_OK;
69 static __u8 cor_flush_sock_managed_data(struct cor_conn *trgt_sock_lx,
70 __u8 *do_wake_sender)
72 __u32 data_rcvd = trgt_sock_lx->target.sock.rcvd - CONN_MNGD_HEADERLEN;
73 if (data_rcvd < trgt_sock_lx->target.sock.rcv_data_len) {
74 __u32 len = trgt_sock_lx->target.sock.rcv_data_len - data_rcvd;
75 __u32 pulled;
77 BUG_ON(trgt_sock_lx->target.sock.rcv_buf == 0);
79 pulled = cor_databuf_trypull(trgt_sock_lx,
80 trgt_sock_lx->target.sock.rcv_buf + data_rcvd,
81 len);
83 if (pulled > 0 && trgt_sock_lx->sourcetype == SOURCE_SOCK)
84 cor_update_src_sock_sndspeed(trgt_sock_lx, pulled);
86 trgt_sock_lx->target.sock.rcvd += pulled;
87 if (pulled > 0)
88 *do_wake_sender = 1;
90 if (pulled < len)
91 return RCV_BUF_STATE_INCOMPLETE;
94 return RCV_BUF_STATE_OK;
97 static __u8 cor_flush_sock_managed_chksum(struct cor_conn *trgt_sock_lx,
98 __u8 *do_wake_sender)
100 __u32 checksum_rcvd = trgt_sock_lx->target.sock.rcvd -
101 CONN_MNGD_HEADERLEN -
102 trgt_sock_lx->target.sock.rcv_data_len;
103 if (checksum_rcvd < CONN_MNGD_CHECKSUMLEN) {
104 __u32 len = CONN_MNGD_CHECKSUMLEN - checksum_rcvd;
105 __u32 pulled;
106 char checksum_calc[CONN_MNGD_CHECKSUMLEN];
108 pulled = cor_databuf_trypull(trgt_sock_lx,
109 trgt_sock_lx->target.sock.rcv_chksum +
110 checksum_rcvd, len);
112 if (pulled > 0 && trgt_sock_lx->sourcetype == SOURCE_SOCK)
113 cor_update_src_sock_sndspeed(trgt_sock_lx, pulled);
115 trgt_sock_lx->target.sock.rcvd += pulled;
116 if (pulled > 0)
117 *do_wake_sender = 1;
119 if (pulled < len)
120 return RCV_BUF_STATE_INCOMPLETE;
122 cor_mngdsocket_chksum(trgt_sock_lx->target.sock.rcv_hdr,
123 CONN_MNGD_HEADERLEN,
124 trgt_sock_lx->target.sock.rcv_buf,
125 trgt_sock_lx->target.sock.rcv_data_len,
126 checksum_calc, CONN_MNGD_CHECKSUMLEN);
128 if (unlikely(memcmp(trgt_sock_lx->target.sock.rcv_chksum,
129 checksum_calc, CONN_MNGD_CHECKSUMLEN) != 0)) {
130 #ifdef COR_DEBUG
131 __u16 hdr = cor_parse_u16(
132 trgt_sock_lx->target.sock.rcv_hdr);
133 __u32 chk_calc = cor_parse_u32(checksum_calc);
134 __u32 chk = cor_parse_u32(
135 trgt_sock_lx->target.sock.rcv_chksum);
136 printk(KERN_WARNING "cor: user socket chksum mismatch hdr %u rcvlen %u chksum_calc %x chksum_rcvd %x\n",
137 hdr,
138 trgt_sock_lx->target.sock.rcv_data_len,
139 chk_calc, chk);
140 #endif
141 return RCV_BUF_STATE_RESET;
145 return RCV_BUF_STATE_OK;
149 void cor_flush_sock_managed(struct cor_conn *trgt_sock_lx, int from_recvmsg,
150 __u8 *do_wake_sender)
152 struct cor_sock *cs = trgt_sock_lx->target.sock.cs;
153 __u8 rc;
155 BUG_ON(cs == 0);
157 if (trgt_sock_lx->target.sock.rcv_buf_state != RCV_BUF_STATE_INCOMPLETE)
158 return;
160 rc = cor_flush_sock_managed_hdr(trgt_sock_lx, do_wake_sender);
161 if (rc != RCV_BUF_STATE_OK)
162 goto out;
164 rc = cor_flush_sock_managed_data(trgt_sock_lx, do_wake_sender);
165 if (rc != RCV_BUF_STATE_OK)
166 goto out;
168 rc = cor_flush_sock_managed_chksum(trgt_sock_lx, do_wake_sender);
169 out:
170 BUG_ON(trgt_sock_lx->target.sock.rcvd >
171 CONN_MNGD_HEADERLEN +
172 trgt_sock_lx->target.sock.rcv_data_len +
173 CONN_MNGD_CHECKSUMLEN);
175 cor_databuf_ackread(trgt_sock_lx);
176 cor_bufsize_read_to_sock(trgt_sock_lx);
178 trgt_sock_lx->target.sock.rcv_buf_state = rc;
180 if (from_recvmsg) {
181 if (rc == RCV_BUF_STATE_INCOMPLETE) {
182 atomic_set(&(cs->ready_to_read), 0);
184 } else {
185 /* This does not work because on the next call
186 * rcv_buf_state == RCV_BUF_STATE_OK and we do not get this far
188 /*if (trgt_sock_lx->is_highlatency != 0 &&
189 trgt_sock_lx->flush == 0 &&
190 trgt_sock_lx->data_buf.read_remaining < 4096 &&
191 trgt_sock_lx->sourcetype == SOURCE_SOCK &&
192 cor_sock_sndbufavailable(trgt_sock_lx) != 0)
193 return;
195 if (trgt_sock_lx->is_highlatency != 0 &&
196 trgt_sock_lx->flush == 0 &&
197 trgt_sock_lx->data_buf.read_remaining < 4096 &&
198 trgt_sock_lx->sourcetype == SOURCE_IN &&
199 cor_srcin_buflimit_reached(trgt_sock_lx) == 0)
200 return;*/
202 if (likely(rc == RCV_BUF_STATE_OK &&
203 (trgt_sock_lx->target.sock.rcv_hdr_flags &
204 CONN_MNGD_HASDATA) != 0 &&
205 trgt_sock_lx->target.sock.rcv_data_len > 0)) {
206 cor_sk_data_ready(cs);
207 } else {
208 cor_mngdsocket_readfromconn_fromatomic(cs);
213 void cor_flush_sock(struct cor_conn *trgt_sock_lx)
215 struct cor_sock *cs = trgt_sock_lx->target.sock.cs;
217 if (unlikely(cs == 0))
218 return;
220 if (unlikely(trgt_sock_lx->data_buf.read_remaining == 0))
221 return;
223 if (trgt_sock_lx->target.sock.waiting_for_userspace == 0) {
224 trgt_sock_lx->target.sock.waiting_for_userspace = 1;
225 trgt_sock_lx->target.sock.waiting_for_userspace_since = jiffies;
228 if (trgt_sock_lx->target.sock.socktype == SOCKTYPE_RAW) {
229 cor_sk_data_ready(cs);
230 } else if (trgt_sock_lx->target.sock.socktype == SOCKTYPE_MANAGED) {
231 __u8 do_wake_sender = 0;
232 cor_flush_sock_managed(trgt_sock_lx, 0, &do_wake_sender);
233 } else {
234 BUG();
238 MODULE_LICENSE("GPL");