/src/kamailio/src/core/tcp_conn.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2001-2003 FhG Fokus |
3 | | * |
4 | | * This file is part of Kamailio, a free SIP server. |
5 | | * |
6 | | * Kamailio is free software; you can redistribute it and/or modify |
7 | | * it under the terms of the GNU General Public License as published by |
8 | | * the Free Software Foundation; either version 2 of the License, or |
9 | | * (at your option) any later version |
10 | | * |
11 | | * Kamailio is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License |
17 | | * along with this program; if not, write to the Free Software |
18 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 | | * |
20 | | */ |
21 | | |
22 | | #ifndef _tcp_conn_h |
23 | | #define _tcp_conn_h |
24 | | |
25 | | #include <sys/time.h> |
26 | | |
27 | | #include "tcp_init.h" |
28 | | #include "tcp_options.h" |
29 | | |
30 | | #include "ip_addr.h" |
31 | | #include "locking.h" |
32 | | #include "atomic_ops.h" |
33 | | #include "timer_ticks.h" |
34 | | #include "timer.h" |
35 | | |
36 | | /* maximum number of port aliases x search wildcard possibilities */ |
37 | | #define TCP_CON_MAX_ALIASES (4 * 3) |
38 | | |
39 | | #define TCP_CHILD_TIMEOUT \ |
40 | | 5 /* after 5 seconds, the child "returns" |
41 | | * the connection to the tcp maing process */ |
42 | 0 | #define TCP_MAIN_SELECT_TIMEOUT 5 /* how often "tcp main" checks for timeout*/ |
43 | 0 | #define TCP_CHILD_SELECT_TIMEOUT 2 /* the same as above but for children */ |
44 | | |
45 | | #define TCPCONN_MATCH_DEFAULT 0 |
46 | 0 | #define TCPCONN_MATCH_STRICT 1 |
47 | | |
48 | | /* tcp connection flags */ |
49 | 0 | #define F_CONN_READ_W 2 /* watched for READ ev. in main */ |
50 | 0 | #define F_CONN_WRITE_W 4 /* watched for WRITE (main) */ |
51 | 0 | #define F_CONN_READER 8 /* handled by a tcp reader */ |
52 | 0 | #define F_CONN_HASHED 16 /* in tcp_main hash */ |
53 | 0 | #define F_CONN_FD_CLOSED 32 /* fd was already closed */ |
54 | 0 | #define F_CONN_PENDING 64 /* pending connect (fd not known yet in main) */ |
55 | 0 | #define F_CONN_MAIN_TIMER 128 /* timer active in the tcp_main process */ |
56 | 0 | #define F_CONN_EOF_SEEN 256 /* FIN or RST have been received */ |
57 | 0 | #define F_CONN_FORCE_EOF 512 /* act as if an EOF was received */ |
58 | 0 | #define F_CONN_OOB_DATA 1024 /* out of band data on the connection */ |
59 | 0 | #define F_CONN_WR_ERROR 2048 /* write error on the fd */ |
60 | 0 | #define F_CONN_WANTS_RD 4096 /* conn. should be watched for READ */ |
61 | 0 | #define F_CONN_WANTS_WR 8192 /* conn. should be watched for WRITE */ |
62 | 0 | #define F_CONN_PASSIVE 16384 /* conn. created via accept() and not connect()*/ |
63 | | #define F_CONN_CLOSE_EV 32768 /* explicitely call tcpops ev route when closed */ |
64 | 0 | #define F_CONN_NOSEND 65536 /* do not send data on this connection */ |
65 | | |
66 | | #ifndef NO_READ_HTTP11 |
67 | | #define READ_HTTP11 |
68 | | #endif |
69 | | |
70 | | #ifndef NO_READ_MSRP |
71 | | #define READ_MSRP |
72 | | #endif |
73 | | |
74 | | #ifndef NO_READ_WS |
75 | | #define READ_WS |
76 | | #endif |
77 | | |
78 | | typedef enum tcp_req_errors |
79 | | { |
80 | | TCP_REQ_INIT, |
81 | | TCP_REQ_OK, |
82 | | TCP_READ_ERROR, |
83 | | TCP_REQ_OVERRUN, |
84 | | TCP_REQ_BAD_LEN |
85 | | } tcp_req_errors_t; |
86 | | typedef enum tcp_req_states |
87 | | { |
88 | | H_SKIP_EMPTY, |
89 | | H_SKIP_EMPTY_CR_FOUND, |
90 | | H_SKIP_EMPTY_CRLF_FOUND, |
91 | | H_SKIP_EMPTY_CRLFCR_FOUND, |
92 | | H_SKIP, |
93 | | H_LF, |
94 | | H_LFCR, |
95 | | H_BODY, |
96 | | H_STARTWS, |
97 | | H_CONT_LEN1, |
98 | | H_CONT_LEN2, |
99 | | H_CONT_LEN3, |
100 | | H_CONT_LEN4, |
101 | | H_CONT_LEN5, |
102 | | H_CONT_LEN6, |
103 | | H_CONT_LEN7, |
104 | | H_CONT_LEN8, |
105 | | H_CONT_LEN9, |
106 | | H_CONT_LEN10, |
107 | | H_CONT_LEN11, |
108 | | H_CONT_LEN12, |
109 | | H_CONT_LEN13, |
110 | | H_L_COLON, |
111 | | H_CONT_LEN_BODY, |
112 | | H_CONT_LEN_BODY_PARSE, |
113 | | H_STUN_MSG, |
114 | | H_STUN_READ_BODY, |
115 | | H_STUN_FP, |
116 | | H_STUN_END, |
117 | | H_PING_CRLF |
118 | | #ifdef READ_HTTP11 |
119 | | , |
120 | | H_HTTP11_CHUNK_START, |
121 | | H_HTTP11_CHUNK_SIZE, |
122 | | H_HTTP11_CHUNK_BODY, |
123 | | H_HTTP11_CHUNK_END, |
124 | | H_HTTP11_CHUNK_FINISH |
125 | | #endif |
126 | | #ifdef READ_MSRP |
127 | | , |
128 | | H_MSRP_BODY, |
129 | | H_MSRP_BODY_LF, |
130 | | H_MSRP_BODY_END, |
131 | | H_MSRP_FINISH |
132 | | #endif |
133 | | } tcp_req_states_t; |
134 | | |
135 | | typedef enum tcp_conn_states |
136 | | { |
137 | | S_CONN_ERROR = -2, |
138 | | S_CONN_BAD = -1, |
139 | | S_CONN_OK = 0, /* established (write or read) */ |
140 | | S_CONN_INIT, /* initial state (invalid) */ |
141 | | S_CONN_EOF, |
142 | | S_CONN_ACCEPT, |
143 | | S_CONN_CONNECT |
144 | | } tcp_conn_states_t; |
145 | | |
146 | | |
147 | | /* fd communication commands */ |
148 | | typedef enum conn_cmds |
149 | | { |
150 | | CONN_DESTROY = -3 /* destroy connection & auto-dec. refcnt */, |
151 | | CONN_ERROR = -2 /* error on connection & auto-dec. refcnt */, |
152 | | CONN_EOF = -1 /* eof received or conn. closed & auto-dec refcnt */, |
153 | | CONN_NOP = 0 /* do-nothing (invalid for tcp_main) */, |
154 | | CONN_RELEASE /* release a connection from tcp_read back into tcp_main |
155 | | * & auto-dec refcnt */ |
156 | | , |
157 | | CONN_GET_FD /* request a fd from tcp_main */, |
158 | | CONN_NEW /* update/set a fd int a new tcp connection; refcnts are |
159 | | * not touched */ |
160 | | , |
161 | | CONN_QUEUED_WRITE /* new write queue: start watching the fd for write & |
162 | | * auto-dec refcnt */ |
163 | | , |
164 | | CONN_NEW_PENDING_WRITE /* like CONN_NEW+CONN_QUEUED_WRITE: set fd and |
165 | | * start watching it for write (write queue |
166 | | * non-empty); refcnts are not touced */ |
167 | | , |
168 | | CONN_NEW_COMPLETE /* like CONN_NEW_PENDING_WRITE, but there is no |
169 | | * pending write (the write queue might be empty) */ |
170 | | } conn_cmds_t; |
171 | | /* CONN_RELEASE, EOF, ERROR, DESTROY can be used by "reader" processes |
172 | | * CONN_GET_FD, CONN_NEW*, CONN_QUEUED_WRITE only by writers */ |
173 | | |
174 | | /* tcp_req flags */ |
175 | | typedef enum tcp_req_flags |
176 | | { |
177 | | F_TCP_REQ_HAS_CLEN = (1 << 0), |
178 | | F_TCP_REQ_COMPLETE = (1 << 1), |
179 | | #ifdef READ_HTTP11 |
180 | | F_TCP_REQ_BCHUNKED = (1 << 2), |
181 | | #endif |
182 | | #ifdef READ_MSRP |
183 | | F_TCP_REQ_MSRP_NO = (1 << 3), |
184 | | F_TCP_REQ_MSRP_FRAME = (1 << 4), |
185 | | F_TCP_REQ_MSRP_BODY = (1 << 5), |
186 | | #endif |
187 | | F_TCP_REQ_HEP3 = (1 << 6), |
188 | | } tcp_req_flags_t; |
189 | | |
190 | 0 | #define TCP_REQ_HAS_CLEN(tr) ((tr)->flags & F_TCP_REQ_HAS_CLEN) |
191 | | #define TCP_REQ_COMPLETE(tr) ((tr)->flags & F_TCP_REQ_COMPLETE) |
192 | | #ifdef READ_HTTP11 |
193 | 0 | #define TCP_REQ_BCHUNKED(tr) ((tr)->flags & F_TCP_REQ_BCHUNKED) |
194 | | #endif |
195 | | |
196 | 0 | #define KSR_TCP_REQSTATE_DATARECV (1 << 0) |
197 | | |
198 | | typedef struct tcp_req |
199 | | { |
200 | | struct tcp_req *next; |
201 | | /* sockaddr ? */ |
202 | | char *buf; /* bytes read so far (+0-terminator)*/ |
203 | | char *start; /* where the message starts, after all the empty lines are |
204 | | skipped*/ |
205 | | char *pos; /* current position in buf */ |
206 | | char *parsed; /* last parsed position */ |
207 | | char *body; /* body position */ |
208 | | unsigned int b_size; /* buffer size-1 (extra space for 0-term)*/ |
209 | | int content_len; |
210 | | #ifdef READ_HTTP11 |
211 | | int chunk_size; |
212 | | #endif |
213 | | enum tcp_req_flags flags; /* F_TCP_REQ_HAS_CLEN | F_TCP_REQ_COMPLETE */ |
214 | | int bytes_to_go; /* how many bytes we have still to read from the body*/ |
215 | | enum tcp_req_errors error; |
216 | | enum tcp_req_states state; |
217 | | unsigned int dxstate; |
218 | | struct timeval tvrstart; |
219 | | } tcp_req_t; |
220 | | |
221 | | struct tcp_connection; |
222 | | |
223 | | /* tcp port alias structure */ |
224 | | typedef struct tcp_conn_alias |
225 | | { |
226 | | struct tcp_connection *parent; |
227 | | struct tcp_conn_alias *next; |
228 | | struct tcp_conn_alias *prev; |
229 | | unsigned short port; /* alias port */ |
230 | | unsigned short hash; /* hash index in the address hash */ |
231 | | } tcp_conn_alias_t; |
232 | | |
233 | | |
234 | | #ifdef TCP_ASYNC |
235 | | typedef struct tcp_wbuffer |
236 | | { |
237 | | struct tcp_wbuffer *next; |
238 | | unsigned int b_size; |
239 | | char buf[1]; |
240 | | } tcp_wbuffer_t; |
241 | | |
242 | | typedef struct tcp_wbuffer_queue |
243 | | { |
244 | | struct tcp_wbuffer *first; |
245 | | struct tcp_wbuffer *last; |
246 | | ticks_t wr_timeout; /* write timeout*/ |
247 | | unsigned int queued; /* total size */ |
248 | | unsigned int offset; /* offset in the first wbuffer were data |
249 | | starts */ |
250 | | unsigned int last_used; /* how much of the last buffer is used */ |
251 | | } tcp_wbuffer_queue_t; |
252 | | #endif |
253 | | |
254 | | |
255 | | enum tcp_closed_reason |
256 | | { |
257 | | TCP_CLOSED_EOF = 0, |
258 | | TCP_CLOSED_TIMEOUT, |
259 | | TCP_CLOSED_RESET, |
260 | | |
261 | | _TCP_CLOSED_REASON_MAX /* /!\ keep this one always at the end */ |
262 | | }; |
263 | | |
264 | | |
265 | | typedef struct tcp_connection |
266 | | { |
267 | | int s; /*socket, used by "tcp main" */ |
268 | | int fd; /* used only by "children", don't modify it! private data! */ |
269 | | gen_lock_t write_lock; |
270 | | int id; /* id (unique!) used to retrieve a specific connection when |
271 | | * reply-ing */ |
272 | | enum tcp_closed_reason event; /* connection close reason */ |
273 | | int reader_pid; /* pid of the active reader process */ |
274 | | struct receive_info rcv; /* src & dst ip, ports, proto a.s.o*/ |
275 | | ksr_coninfo_t cinfo; /* connection info (e.g., for haproxy ) */ |
276 | | struct tcp_req req; /* request data */ |
277 | | atomic_t refcnt; |
278 | | enum sip_protos type; /* PROTO_TCP or a protocol over it, e.g. TLS */ |
279 | | unsigned int flags; /* connection related flags */ |
280 | | snd_flags_t send_flags; /* special send flags */ |
281 | | enum tcp_conn_states state; /* connection state */ |
282 | | enum tcp_conn_states initstate; /* initial connection state */ |
283 | | void *extra_data; /* extra data associated to the connection, 0 for tcp*/ |
284 | | struct timer_ln timer; |
285 | | time_t timestamp; /* connection creation timestamp */ |
286 | | ticks_t timeout; /* connection timeout, after this it will be removed*/ |
287 | | ticks_t lifetime; /* connection lifetime */ |
288 | | unsigned id_hash; /* hash index in the id_hash */ |
289 | | struct tcp_connection *id_next; /* next, prev in id hash table */ |
290 | | struct tcp_connection *id_prev; |
291 | | struct tcp_connection *c_next; /* child next prev (use locally) */ |
292 | | struct tcp_connection *c_prev; |
293 | | struct tcp_conn_alias con_aliases[TCP_CON_MAX_ALIASES]; |
294 | | int aliases; /* aliases number, at least 1 */ |
295 | | #ifdef TCP_ASYNC |
296 | | struct tcp_wbuffer_queue wbuf_q; |
297 | | #endif |
298 | | } tcp_connection_t; |
299 | | |
300 | | |
301 | | /* helper macros */ |
302 | | |
303 | | #define tcpconn_set_send_flags(c, snd_flags) \ |
304 | 0 | SND_FLAGS_OR(&(c)->send_flags, &(c)->send_flags, &(snd_flags)) |
305 | | |
306 | | #define tcpconn_close_after_send(c) ((c)->send_flags.f & SND_F_CON_CLOSE) |
307 | | |
308 | | #define TCP_RCV_INFO(c) (&(c)->rcv) |
309 | | |
310 | | #define TCP_RCV_LADDR(r) (&((r).dst_ip)) |
311 | | #define TCP_RCV_LPORT(r) ((r).dst_port) |
312 | | #define TCP_RCV_PADDR(r) (&((r).src_ip)) |
313 | | #define TCP_RCV_PPORT(r) ((r).src_port) |
314 | | #define TCP_RCV_PSU(r) (&(r).src_su) |
315 | | #define TCP_RCV_SOCK_INFO(r) ((r).bind_address) |
316 | | #define TCP_RCV_PROTO(r) ((r).proto) |
317 | | #ifdef USE_COMP |
318 | | #define TCP_RCV_COMP(r) ((r).comp) |
319 | | #else |
320 | | #define TCP_RCV_COMP(r) 0 |
321 | | #endif /* USE_COMP */ |
322 | | |
323 | | #define TCP_LADDR(c) TCP_RCV_LADDR(c->rcv) |
324 | | #define TCP_LPORT(c) TCP_RCV_LPORT(c->rcv) |
325 | | #define TCP_PADDR(c) TCP_RCV_PADDR(c->rcv) |
326 | | #define TCP_PPORT(c) TCP_RCV_PPORT(c->rcv) |
327 | | #define TCP_PSU(c) TCP_RCV_PSU(c->rcv) |
328 | | #define TCP_SOCK_INFO(c) TCP_RCV_SOCK_INFO(c->rcv) |
329 | | #define TCP_PROTO(c) TCP_RCV_PROTO(c->rcv) |
330 | | #define TCP_COMP(c) TCP_RCV_COMP(c->rcv) |
331 | | |
332 | | |
333 | 0 | #define tcpconn_ref(c) atomic_inc(&((c)->refcnt)) |
334 | 0 | #define tcpconn_put(c) atomic_dec_and_test(&((c)->refcnt)) |
335 | | |
336 | | |
337 | | #define init_tcp_req(r, rd_buf, rd_buf_size) \ |
338 | 0 | do { \ |
339 | 0 | memset((r), 0, sizeof(struct tcp_req)); \ |
340 | 0 | (r)->buf = (rd_buf); \ |
341 | 0 | (r)->b_size = (rd_buf_size)-1; /* space for 0 term. */ \ |
342 | 0 | (r)->parsed = (r)->pos = (r)->start = (r)->buf; \ |
343 | 0 | (r)->error = TCP_REQ_OK; \ |
344 | 0 | (r)->state = H_SKIP_EMPTY; \ |
345 | 0 | } while(0) |
346 | | |
347 | | |
348 | | /* add a tcpconn to a list*/ |
349 | | /* list head, new element, next member, prev member */ |
350 | | #define tcpconn_listadd(head, c, next, prev) \ |
351 | 0 | do { \ |
352 | 0 | /* add it at the beginning of the list*/ \ |
353 | 0 | (c)->next = (head); \ |
354 | 0 | (c)->prev = 0; \ |
355 | 0 | if((head)) \ |
356 | 0 | (head)->prev = (c); \ |
357 | 0 | (head) = (c); \ |
358 | 0 | } while(0) |
359 | | |
360 | | |
361 | | /* remove a tcpconn from a list*/ |
362 | | #define tcpconn_listrm(head, c, next, prev) \ |
363 | 0 | do { \ |
364 | 0 | if((head) == (c)) \ |
365 | 0 | (head) = (c)->next; \ |
366 | 0 | if((c)->next) \ |
367 | 0 | (c)->next->prev = (c)->prev; \ |
368 | 0 | if((c)->prev) \ |
369 | 0 | (c)->prev->next = (c)->next; \ |
370 | 0 | } while(0) |
371 | | |
372 | | |
373 | 0 | #define TCPCONN_LOCK lock_get(tcpconn_lock); |
374 | 0 | #define TCPCONN_UNLOCK lock_release(tcpconn_lock); |
375 | | |
376 | 0 | #define TCP_ALIAS_HASH_SIZE 4096 |
377 | 0 | #define TCP_ID_HASH_SIZE 1024 |
378 | | |
379 | | /* hash (dst_ip, dst_port, local_ip, local_port) */ |
380 | | static inline unsigned tcp_addr_hash(struct ip_addr *ip, unsigned short port, |
381 | | struct ip_addr *l_ip, unsigned short l_port) |
382 | 0 | { |
383 | 0 | unsigned h; |
384 | |
|
385 | 0 | if(ip->len == 4) |
386 | 0 | h = (ip->u.addr32[0] ^ port) ^ (l_ip->u.addr32[0] ^ l_port); |
387 | 0 | else if(ip->len == 16) |
388 | 0 | h = (ip->u.addr32[0] ^ ip->u.addr32[1] ^ ip->u.addr32[2] |
389 | 0 | ^ ip->u.addr32[3] ^ port) |
390 | 0 | ^ (l_ip->u.addr32[0] ^ l_ip->u.addr32[1] ^ l_ip->u.addr32[2] |
391 | 0 | ^ l_ip->u.addr32[3] ^ l_port); |
392 | 0 | else { |
393 | 0 | LM_CRIT("bad len %d for an ip address\n", ip->len); |
394 | 0 | return 0; |
395 | 0 | } |
396 | | /* make sure the first bits are influenced by all 32 |
397 | | * (the first log2(TCP_ALIAS_HASH_SIZE) bits should be a mix of all |
398 | | * 32)*/ |
399 | 0 | h ^= h >> 17; |
400 | 0 | h ^= h >> 7; |
401 | 0 | return h & (TCP_ALIAS_HASH_SIZE - 1); |
402 | 0 | } Unexecuted instantiation: receive.c:tcp_addr_hash Unexecuted instantiation: route.c:tcp_addr_hash Unexecuted instantiation: select_core.c:tcp_addr_hash Unexecuted instantiation: tcp_main.c:tcp_addr_hash Unexecuted instantiation: tcp_read.c:tcp_addr_hash Unexecuted instantiation: tls_hooks.c:tcp_addr_hash Unexecuted instantiation: action.c:tcp_addr_hash Unexecuted instantiation: core_cmd.c:tcp_addr_hash Unexecuted instantiation: forward.c:tcp_addr_hash Unexecuted instantiation: kemi.c:tcp_addr_hash Unexecuted instantiation: local_timer.c:tcp_addr_hash Unexecuted instantiation: msg_translator.c:tcp_addr_hash |
403 | | |
404 | 0 | #define tcp_id_hash(id) (id & (TCP_ID_HASH_SIZE - 1)) |
405 | | |
406 | | struct tcp_connection *tcpconn_get(int id, struct ip_addr *ip, int port, |
407 | | union sockaddr_union *local_addr, ticks_t timeout); |
408 | | |
409 | | struct tcp_connection *tcpconn_lookup(int id, struct ip_addr *ip, int port, |
410 | | union sockaddr_union *local_addr, int try_local_port, ticks_t timeout); |
411 | | |
412 | | typedef struct tcp_event_info |
413 | | { |
414 | | int type; |
415 | | char *buf; |
416 | | unsigned int len; |
417 | | struct receive_info *rcv; |
418 | | struct tcp_connection *con; |
419 | | } tcp_event_info_t; |
420 | | |
421 | | typedef struct tcp_closed_event_info |
422 | | { |
423 | | enum tcp_closed_reason reason; |
424 | | struct tcp_connection *con; |
425 | | } tcp_closed_event_info_t; |
426 | | |
427 | | typedef struct ws_event_info |
428 | | { |
429 | | int type; |
430 | | char *buf; |
431 | | unsigned int len; |
432 | | int id; |
433 | | } ws_event_info_t; |
434 | | |
435 | | #endif |