File: | libsofia-sip-ua/tport/tport_type_ws.c |
Warning: | line 367, column 12 Although the value stored to 'tbf' is used in the enclosing expression, the value is never actually read from 'tbf' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | * This file is part of the Sofia-SIP package |
3 | * |
4 | * Copyright (C) 2006 Nokia Corporation. |
5 | * |
6 | * Contact: Pekka Pessi <pekka.pessi@nokia.com> |
7 | * |
8 | * This library is free software; you can redistribute it and/or |
9 | * modify it under the terms of the GNU Lesser General Public License |
10 | * as published by the Free Software Foundation; either version 2.1 of |
11 | * the License, or (at your option) any later version. |
12 | * |
13 | * This library is distributed in the hope that it will be useful, but |
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | * Lesser General Public License for more details. |
17 | * |
18 | * You should have received a copy of the GNU Lesser General Public |
19 | * License along with this library; if not, write to the Free Software |
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA |
21 | * 02110-1301 USA |
22 | * |
23 | */ |
24 | |
25 | /**@CFILE tport_type_ws.c WS Transport |
26 | * |
27 | * See tport.docs for more detailed description of tport interface. |
28 | * |
29 | * @author Pekka Pessi <Pekka.Pessi@nokia.com> |
30 | * @author Martti Mela <Martti.Mela@nokia.com> |
31 | * |
32 | * @date Created: Fri Mar 24 08:45:49 EET 2006 ppessi |
33 | */ |
34 | |
35 | #include "config.h" |
36 | |
37 | #include "tport_internal.h" |
38 | #include "tport_ws.h" |
39 | #include "tport_tls.h" |
40 | |
41 | #if HAVE_NETINET_TCP_H1 |
42 | #include <netinet/tcp.h> |
43 | #endif |
44 | |
45 | #ifndef SOL_TCP6 |
46 | #define SOL_TCP6 IPPROTO_TCPIPPROTO_TCP |
47 | #endif |
48 | |
49 | #include <stdlib.h> |
50 | #include <string.h> |
51 | #include <time.h> |
52 | #include <assert.h> |
53 | #include <errno(*__errno_location ()).h> |
54 | #include <limits.h> |
55 | |
56 | #if HAVE_FUNC1 |
57 | #elif HAVE_FUNCTION1 |
58 | #define __func__ __FUNCTION__ |
59 | #else |
60 | static char const __func__[] = "tport_type_ws"; |
61 | #endif |
62 | |
63 | #if HAVE_WIN32 |
64 | #include <io.h> |
65 | #define access(_filename, _mode) _access(_filename, _mode) |
66 | #define R_OK4 (04) |
67 | #endif |
68 | |
69 | /* ---------------------------------------------------------------------- */ |
70 | /* WS */ |
71 | |
72 | #include <sofia-sip/http.h> |
73 | #include <sofia-sip/http_header.h> |
74 | |
75 | static int tport_ws_init_primary_secure(tport_primary_t *pri, |
76 | tp_name_t tpn[1], |
77 | su_addrinfo_t *ai, |
78 | tagi_t const *tags, |
79 | char const **return_culprit); |
80 | |
81 | static int tport_ws_setsndbuf(int socket, int atleast); |
82 | static void tport_ws_deinit_primary(tport_primary_t *pri); |
83 | |
84 | tport_vtable_t const tport_ws_vtable = |
85 | { |
86 | /* vtp_name */ "ws", |
87 | /* vtp_public */ tport_type_local, |
88 | /* vtp_pri_size */ sizeof (tport_ws_primary_t), |
89 | /* vtp_init_primary */ tport_ws_init_primary, |
90 | /* vtp_deinit_primary */ tport_ws_deinit_primary, |
91 | /* vtp_wakeup_pri */ tport_accept, |
92 | /* vtp_connect */ NULL((void*)0), |
93 | /* vtp_secondary_size */ sizeof (tport_ws_t), |
94 | /* vtp_init_secondary */ tport_ws_init_secondary, |
95 | /* tp_deinit_secondary */ tport_ws_deinit_secondary, |
96 | /* vtp_shutdown */ NULL((void*)0), |
97 | /* vtp_set_events */ NULL((void*)0), |
98 | /* vtp_wakeup */ NULL((void*)0), |
99 | /* vtp_recv */ tport_recv_stream_ws, |
100 | /* vtp_send */ tport_send_stream_ws, |
101 | /* vtp_deliver */ NULL((void*)0), |
102 | /* vtp_prepare */ NULL((void*)0), |
103 | /* vtp_keepalive */ NULL((void*)0), |
104 | /* vtp_stun_response */ NULL((void*)0), |
105 | /* vtp_next_secondary_timer*/ tport_ws_next_timer, |
106 | /* vtp_secondary_timer */ tport_ws_timer, |
107 | }; |
108 | |
109 | tport_vtable_t const tport_ws_client_vtable = |
110 | { |
111 | /* vtp_name */ "ws", |
112 | /* vtp_public */ tport_type_client, |
113 | /* vtp_pri_size */ sizeof (tport_ws_primary_t), |
114 | /* vtp_init_primary */ tport_ws_init_client, |
115 | /* vtp_deinit_primary */ tport_ws_deinit_primary, |
116 | /* vtp_wakeup_pri */ NULL((void*)0), |
117 | /* vtp_connect */ NULL((void*)0), |
118 | /* vtp_secondary_size */ sizeof (tport_ws_t), |
119 | /* vtp_init_secondary */ tport_ws_init_secondary, |
120 | /* vtp_deinit_secondary */ NULL((void*)0), |
121 | /* vtp_shutdown */ NULL((void*)0), |
122 | /* vtp_set_events */ NULL((void*)0), |
123 | /* vtp_wakeup */ NULL((void*)0), |
124 | /* vtp_recv */ tport_recv_stream_ws, |
125 | /* vtp_send */ tport_send_stream_ws, |
126 | /* vtp_deliver */ NULL((void*)0), |
127 | /* vtp_prepare */ NULL((void*)0), |
128 | /* vtp_keepalive */ NULL((void*)0), |
129 | /* vtp_stun_response */ NULL((void*)0), |
130 | /* vtp_next_secondary_timer*/ tport_ws_next_timer, |
131 | /* vtp_secondary_timer */ tport_ws_timer, |
132 | }; |
133 | |
134 | tport_vtable_t const tport_wss_vtable = |
135 | { |
136 | /* vtp_name */ "wss", |
137 | /* vtp_public */ tport_type_local, |
138 | /* vtp_pri_size */ sizeof (tport_ws_primary_t), |
139 | /* vtp_init_primary */ tport_ws_init_primary_secure, |
140 | /* vtp_deinit_primary */ tport_ws_deinit_primary, |
141 | /* vtp_wakeup_pri */ tport_accept, |
142 | /* vtp_connect */ NULL((void*)0), |
143 | /* vtp_secondary_size */ sizeof (tport_ws_t), |
144 | /* vtp_init_secondary */ tport_ws_init_secondary, |
145 | /* vtp_deinit_secondary */ tport_ws_deinit_secondary, |
146 | /* vtp_shutdown */ NULL((void*)0), |
147 | /* vtp_set_events */ NULL((void*)0), |
148 | /* vtp_wakeup */ NULL((void*)0), |
149 | /* vtp_recv */ tport_recv_stream_ws, |
150 | /* vtp_send */ tport_send_stream_ws, |
151 | /* vtp_deliver */ NULL((void*)0), |
152 | /* vtp_prepare */ NULL((void*)0), |
153 | /* vtp_keepalive */ NULL((void*)0), |
154 | /* vtp_stun_response */ NULL((void*)0), |
155 | /* vtp_next_secondary_timer*/ tport_ws_next_timer, |
156 | /* vtp_secondary_timer */ tport_ws_timer, |
157 | }; |
158 | |
159 | tport_vtable_t const tport_wss_client_vtable = |
160 | { |
161 | /* vtp_name */ "wss", |
162 | /* vtp_public */ tport_type_client, |
163 | /* vtp_pri_size */ sizeof (tport_ws_primary_t), |
164 | /* vtp_init_primary */ tport_ws_init_client, |
165 | /* vtp_deinit_primary */ tport_ws_deinit_primary, |
166 | /* vtp_wakeup_pri */ NULL((void*)0), |
167 | /* vtp_connect */ NULL((void*)0), |
168 | /* vtp_secondary_size */ sizeof (tport_ws_t), |
169 | /* vtp_init_secondary */ tport_ws_init_secondary, |
170 | /* vtp_deinit_secondary */ NULL((void*)0), |
171 | /* vtp_shutdown */ NULL((void*)0), |
172 | /* vtp_set_events */ NULL((void*)0), |
173 | /* vtp_wakeup */ NULL((void*)0), |
174 | /* vtp_recv */ tport_recv_stream_ws, |
175 | /* vtp_send */ tport_send_stream_ws, |
176 | /* vtp_deliver */ NULL((void*)0), |
177 | /* vtp_prepare */ NULL((void*)0), |
178 | /* vtp_keepalive */ NULL((void*)0), |
179 | /* vtp_stun_response */ NULL((void*)0), |
180 | /* vtp_next_secondary_timer*/ tport_ws_next_timer, |
181 | /* vtp_secondary_timer */ tport_ws_timer, |
182 | }; |
183 | |
184 | |
185 | static void tport_ws_deinit_primary(tport_primary_t *pri) |
186 | { |
187 | tport_ws_primary_t *wspri = (tport_ws_primary_t *)pri; |
188 | |
189 | if ( wspri->ssl_ctx ) { |
190 | SSL_CTX_free(wspri->ssl_ctx); |
191 | wspri->ssl_ctx = NULL((void*)0); |
192 | } |
193 | } |
194 | |
195 | /** Receive from stream. |
196 | * |
197 | * @retval -1 error |
198 | * @retval 0 end-of-stream |
199 | * @retval 1 normal receive |
200 | * @retval 2 incomplete recv, recv again |
201 | * |
202 | */ |
203 | int tport_recv_stream_ws(tport_t *self) |
204 | { |
205 | msg_t *msg; |
206 | ssize_t n, N, veclen, i, m; |
207 | int err; |
208 | msg_iovec_t iovec[msg_n_fragments] = {{ 0 }}; |
209 | tport_ws_t *wstp = (tport_ws_t *)self; |
210 | uint8_t *data; |
211 | ws_opcode_t oc; |
212 | |
213 | if (wstp->ws_initialized < 0) { |
214 | return -1; |
215 | } |
216 | |
217 | N = ws_read_frame(&wstp->ws, &oc, &data); |
218 | |
219 | if (N == -2) { |
220 | return 1; |
221 | } |
222 | |
223 | if ((N == -1000) || (N == 0)) { |
224 | if (self->tp_msg) { |
225 | msg_recv_commit(self->tp_msg, 0, 1); |
226 | } |
227 | return 0; /* End of stream */ |
228 | } |
229 | if (N < 0) { |
230 | err = errno(*__errno_location ()) = EHOSTDOWN112; |
231 | SU_DEBUG_1(("%s(%p): su_getmsgsize(): %s (%d) N=%ld\n", __func__, (void *)self,(((tport_log != ((void*)0) && tport_log->log_init) == 0 ? 9 : ((tport_log != ((void*)0) && tport_log-> log_init > 1) ? tport_log->log_level : su_log_default-> log_level)) >= 1 ? (_su_llog(tport_log, 1, "tport_type_ws.c" , (const char *)__func__, 232, "%s(%p): su_getmsgsize(): %s (%d) N=%ld\n" , __func__, (void *)self, su_strerror(err), err, (long)N)) : ( void)0) |
232 | su_strerror(err), err, (long)N))(((tport_log != ((void*)0) && tport_log->log_init) == 0 ? 9 : ((tport_log != ((void*)0) && tport_log-> log_init > 1) ? tport_log->log_level : su_log_default-> log_level)) >= 1 ? (_su_llog(tport_log, 1, "tport_type_ws.c" , (const char *)__func__, 232, "%s(%p): su_getmsgsize(): %s (%d) N=%ld\n" , __func__, (void *)self, su_strerror(err), err, (long)N)) : ( void)0); |
233 | return 0; |
234 | } |
235 | |
236 | veclen = tport_recv_iovec(self, &self->tp_msg, iovec, N, 0); |
237 | if (veclen < 0) |
238 | return -1; |
239 | |
240 | msg = self->tp_msg; |
241 | |
242 | msg_set_address(msg, self->tp_addr, self->tp_addrlentp_addrinfo->ai_addrlen); |
243 | |
244 | for (i = 0, n = 0; i < veclen; i++) { |
245 | m = iovec[i].mv_lensiv_len; assert(N >= n + m)((void) sizeof ((N >= n + m) ? 1 : 0), __extension__ ({ if (N >= n + m) ; else __assert_fail ("N >= n + m", "tport_type_ws.c" , 245, __extension__ __PRETTY_FUNCTION__); })); |
246 | memcpy(iovec[i].mv_basesiv_base, data + n, m); |
247 | n += m; |
248 | } |
249 | |
250 | assert(N == n)((void) sizeof ((N == n) ? 1 : 0), __extension__ ({ if (N == n ) ; else __assert_fail ("N == n", "tport_type_ws.c", 250, __extension__ __PRETTY_FUNCTION__); })); |
251 | |
252 | /* Write the received data to the message dump file */ |
253 | if (self->tp_master->mr_dump_file) |
254 | tport_dump_iovec(self, msg, n, iovec, veclen, "recv", "from"); |
255 | |
256 | if (self->tp_master->mr_capt_sock) |
257 | tport_capt_msg(self, msg, n, iovec, veclen, "recv"); |
258 | |
259 | /* Mark buffer as used */ |
260 | msg_recv_commit(msg, N, 0); |
261 | |
262 | return 1; |
263 | } |
264 | |
265 | /** Send to stream */ |
266 | ssize_t tport_send_stream_ws(tport_t const *self, msg_t *msg, |
267 | msg_iovec_t iov[], |
268 | size_t iovlen) |
269 | { |
270 | size_t i, j, m, size = 0; |
271 | ssize_t nerror; |
272 | tport_ws_t *wstp = (tport_ws_t *)self; |
273 | |
274 | wstp->wstp_buflen = 0; |
275 | |
276 | for (i = 0; i < iovlen; i = j) { |
277 | char *buf = NULL((void*)0); |
278 | unsigned wsbufsize = sizeof(wstp->wstp_buffer); |
279 | |
280 | for (j = i, m = 0; buf && j < iovlen; j++) { |
281 | if (m + iov[j].siv_len > wsbufsize) { |
282 | break; |
283 | } |
284 | if (buf + m != iov[j].siv_base) { |
285 | memcpy(buf + m, iov[j].siv_base, iov[j].siv_len); |
286 | } |
287 | m += iov[j].siv_len; iov[j].siv_len = 0; |
288 | } |
289 | |
290 | if (j == i) { |
291 | buf = iov[i].siv_base, m = iov[i].siv_len, j++; |
292 | } else { |
293 | iov[j].siv_base = buf, iov[j].siv_len = m; |
294 | } |
295 | |
296 | nerror = 0; |
297 | |
298 | if (m + wstp->wstp_buflen >= wsbufsize) { |
299 | nerror = -1; |
300 | errno(*__errno_location ()) = ENOMEM12; |
301 | } else { |
302 | if (memcpy(wstp->wstp_buffer + wstp->wstp_buflen, buf, m)) { |
303 | wstp->wstp_buflen += m; |
304 | } else { |
305 | nerror = -1; |
306 | errno(*__errno_location ()) = ENOMEM12; |
307 | } |
308 | } |
309 | |
310 | SU_DEBUG_9(("tport_ws_writevec: vec %p %p %lu ("MOD_ZD")\n",(((tport_log != ((void*)0) && tport_log->log_init) == 0 ? 9 : ((tport_log != ((void*)0) && tport_log-> log_init > 1) ? tport_log->log_level : su_log_default-> log_level)) >= 9 ? (_su_llog(tport_log, 9, "tport_type_ws.c" , (const char *)__func__, 312, "tport_ws_writevec: vec %p %p %lu (" "%zd"")\n", (void *)&wstp->ws, (void *)iov[i].siv_base , (LU)iov[i].siv_len, nerror)) : (void)0) |
311 | (void *)&wstp->ws, (void *)iov[i].siv_base, (LU)iov[i].siv_len,(((tport_log != ((void*)0) && tport_log->log_init) == 0 ? 9 : ((tport_log != ((void*)0) && tport_log-> log_init > 1) ? tport_log->log_level : su_log_default-> log_level)) >= 9 ? (_su_llog(tport_log, 9, "tport_type_ws.c" , (const char *)__func__, 312, "tport_ws_writevec: vec %p %p %lu (" "%zd"")\n", (void *)&wstp->ws, (void *)iov[i].siv_base , (LU)iov[i].siv_len, nerror)) : (void)0) |
312 | nerror))(((tport_log != ((void*)0) && tport_log->log_init) == 0 ? 9 : ((tport_log != ((void*)0) && tport_log-> log_init > 1) ? tport_log->log_level : su_log_default-> log_level)) >= 9 ? (_su_llog(tport_log, 9, "tport_type_ws.c" , (const char *)__func__, 312, "tport_ws_writevec: vec %p %p %lu (" "%zd"")\n", (void *)&wstp->ws, (void *)iov[i].siv_base , (LU)iov[i].siv_len, nerror)) : (void)0); |
313 | |
314 | if (nerror == -1) { |
315 | int err = su_errno(); |
316 | if (su_is_blocking(err)((err) == 115 || (err) == 11 || (err) == 11 || (err) == 4)) |
317 | break; |
318 | SU_DEBUG_3(("ws_write: %s\n", strerror(err)))(((tport_log != ((void*)0) && tport_log->log_init) == 0 ? 9 : ((tport_log != ((void*)0) && tport_log-> log_init > 1) ? tport_log->log_level : su_log_default-> log_level)) >= 3 ? (_su_llog(tport_log, 3, "tport_type_ws.c" , (const char *)__func__, 318, "ws_write: %s\n", strerror(err ))) : (void)0); |
319 | return -1; |
320 | } |
321 | } |
322 | |
323 | if (wstp->wstp_buflen) { |
324 | ssize_t wrote = 0; |
325 | |
326 | *(wstp->wstp_buffer + wstp->wstp_buflen) = '\0'; |
327 | wrote = ws_write_frame(&wstp->ws, WSOC_TEXT, wstp->wstp_buffer, wstp->wstp_buflen); |
328 | |
329 | if (wrote <= 0) { |
330 | int err = su_errno(); |
331 | SU_DEBUG_3(("ws_write_frame: %s (%ld)\n", strerror(err), (long)wrote))(((tport_log != ((void*)0) && tport_log->log_init) == 0 ? 9 : ((tport_log != ((void*)0) && tport_log-> log_init > 1) ? tport_log->log_level : su_log_default-> log_level)) >= 3 ? (_su_llog(tport_log, 3, "tport_type_ws.c" , (const char *)__func__, 331, "ws_write_frame: %s (%ld)\n", strerror (err), (long)wrote)) : (void)0); |
332 | return (wrote == 0) ? 0 : -1; |
333 | } else { |
334 | size = wstp->wstp_buflen; |
335 | } |
336 | } |
337 | |
338 | return size; |
339 | } |
340 | |
341 | static int tport_ws_init_primary_secure(tport_primary_t *pri, |
342 | tp_name_t tpn[1], |
343 | su_addrinfo_t *ai, |
344 | tagi_t const *tags, |
345 | char const **return_culprit) |
346 | { |
347 | tport_ws_primary_t *wspri = (tport_ws_primary_t *)pri; |
348 | const char *cert = "/ssl.pem"; |
349 | const char *key = "/ssl.pem"; |
350 | const char *chain = NULL((void*)0); |
351 | char *homedir; |
352 | char *tbf = NULL((void*)0); |
353 | su_home_t autohome[SU_HOME_AUTO_SIZE(1024)(((1024) + ((sizeof(su_home_t) + 7) & (size_t)~8) + ((3 * sizeof (void *) + 4 * sizeof(unsigned) + 7 * (sizeof (long) + sizeof(void *)) + 7) & (size_t)~8)) / sizeof(su_home_t))]; |
354 | char const *path = NULL((void*)0); |
355 | int ret = -1; |
356 | |
357 | su_home_auto(autohome, sizeof autohome); |
358 | |
359 | tl_gets(tags, |
360 | TPTAG_CERTIFICATE_REF(path)tptag_certificate_ref, tag_str_vr(&(path)), |
361 | TAG_END()(tag_type_t)0, (tag_value_t)0); |
362 | |
363 | if (!path) { |
364 | homedir = getenv("HOME"); |
365 | if (!homedir) |
366 | homedir = ""; |
367 | path = tbf = su_sprintf(autohome, "%s/.sip/auth", homedir); |
Although the value stored to 'tbf' is used in the enclosing expression, the value is never actually read from 'tbf' | |
368 | } |
369 | |
370 | if (path) { |
371 | key = su_sprintf(autohome, "%s/%s", path, "wss.key"); |
372 | if (access(key, R_OK4) != 0) key = NULL((void*)0); |
373 | |
374 | cert = su_sprintf(autohome, "%s/%s", path, "wss.crt"); |
375 | if (access(cert, R_OK4) != 0) cert = NULL((void*)0); |
376 | |
377 | chain = su_sprintf(autohome, "%s/%s", path, "ca-bundle.crt"); |
378 | if (access(chain, R_OK4) != 0) chain = NULL((void*)0); |
379 | |
380 | if ( !key ) key = su_sprintf(autohome, "%s/%s", path, "wss.pem"); |
381 | if ( !cert ) cert = su_sprintf(autohome, "%s/%s", path, "wss.pem"); |
382 | if ( !chain ) chain = su_sprintf(autohome, "%s/%s", path, "wss.pem"); |
383 | if (access(key, R_OK4) != 0) key = NULL((void*)0); |
384 | if (access(cert, R_OK4) != 0) cert = NULL((void*)0); |
385 | if (access(chain, R_OK4) != 0) chain = NULL((void*)0); |
386 | } |
387 | |
388 | init_ssl(); |
389 | |
390 | // OpenSSL_add_all_algorithms(); /* load & register cryptos */ |
391 | // SSL_load_error_strings(); /* load all error messages */ |
392 | wspri->ssl_method = SSLv23_server_methodTLS_server_method(); /* create server instance */ |
393 | wspri->ssl_ctx = SSL_CTX_new((SSL_METHOD *)wspri->ssl_method); /* create context */ |
394 | |
395 | if (!wspri->ssl_ctx) { |
396 | tls_log_errors(3, "tport_ws_init_primary_secure", 0); |
397 | goto done; |
398 | } |
399 | |
400 | SSL_CTX_sess_set_remove_cb(wspri->ssl_ctx, NULL((void*)0)); |
401 | wspri->ws_secure = 1; |
402 | |
403 | /* Disable SSLv2 */ |
404 | SSL_CTX_set_options(wspri->ssl_ctx, SSL_OP_NO_SSLv20x0); |
405 | /* Disable SSLv3 */ |
406 | SSL_CTX_set_options(wspri->ssl_ctx, SSL_OP_NO_SSLv30x02000000U); |
407 | /* Disable TLSv1 */ |
408 | SSL_CTX_set_options(wspri->ssl_ctx, SSL_OP_NO_TLSv10x04000000U); |
409 | /* Disable Compression CRIME (Compression Ratio Info-leak Made Easy) */ |
410 | SSL_CTX_set_options(wspri->ssl_ctx, SSL_OP_NO_COMPRESSION0x00020000U); |
411 | |
412 | if (chain) { |
413 | if ( !SSL_CTX_use_certificate_chain_file(wspri->ssl_ctx, chain) ) { |
414 | tls_log_errors(3, "tport_ws_init_primary_secure", 0); |
415 | } |
416 | } |
417 | |
418 | /* set the local certificate from CertFile */ |
419 | if ( !SSL_CTX_use_certificate_file(wspri->ssl_ctx, cert, SSL_FILETYPE_PEM1) ) { |
420 | tls_log_errors(3, "tport_ws_init_primary_secure", 0); |
421 | goto done; |
422 | } |
423 | /* set the private key from KeyFile */ |
424 | if ( !SSL_CTX_use_PrivateKey_file(wspri->ssl_ctx, key, SSL_FILETYPE_PEM1) ) { |
425 | tls_log_errors(3, "tport_ws_init_primary_secure", 0); |
426 | goto done; |
427 | } |
428 | /* verify private key */ |
429 | if ( !SSL_CTX_check_private_key(wspri->ssl_ctx) ) { |
430 | tls_log_errors(3, "tport_ws_init_primary_secure", 0); |
431 | goto done; |
432 | } |
433 | |
434 | if ( !SSL_CTX_set_cipher_list(wspri->ssl_ctx, "!eNULL:!aNULL:!DSS:HIGH:@STRENGTH") ) { |
435 | tls_log_errors(3, "tport_ws_init_primary_secure", 0); |
436 | goto done; |
437 | } |
438 | |
439 | ret = tport_ws_init_primary(pri, tpn, ai, tags, return_culprit); |
440 | |
441 | done: |
442 | su_home_zap(autohome)su_home_unref((autohome)); |
443 | return ret; |
444 | } |
445 | |
446 | int tport_ws_init_primary(tport_primary_t *pri, |
447 | tp_name_t tpn[1], |
448 | su_addrinfo_t *ai, |
449 | tagi_t const *tags, |
450 | char const **return_culprit) |
451 | { |
452 | int socket; |
453 | |
454 | socket = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); |
455 | |
456 | if (socket == INVALID_SOCKET((su_socket_t)INVALID_SOCKET)) |
457 | return *return_culprit = "socket", -1; |
458 | |
459 | tport_ws_setsndbuf(socket, 64 * 1024); |
460 | |
461 | return tport_stream_init_primary(pri, socket, tpn, ai, tags, return_culprit); |
462 | } |
463 | |
464 | int tport_ws_init_client(tport_primary_t *pri, |
465 | tp_name_t tpn[1], |
466 | su_addrinfo_t *ai, |
467 | tagi_t const *tags, |
468 | char const **return_culprit) |
469 | { |
470 | pri->pri_primary->tp_conn_orient = 1; |
471 | |
472 | return 0; |
473 | } |
474 | |
475 | int tport_ws_init_secondary(tport_t *self, int socket, int accepted, |
476 | char const **return_reason) |
477 | { |
478 | int one = 1; |
479 | tport_ws_primary_t *wspri = (tport_ws_primary_t *)self->tp_pri; |
480 | tport_ws_t *wstp = (tport_ws_t *)self; |
481 | |
482 | self->tp_has_connection = 1; |
483 | self->tp_params->tpp_keepalive = 5000; |
484 | |
485 | /* override the default 30 minute timeout on tport connections */ |
486 | self->tp_params->tpp_idle = UINT_MAX(2147483647 *2U +1U); |
487 | |
488 | if (setsockopt(socket, SOL_TCP6, TCP_NODELAY1, (void *)&one, sizeof one) == -1) |
489 | return *return_reason = "TCP_NODELAY", -1; |
490 | |
491 | #if defined(SO_KEEPALIVE9) |
492 | setsockopt(socket, SOL_SOCKET1, SO_KEEPALIVE9, (void *)&one, sizeof one); |
493 | #endif |
494 | one = 30; |
495 | #if defined(TCP_KEEPIDLE4) |
496 | setsockopt(socket, SOL_TCP6, TCP_KEEPIDLE4, (void *)&one, sizeof one); |
497 | #endif |
498 | #if defined(TCP_KEEPINTVL5) |
499 | setsockopt(socket, SOL_TCP6, TCP_KEEPINTVL5, (void *)&one, sizeof one); |
500 | #endif |
501 | |
502 | |
503 | if (!accepted) |
504 | tport_ws_setsndbuf(socket, 64 * 1024); |
505 | |
506 | if ( wspri->ws_secure ) wstp->ws_secure = 1; |
507 | |
508 | memset(&wstp->ws, 0, sizeof(wstp->ws)); |
509 | |
510 | if (ws_init(&wstp->ws, socket, wstp->ws_secure ? wspri->ssl_ctx : NULL((void*)0), 0, 0, 0) < 0) { |
511 | ws_destroy(&wstp->ws); |
512 | wstp->ws_initialized = -1; |
513 | return *return_reason = "WS_INIT", -1; |
514 | } |
515 | |
516 | wstp->connected = time(NULL((void*)0)); |
517 | |
518 | wstp->ws_initialized = 1; |
519 | self->tp_pre_framed = 1; |
520 | |
521 | tport_set_secondary_timer(self); |
522 | |
523 | return 0; |
524 | } |
525 | |
526 | static void tport_ws_deinit_secondary(tport_t *self) |
527 | { |
528 | tport_ws_t *wstp = (tport_ws_t *)self; |
529 | |
530 | if (wstp->ws_initialized == 1) { |
531 | SU_DEBUG_1(("%p destroy ws%s transport %p.\n", (void *) self, wstp->ws_secure ? "s" : "", (void *) &wstp->ws))(((tport_log != ((void*)0) && tport_log->log_init) == 0 ? 9 : ((tport_log != ((void*)0) && tport_log-> log_init > 1) ? tport_log->log_level : su_log_default-> log_level)) >= 1 ? (_su_llog(tport_log, 1, "tport_type_ws.c" , (const char *)__func__, 531, "%p destroy ws%s transport %p.\n" , (void *) self, wstp->ws_secure ? "s" : "", (void *) & wstp->ws)) : (void)0); |
532 | ws_destroy(&wstp->ws); |
533 | wstp->ws_initialized = -1; |
534 | } |
535 | } |
536 | |
537 | static int tport_ws_setsndbuf(int socket, int atleast) |
538 | { |
539 | #if SU_HAVE_WINSOCK2 |
540 | /* Set send buffer size to something reasonable on windows */ |
541 | int size = 0; |
542 | socklen_t sizelen = sizeof size; |
543 | |
544 | if (getsockopt(socket, SOL_SOCKET1, SO_SNDBUF7, (void *)&size, &sizelen) < 0) |
545 | return -1; |
546 | |
547 | if (sizelen != sizeof size) |
548 | return su_seterrno(EINVAL22); |
549 | |
550 | if (size >= atleast) |
551 | return 0; /* OK */ |
552 | |
553 | return setsockopt(socket, SOL_SOCKET1, SO_SNDBUF7, |
554 | (void *)&atleast, sizeof atleast); |
555 | #else |
556 | return 0; |
557 | #endif |
558 | } |
559 | |
560 | |
561 | /** Send PING */ |
562 | int tport_ws_ping(tport_t *self, su_time_t now) |
563 | { |
564 | ssize_t n; |
565 | char *why = ""; |
566 | |
567 | if (tport_has_queued(self)) |
568 | return 0; |
569 | |
570 | n = send(self->tp_socket, "\r\n\r\n", 4, 0); |
571 | |
572 | if (n > 0) |
573 | self->tp_ktime = now; |
574 | |
575 | if (n == 4) { |
576 | if (self->tp_ptime.tv_sec == 0) |
577 | self->tp_ptime = now; |
578 | } |
579 | else if (n == -1) { |
580 | int error = su_errno(); |
581 | |
582 | why = " failed"; |
583 | |
584 | if (!su_is_blocking(error)((error) == 115 || (error) == 11 || (error) == 11 || (error) == 4)) |
585 | tport_error_report(self, error, NULL((void*)0)); |
586 | else |
587 | why = " blocking"; |
588 | } |
589 | |
590 | SU_DEBUG_7(("%s(%p): %s to " TPN_FORMAT "%s\n",(((tport_log != ((void*)0) && tport_log->log_init) == 0 ? 9 : ((tport_log != ((void*)0) && tport_log-> log_init > 1) ? tport_log->log_level : su_log_default-> log_level)) >= 7 ? (_su_llog(tport_log, 7, "tport_type_ws.c" , (const char *)__func__, 592, "%s(%p): %s to " "%s/%s:%s%s%s%s%s" "%s\n", __func__, (void *)self, "sending PING", (self->tp_name )->tpn_proto, (self->tp_name)->tpn_host, (self->tp_name )->tpn_port, (self->tp_name)->tpn_comp ? ";comp=" : "" , (self->tp_name)->tpn_comp ? (self->tp_name)->tpn_comp : "", (self->tp_name)->tpn_ident ? "/" : "", (self-> tp_name)->tpn_ident ? (self->tp_name)->tpn_ident : "" , why)) : (void)0) |
591 | __func__, (void *)self,(((tport_log != ((void*)0) && tport_log->log_init) == 0 ? 9 : ((tport_log != ((void*)0) && tport_log-> log_init > 1) ? tport_log->log_level : su_log_default-> log_level)) >= 7 ? (_su_llog(tport_log, 7, "tport_type_ws.c" , (const char *)__func__, 592, "%s(%p): %s to " "%s/%s:%s%s%s%s%s" "%s\n", __func__, (void *)self, "sending PING", (self->tp_name )->tpn_proto, (self->tp_name)->tpn_host, (self->tp_name )->tpn_port, (self->tp_name)->tpn_comp ? ";comp=" : "" , (self->tp_name)->tpn_comp ? (self->tp_name)->tpn_comp : "", (self->tp_name)->tpn_ident ? "/" : "", (self-> tp_name)->tpn_ident ? (self->tp_name)->tpn_ident : "" , why)) : (void)0) |
592 | "sending PING", TPN_ARGS(self->tp_name), why))(((tport_log != ((void*)0) && tport_log->log_init) == 0 ? 9 : ((tport_log != ((void*)0) && tport_log-> log_init > 1) ? tport_log->log_level : su_log_default-> log_level)) >= 7 ? (_su_llog(tport_log, 7, "tport_type_ws.c" , (const char *)__func__, 592, "%s(%p): %s to " "%s/%s:%s%s%s%s%s" "%s\n", __func__, (void *)self, "sending PING", (self->tp_name )->tpn_proto, (self->tp_name)->tpn_host, (self->tp_name )->tpn_port, (self->tp_name)->tpn_comp ? ";comp=" : "" , (self->tp_name)->tpn_comp ? (self->tp_name)->tpn_comp : "", (self->tp_name)->tpn_ident ? "/" : "", (self-> tp_name)->tpn_ident ? (self->tp_name)->tpn_ident : "" , why)) : (void)0); |
593 | |
594 | return n == -1 ? -1 : 0; |
595 | } |
596 | |
597 | /** Send pong */ |
598 | int tport_ws_pong(tport_t *self) |
599 | { |
600 | self->tp_ping = 0; |
601 | |
602 | if (tport_has_queued(self) || !self->tp_params->tpp_pong2ping) |
603 | return 0; |
604 | |
605 | SU_DEBUG_7(("%s(%p): %s to " TPN_FORMAT "%s\n",(((tport_log != ((void*)0) && tport_log->log_init) == 0 ? 9 : ((tport_log != ((void*)0) && tport_log-> log_init > 1) ? tport_log->log_level : su_log_default-> log_level)) >= 7 ? (_su_llog(tport_log, 7, "tport_type_ws.c" , (const char *)__func__, 607, "%s(%p): %s to " "%s/%s:%s%s%s%s%s" "%s\n", __func__, (void *)self, "sending PONG", (self->tp_name )->tpn_proto, (self->tp_name)->tpn_host, (self->tp_name )->tpn_port, (self->tp_name)->tpn_comp ? ";comp=" : "" , (self->tp_name)->tpn_comp ? (self->tp_name)->tpn_comp : "", (self->tp_name)->tpn_ident ? "/" : "", (self-> tp_name)->tpn_ident ? (self->tp_name)->tpn_ident : "" , "")) : (void)0) |
606 | __func__, (void *)self,(((tport_log != ((void*)0) && tport_log->log_init) == 0 ? 9 : ((tport_log != ((void*)0) && tport_log-> log_init > 1) ? tport_log->log_level : su_log_default-> log_level)) >= 7 ? (_su_llog(tport_log, 7, "tport_type_ws.c" , (const char *)__func__, 607, "%s(%p): %s to " "%s/%s:%s%s%s%s%s" "%s\n", __func__, (void *)self, "sending PONG", (self->tp_name )->tpn_proto, (self->tp_name)->tpn_host, (self->tp_name )->tpn_port, (self->tp_name)->tpn_comp ? ";comp=" : "" , (self->tp_name)->tpn_comp ? (self->tp_name)->tpn_comp : "", (self->tp_name)->tpn_ident ? "/" : "", (self-> tp_name)->tpn_ident ? (self->tp_name)->tpn_ident : "" , "")) : (void)0) |
607 | "sending PONG", TPN_ARGS(self->tp_name), ""))(((tport_log != ((void*)0) && tport_log->log_init) == 0 ? 9 : ((tport_log != ((void*)0) && tport_log-> log_init > 1) ? tport_log->log_level : su_log_default-> log_level)) >= 7 ? (_su_llog(tport_log, 7, "tport_type_ws.c" , (const char *)__func__, 607, "%s(%p): %s to " "%s/%s:%s%s%s%s%s" "%s\n", __func__, (void *)self, "sending PONG", (self->tp_name )->tpn_proto, (self->tp_name)->tpn_host, (self->tp_name )->tpn_port, (self->tp_name)->tpn_comp ? ";comp=" : "" , (self->tp_name)->tpn_comp ? (self->tp_name)->tpn_comp : "", (self->tp_name)->tpn_ident ? "/" : "", (self-> tp_name)->tpn_ident ? (self->tp_name)->tpn_ident : "" , "")) : (void)0); |
608 | |
609 | return send(self->tp_socket, "\r\n", 2, 0); |
610 | } |
611 | |
612 | /** Calculate next timer for WS. */ |
613 | int tport_ws_next_timer(tport_t *self, |
614 | su_time_t *return_target, |
615 | char const **return_why) |
616 | { |
617 | tport_ws_t *wstp = (tport_ws_t *)self; |
618 | int ll = establish_logical_layer(&wstp->ws); |
619 | int punt = 0; |
620 | |
621 | if (ll == -1) { |
622 | punt = 1; |
623 | } else if (ll < 0) { |
624 | time_t now = time(NULL((void*)0)); |
625 | if (now - wstp->connected > 5) { |
626 | punt = 2; |
627 | } |
628 | } else { |
629 | self->tp_params->tpp_keepalive = 0; |
630 | } |
631 | |
632 | if (punt) { |
633 | tport_close(self); |
634 | |
635 | SU_DEBUG_7(("%s(%p): %s to " TPN_FORMAT "%s\n",(((tport_log != ((void*)0) && tport_log->log_init) == 0 ? 9 : ((tport_log != ((void*)0) && tport_log-> log_init > 1) ? tport_log->log_level : su_log_default-> log_level)) >= 7 ? (_su_llog(tport_log, 7, "tport_type_ws.c" , (const char *)__func__, 637, "%s(%p): %s to " "%s/%s:%s%s%s%s%s" "%s\n", __func__, (void *)self, (punt == 2 ? "Timeout establishing SSL" : "Error establishing SSL"), (self->tp_name)->tpn_proto , (self->tp_name)->tpn_host, (self->tp_name)->tpn_port , (self->tp_name)->tpn_comp ? ";comp=" : "", (self-> tp_name)->tpn_comp ? (self->tp_name)->tpn_comp : "", (self->tp_name)->tpn_ident ? "/" : "", (self->tp_name )->tpn_ident ? (self->tp_name)->tpn_ident : "", "")) : (void)0) |
636 | __func__, (void *)self,(((tport_log != ((void*)0) && tport_log->log_init) == 0 ? 9 : ((tport_log != ((void*)0) && tport_log-> log_init > 1) ? tport_log->log_level : su_log_default-> log_level)) >= 7 ? (_su_llog(tport_log, 7, "tport_type_ws.c" , (const char *)__func__, 637, "%s(%p): %s to " "%s/%s:%s%s%s%s%s" "%s\n", __func__, (void *)self, (punt == 2 ? "Timeout establishing SSL" : "Error establishing SSL"), (self->tp_name)->tpn_proto , (self->tp_name)->tpn_host, (self->tp_name)->tpn_port , (self->tp_name)->tpn_comp ? ";comp=" : "", (self-> tp_name)->tpn_comp ? (self->tp_name)->tpn_comp : "", (self->tp_name)->tpn_ident ? "/" : "", (self->tp_name )->tpn_ident ? (self->tp_name)->tpn_ident : "", "")) : (void)0) |
637 | (punt == 2 ? "Timeout establishing SSL" : "Error establishing SSL"), TPN_ARGS(self->tp_name), ""))(((tport_log != ((void*)0) && tport_log->log_init) == 0 ? 9 : ((tport_log != ((void*)0) && tport_log-> log_init > 1) ? tport_log->log_level : su_log_default-> log_level)) >= 7 ? (_su_llog(tport_log, 7, "tport_type_ws.c" , (const char *)__func__, 637, "%s(%p): %s to " "%s/%s:%s%s%s%s%s" "%s\n", __func__, (void *)self, (punt == 2 ? "Timeout establishing SSL" : "Error establishing SSL"), (self->tp_name)->tpn_proto , (self->tp_name)->tpn_host, (self->tp_name)->tpn_port , (self->tp_name)->tpn_comp ? ";comp=" : "", (self-> tp_name)->tpn_comp ? (self->tp_name)->tpn_comp : "", (self->tp_name)->tpn_ident ? "/" : "", (self->tp_name )->tpn_ident ? (self->tp_name)->tpn_ident : "", "")) : (void)0); |
638 | if (wstp->ws.secure) |
639 | return -1; |
640 | } |
641 | |
642 | |
643 | return |
644 | tport_next_recv_timeout(self, return_target, return_why) | |
645 | tport_next_keepalive(self, return_target, return_why); |
646 | } |
647 | |
648 | /** WS timer. */ |
649 | void tport_ws_timer(tport_t *self, su_time_t now) |
650 | { |
651 | tport_ws_t *wstp = (tport_ws_t *)self; |
652 | |
653 | if (!strcmp("wss", self->tp_protonametp_name->tpn_proto) && !wstp->ws.secure_established) { |
654 | tport_close(self); |
655 | } else { |
656 | tport_recv_timeout_timer(self, now); |
657 | tport_keepalive_timer(self, now); |
658 | } |
659 | tport_base_timer(self, now); |
660 | } |