Bug Summary

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'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name tport_type_ws.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib/llvm-11/lib/clang/11.0.1 -D HAVE_CONFIG_H -I . -I ../.. -I ../../libsofia-sip-ua/su/sofia-sip -I ./../bnf -I ../bnf -I ./../stun -I ../stun -I ./../ipt -I ../ipt -I ./../msg -I ../msg -I ./../http -I ../http -I ./../url -I ../url -I ./../sip -I ../sip -I ./../su -I ../su -I ./include -D SU_DEBUG=0 -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-11/lib/clang/11.0.1/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir /drone/src/libsofia-sip-ua/tport -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-output=html -faddrsig -o /drone/src/scan-build/2022-06-23-181620-12-1 -x c tport_type_ws.c
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
60static 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
75static 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
81static int tport_ws_setsndbuf(int socket, int atleast);
82static void tport_ws_deinit_primary(tport_primary_t *pri);
83
84tport_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
109tport_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
134tport_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
159tport_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
185static 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 */
203int 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 */
266ssize_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
341static 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
446int 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
464int 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
475int 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
526static 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
537static 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 */
562int 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 */
598int 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. */
613int 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. */
649void 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}