Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 1 | /* |
| 2 | * libwebsockets - small server side websockets and web server implementation |
| 3 | * |
| 4 | * Copyright (C) 2010-2014 Andy Green <andy@warmcat.com> |
| 5 | * |
| 6 | * This library is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU Lesser General Public |
| 8 | * License as published by the Free Software Foundation: |
| 9 | * version 2.1 of the License. |
| 10 | * |
| 11 | * This library is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 14 | * Lesser General Public License for more details. |
| 15 | * |
| 16 | * You should have received a copy of the GNU Lesser General Public |
| 17 | * License along with this library; if not, write to the Free Software |
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
| 19 | * MA 02110-1301 USA |
| 20 | */ |
| 21 | |
| 22 | #include "private-libwebsockets.h" |
| 23 | |
| 24 | int |
Andy Green | 4b85c1d | 2015-12-04 11:08:32 +0800 | [diff] [blame^] | 25 | insert_wsi_socket_into_fds(struct lws_context *context, |
| 26 | struct lws *wsi) |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 27 | { |
Andy Green | 4b85c1d | 2015-12-04 11:08:32 +0800 | [diff] [blame^] | 28 | struct lws_pollargs pa = { wsi->sock, LWS_POLLIN, 0 }; |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 29 | |
| 30 | if (context->fds_count >= context->max_fds) { |
| 31 | lwsl_err("Too many fds (%d)\n", context->max_fds); |
| 32 | return 1; |
| 33 | } |
| 34 | |
Andy Green | 2cd3074 | 2015-11-02 13:10:33 +0800 | [diff] [blame] | 35 | #if !defined(_WIN32) && !defined(MBED_OPERATORS) |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 36 | if (wsi->sock >= context->max_fds) { |
| 37 | lwsl_err("Socket fd %d is too high (%d)\n", |
| 38 | wsi->sock, context->max_fds); |
| 39 | return 1; |
| 40 | } |
Bud Davis | 229bfec | 2015-01-30 10:13:01 +0800 | [diff] [blame] | 41 | #endif |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 42 | |
| 43 | assert(wsi); |
Andy Green | fc772cc | 2015-11-14 13:48:58 +0800 | [diff] [blame] | 44 | assert(lws_socket_is_valid(wsi->sock)); |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 45 | |
Andy Green | 11f2734 | 2015-11-08 12:10:26 +0800 | [diff] [blame] | 46 | // lwsl_info("insert_wsi_socket_into_fds: wsi=%p, sock=%d, fds pos=%d\n", |
| 47 | // wsi, wsi->sock, context->fds_count); |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 48 | |
Andy Green | 1963c9a | 2015-10-15 07:39:33 +0800 | [diff] [blame] | 49 | if (context->protocols[0].callback(context, wsi, |
Andy Green | 5a3b1d3 | 2015-11-20 09:51:18 +0800 | [diff] [blame] | 50 | LWS_CALLBACK_LOCK_POLL, wsi->user_space, (void *) &pa, 1)) |
Andy Green | 1963c9a | 2015-10-15 07:39:33 +0800 | [diff] [blame] | 51 | return -1; |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 52 | |
Bud Davis | 229bfec | 2015-01-30 10:13:01 +0800 | [diff] [blame] | 53 | insert_wsi(context, wsi); |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 54 | wsi->position_in_fds_table = context->fds_count; |
| 55 | context->fds[context->fds_count].fd = wsi->sock; |
| 56 | context->fds[context->fds_count].events = LWS_POLLIN; |
| 57 | |
| 58 | lws_plat_insert_socket_into_fds(context, wsi); |
| 59 | |
| 60 | /* external POLL support via protocol 0 */ |
Andy Green | 1963c9a | 2015-10-15 07:39:33 +0800 | [diff] [blame] | 61 | if (context->protocols[0].callback(context, wsi, |
| 62 | LWS_CALLBACK_ADD_POLL_FD, wsi->user_space, (void *) &pa, 0)) |
| 63 | return -1; |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 64 | |
Andy Green | 1963c9a | 2015-10-15 07:39:33 +0800 | [diff] [blame] | 65 | if (context->protocols[0].callback(context, wsi, |
Andy Green | 5a3b1d3 | 2015-11-20 09:51:18 +0800 | [diff] [blame] | 66 | LWS_CALLBACK_UNLOCK_POLL, wsi->user_space, (void *)&pa, 1)) |
Andy Green | 1963c9a | 2015-10-15 07:39:33 +0800 | [diff] [blame] | 67 | return -1; |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 68 | |
| 69 | return 0; |
| 70 | } |
| 71 | |
| 72 | int |
Andy Green | 4b85c1d | 2015-12-04 11:08:32 +0800 | [diff] [blame^] | 73 | remove_wsi_socket_from_fds(struct lws_context *context, |
| 74 | struct lws *wsi) |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 75 | { |
| 76 | int m; |
Andy Green | 4b85c1d | 2015-12-04 11:08:32 +0800 | [diff] [blame^] | 77 | struct lws_pollargs pa = { wsi->sock, 0, 0 }; |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 78 | |
Andy Green | a717df2 | 2014-04-11 13:14:37 +0800 | [diff] [blame] | 79 | lws_libev_io(context, wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE); |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 80 | |
Joe Kilner | ba8a2f0 | 2015-04-21 10:41:36 +0100 | [diff] [blame] | 81 | --context->fds_count; |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 82 | |
Andy Green | 8c0d3c0 | 2015-11-02 20:34:12 +0800 | [diff] [blame] | 83 | #if !defined(_WIN32) && !defined(MBED_OPERATORS) |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 84 | if (wsi->sock > context->max_fds) { |
| 85 | lwsl_err("Socket fd %d too high (%d)\n", |
| 86 | wsi->sock, context->max_fds); |
| 87 | return 1; |
| 88 | } |
bdavis | 353fdc3 | 2015-10-13 19:54:57 -0500 | [diff] [blame] | 89 | #endif |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 90 | |
| 91 | lwsl_info("%s: wsi=%p, sock=%d, fds pos=%d\n", __func__, |
| 92 | wsi, wsi->sock, wsi->position_in_fds_table); |
| 93 | |
Andy Green | 1963c9a | 2015-10-15 07:39:33 +0800 | [diff] [blame] | 94 | if (context->protocols[0].callback(context, wsi, |
Andy Green | 5a3b1d3 | 2015-11-20 09:51:18 +0800 | [diff] [blame] | 95 | LWS_CALLBACK_LOCK_POLL, wsi->user_space, (void *)&pa, 1)) |
Andy Green | 1963c9a | 2015-10-15 07:39:33 +0800 | [diff] [blame] | 96 | return -1; |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 97 | |
| 98 | m = wsi->position_in_fds_table; /* replace the contents for this */ |
| 99 | |
| 100 | /* have the last guy take up the vacant slot */ |
| 101 | context->fds[m] = context->fds[context->fds_count]; |
| 102 | |
| 103 | lws_plat_delete_socket_from_fds(context, wsi, m); |
| 104 | |
| 105 | /* |
| 106 | * end guy's fds_lookup entry remains unchanged |
| 107 | * (still same fd pointing to same wsi) |
| 108 | */ |
| 109 | /* end guy's "position in fds table" changed */ |
Bud Davis | 229bfec | 2015-01-30 10:13:01 +0800 | [diff] [blame] | 110 | wsi_from_fd(context,context->fds[context->fds_count].fd)-> |
| 111 | position_in_fds_table = m; |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 112 | /* deletion guy's lws_lookup entry needs nuking */ |
Bud Davis | 229bfec | 2015-01-30 10:13:01 +0800 | [diff] [blame] | 113 | delete_from_fd(context,wsi->sock); |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 114 | /* removed wsi has no position any more */ |
| 115 | wsi->position_in_fds_table = -1; |
| 116 | |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 117 | /* remove also from external POLL support via protocol 0 */ |
Andy Green | fc772cc | 2015-11-14 13:48:58 +0800 | [diff] [blame] | 118 | if (lws_socket_is_valid(wsi->sock)) { |
Andy Green | 1963c9a | 2015-10-15 07:39:33 +0800 | [diff] [blame] | 119 | if (context->protocols[0].callback(context, wsi, |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 120 | LWS_CALLBACK_DEL_POLL_FD, wsi->user_space, |
Andy Green | 1963c9a | 2015-10-15 07:39:33 +0800 | [diff] [blame] | 121 | (void *) &pa, 0)) |
| 122 | return -1; |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 123 | } |
Andy Green | 1963c9a | 2015-10-15 07:39:33 +0800 | [diff] [blame] | 124 | if (context->protocols[0].callback(context, wsi, |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 125 | LWS_CALLBACK_UNLOCK_POLL, |
Andy Green | 5a3b1d3 | 2015-11-20 09:51:18 +0800 | [diff] [blame] | 126 | wsi->user_space, (void *) &pa, 1)) |
Andy Green | 1963c9a | 2015-10-15 07:39:33 +0800 | [diff] [blame] | 127 | return -1; |
| 128 | |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 129 | return 0; |
| 130 | } |
| 131 | |
| 132 | int |
Andy Green | 4b85c1d | 2015-12-04 11:08:32 +0800 | [diff] [blame^] | 133 | lws_change_pollfd(struct lws *wsi, int _and, int _or) |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 134 | { |
Andy Green | 4b85c1d | 2015-12-04 11:08:32 +0800 | [diff] [blame^] | 135 | struct lws_context *context; |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 136 | int tid; |
| 137 | int sampled_tid; |
Andy Green | 4b85c1d | 2015-12-04 11:08:32 +0800 | [diff] [blame^] | 138 | struct lws_pollfd *pfd; |
| 139 | struct lws_pollargs pa; |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 140 | |
Andy Green | 4edb452 | 2014-12-15 15:08:13 +0800 | [diff] [blame] | 141 | if (!wsi || !wsi->protocol || wsi->position_in_fds_table < 0) |
| 142 | return 1; |
| 143 | |
| 144 | context = wsi->protocol->owning_server; |
| 145 | if (!context) |
| 146 | return 1; |
| 147 | |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 148 | pfd = &context->fds[wsi->position_in_fds_table]; |
| 149 | pa.fd = wsi->sock; |
| 150 | |
Andy Green | 1963c9a | 2015-10-15 07:39:33 +0800 | [diff] [blame] | 151 | if (context->protocols[0].callback(context, wsi, |
| 152 | LWS_CALLBACK_LOCK_POLL, wsi->user_space, (void *) &pa, 0)) |
| 153 | return -1; |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 154 | |
| 155 | pa.prev_events = pfd->events; |
| 156 | pa.events = pfd->events = (pfd->events & ~_and) | _or; |
| 157 | |
Andy Green | 1963c9a | 2015-10-15 07:39:33 +0800 | [diff] [blame] | 158 | if (context->protocols[0].callback(context, wsi, |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 159 | LWS_CALLBACK_CHANGE_MODE_POLL_FD, |
Andy Green | 1963c9a | 2015-10-15 07:39:33 +0800 | [diff] [blame] | 160 | wsi->user_space, (void *) &pa, 0)) |
| 161 | return -1; |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 162 | |
| 163 | /* |
| 164 | * if we changed something in this pollfd... |
| 165 | * ... and we're running in a different thread context |
| 166 | * than the service thread... |
| 167 | * ... and the service thread is waiting ... |
| 168 | * then cancel it to force a restart with our changed events |
| 169 | */ |
Andy Green | 87eeb0a | 2015-11-25 08:22:08 +0800 | [diff] [blame] | 170 | #if LWS_POSIX |
| 171 | if (pa.prev_events != pa.events) |
| 172 | #endif |
| 173 | { |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 174 | |
Andy Green | a717df2 | 2014-04-11 13:14:37 +0800 | [diff] [blame] | 175 | if (lws_plat_change_pollfd(context, wsi, pfd)) { |
| 176 | lwsl_info("%s failed\n", __func__); |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 177 | return 1; |
Andy Green | a717df2 | 2014-04-11 13:14:37 +0800 | [diff] [blame] | 178 | } |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 179 | |
| 180 | sampled_tid = context->service_tid; |
| 181 | if (sampled_tid) { |
| 182 | tid = context->protocols[0].callback(context, NULL, |
| 183 | LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0); |
Andy Green | 1963c9a | 2015-10-15 07:39:33 +0800 | [diff] [blame] | 184 | if (tid == -1) |
| 185 | return -1; |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 186 | if (tid != sampled_tid) |
Andy Green | 6230476 | 2015-12-04 08:43:54 +0800 | [diff] [blame] | 187 | lws_cancel_service(context); |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 188 | } |
| 189 | } |
| 190 | |
Andy Green | 1963c9a | 2015-10-15 07:39:33 +0800 | [diff] [blame] | 191 | if (context->protocols[0].callback(context, wsi, |
| 192 | LWS_CALLBACK_UNLOCK_POLL, wsi->user_space, (void *) &pa, 0)) |
| 193 | return -1; |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 194 | |
| 195 | return 0; |
| 196 | } |
| 197 | |
| 198 | |
| 199 | /** |
Andy Green | 6230476 | 2015-12-04 08:43:54 +0800 | [diff] [blame] | 200 | * lws_callback_on_writable() - Request a callback when this socket |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 201 | * becomes able to be written to without |
| 202 | * blocking |
| 203 | * |
| 204 | * @context: libwebsockets context |
| 205 | * @wsi: Websocket connection instance to get callback for |
| 206 | */ |
| 207 | |
| 208 | LWS_VISIBLE int |
Andy Green | 4b85c1d | 2015-12-04 11:08:32 +0800 | [diff] [blame^] | 209 | lws_callback_on_writable(struct lws_context *context, |
| 210 | struct lws *wsi) |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 211 | { |
Andy Green | 7df53c5 | 2014-10-22 15:37:28 +0800 | [diff] [blame] | 212 | #ifdef LWS_USE_HTTP2 |
Andy Green | 4b85c1d | 2015-12-04 11:08:32 +0800 | [diff] [blame^] | 213 | struct lws *network_wsi, *wsi2; |
Andy Green | 7df53c5 | 2014-10-22 15:37:28 +0800 | [diff] [blame] | 214 | int already; |
| 215 | |
| 216 | lwsl_info("%s: %p\n", __func__, wsi); |
| 217 | |
| 218 | if (wsi->mode != LWS_CONNMODE_HTTP2_SERVING) |
| 219 | goto network_sock; |
| 220 | |
| 221 | if (wsi->u.http2.requested_POLLOUT) { |
| 222 | lwsl_info("already pending writable\n"); |
| 223 | return 1; |
| 224 | } |
| 225 | |
Andy Green | 97ee57f | 2014-10-29 09:39:08 +0800 | [diff] [blame] | 226 | if (wsi->u.http2.tx_credit <= 0) { |
| 227 | /* |
| 228 | * other side is not able to cope with us sending |
| 229 | * anything so no matter if we have POLLOUT on our side. |
| 230 | * |
| 231 | * Delay waiting for our POLLOUT until peer indicates he has |
| 232 | * space for more using tx window command in http2 layer |
| 233 | */ |
| 234 | lwsl_info("%s: %p: waiting_tx_credit (%d)\n", __func__, wsi, wsi->u.http2.tx_credit); |
| 235 | wsi->u.http2.waiting_tx_credit = 1; |
| 236 | return 0; |
| 237 | } |
| 238 | |
Andy Green | 7df53c5 | 2014-10-22 15:37:28 +0800 | [diff] [blame] | 239 | network_wsi = lws_http2_get_network_wsi(wsi); |
| 240 | already = network_wsi->u.http2.requested_POLLOUT; |
| 241 | |
| 242 | /* mark everybody above him as requesting pollout */ |
| 243 | |
| 244 | wsi2 = wsi; |
| 245 | while (wsi2) { |
| 246 | wsi2->u.http2.requested_POLLOUT = 1; |
| 247 | lwsl_info("mark %p pending writable\n", wsi2); |
| 248 | wsi2 = wsi2->u.http2.parent_wsi; |
| 249 | } |
| 250 | |
| 251 | /* for network action, act only on the network wsi */ |
| 252 | |
| 253 | wsi = network_wsi; |
| 254 | if (already) |
| 255 | return 1; |
| 256 | network_sock: |
| 257 | #endif |
| 258 | |
Andy Green | 8c0d3c0 | 2015-11-02 20:34:12 +0800 | [diff] [blame] | 259 | (void)context; |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 260 | if (lws_ext_callback_for_each_active(wsi, |
| 261 | LWS_EXT_CALLBACK_REQUEST_ON_WRITEABLE, NULL, 0)) |
| 262 | return 1; |
| 263 | |
| 264 | if (wsi->position_in_fds_table < 0) { |
| 265 | lwsl_err("%s: failed to find socket %d\n", __func__, wsi->sock); |
| 266 | return -1; |
| 267 | } |
| 268 | |
| 269 | if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) |
| 270 | return -1; |
| 271 | |
Andy Green | a717df2 | 2014-04-11 13:14:37 +0800 | [diff] [blame] | 272 | lws_libev_io(context, wsi, LWS_EV_START | LWS_EV_WRITE); |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 273 | |
| 274 | return 1; |
| 275 | } |
| 276 | |
| 277 | /** |
Andy Green | 6230476 | 2015-12-04 08:43:54 +0800 | [diff] [blame] | 278 | * lws_callback_on_writable_all_protocol() - Request a callback for |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 279 | * all connections using the given protocol when it |
| 280 | * becomes possible to write to each socket without |
| 281 | * blocking in turn. |
| 282 | * |
| 283 | * @protocol: Protocol whose connections will get callbacks |
| 284 | */ |
| 285 | |
| 286 | LWS_VISIBLE int |
Andy Green | 6230476 | 2015-12-04 08:43:54 +0800 | [diff] [blame] | 287 | lws_callback_on_writable_all_protocol( |
Andy Green | 4b85c1d | 2015-12-04 11:08:32 +0800 | [diff] [blame^] | 288 | const struct lws_protocols *protocol) |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 289 | { |
Andy Green | 4b85c1d | 2015-12-04 11:08:32 +0800 | [diff] [blame^] | 290 | struct lws_context *context = protocol->owning_server; |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 291 | int n; |
Andy Green | 4b85c1d | 2015-12-04 11:08:32 +0800 | [diff] [blame^] | 292 | struct lws *wsi; |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 293 | |
| 294 | for (n = 0; n < context->fds_count; n++) { |
Bud Davis | 229bfec | 2015-01-30 10:13:01 +0800 | [diff] [blame] | 295 | wsi = wsi_from_fd(context,context->fds[n].fd); |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 296 | if (!wsi) |
| 297 | continue; |
| 298 | if (wsi->protocol == protocol) |
Andy Green | 6230476 | 2015-12-04 08:43:54 +0800 | [diff] [blame] | 299 | lws_callback_on_writable(context, wsi); |
Andy Green | 34f3dd2 | 2014-04-03 07:42:50 +0800 | [diff] [blame] | 300 | } |
| 301 | |
| 302 | return 0; |
| 303 | } |