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