| 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 | } |