1/* 2 * libwebsockets - small server side websockets and web server implementation 3 * 4 * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com> 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to 8 * deal in the Software without restriction, including without limitation the 9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 * sell copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 * IN THE SOFTWARE. 23 */ 24 25#if !defined(_GNU_SOURCE) 26#define _GNU_SOURCE 27#endif 28#include "private-lib-core.h" 29 30struct lws * 31wsi_from_fd(const struct lws_context *context, int fd) 32{ 33 struct lws **p, **done; 34 35 if (!context->max_fds_unrelated_to_ulimit) 36 return context->lws_lookup[fd - lws_plat_socket_offset()]; 37 38 /* slow fds handling */ 39 40 p = context->lws_lookup; 41 done = &p[context->max_fds]; 42 43 while (p != done) { 44 if (*p && (*p)->desc.sockfd == fd) 45 return *p; 46 p++; 47 } 48 49 return NULL; 50} 51 52#if defined(_DEBUG) 53int 54sanity_assert_no_wsi_traces(const struct lws_context *context, struct lws *wsi) 55{ 56 struct lws **p, **done; 57 58 if (!context->max_fds_unrelated_to_ulimit) 59 /* can't tell */ 60 return 0; 61 62 /* slow fds handling */ 63 64 p = context->lws_lookup; 65 done = &p[context->max_fds]; 66 67 /* confirm the wsi doesn't already exist */ 68 69 while (p != done && *p != wsi) 70 p++; 71 72 if (p == done) 73 return 0; 74 75 assert(0); /* this wsi is still mentioned inside lws */ 76 77 return 1; 78} 79 80int 81sanity_assert_no_sockfd_traces(const struct lws_context *context, 82 lws_sockfd_type sfd) 83{ 84#if LWS_MAX_SMP > 1 85 /* 86 * We can't really do this test... another thread can accept and 87 * reuse the closed fd 88 */ 89 return 0; 90#else 91 struct lws **p, **done; 92 93 if (sfd == LWS_SOCK_INVALID || !context->lws_lookup) 94 return 0; 95 96 if (!context->max_fds_unrelated_to_ulimit && 97 context->lws_lookup[sfd - lws_plat_socket_offset()]) { 98 assert(0); /* the fd is still in use */ 99 return 1; 100 } 101 102 /* slow fds handling */ 103 104 p = context->lws_lookup; 105 done = &p[context->max_fds]; 106 107 /* confirm the sfd not already in use */ 108 109 while (p != done && (!*p || (*p)->desc.sockfd != sfd)) 110 p++; 111 112 if (p == done) 113 return 0; 114 115 assert(0); /* this fd is still in the tables */ 116 117 return 1; 118#endif 119} 120#endif 121 122 123int 124insert_wsi(const struct lws_context *context, struct lws *wsi) 125{ 126 struct lws **p, **done; 127 128 if (sanity_assert_no_wsi_traces(context, wsi)) 129 return 0; 130 131 if (!context->max_fds_unrelated_to_ulimit) { 132 assert(context->lws_lookup[wsi->desc.sockfd - 133 lws_plat_socket_offset()] == 0); 134 135 context->lws_lookup[wsi->desc.sockfd - \ 136 lws_plat_socket_offset()] = wsi; 137 138 return 0; 139 } 140 141 /* slow fds handling */ 142 143 p = context->lws_lookup; 144 done = &p[context->max_fds]; 145 146 /* confirm fd isn't already in use by a wsi */ 147 148 if (sanity_assert_no_sockfd_traces(context, wsi->desc.sockfd)) 149 return 0; 150 151 p = context->lws_lookup; 152 153 /* find an empty slot */ 154 155 while (p != done && *p) 156 p++; 157 158 if (p == done) { 159 lwsl_err("%s: reached max fds\n", __func__); 160 return 1; 161 } 162 163 *p = wsi; 164 165 return 0; 166} 167 168 169 170void 171delete_from_fd(const struct lws_context *context, int fd) 172{ 173 174 struct lws **p, **done; 175 176 if (!context->max_fds_unrelated_to_ulimit) { 177 if (context->lws_lookup) 178 context->lws_lookup[fd - lws_plat_socket_offset()] = NULL; 179 180 return; 181 } 182 183 /* slow fds handling */ 184 185 p = context->lws_lookup; 186 assert(p); 187 188 done = &p[context->max_fds]; 189 190 /* find the match */ 191 192 while (p != done && (!*p || (*p)->desc.sockfd != fd)) 193 p++; 194 195 if (p != done) 196 *p = NULL; 197 198#if defined(_DEBUG) 199 p = context->lws_lookup; 200 while (p != done && (!*p || (*p)->desc.sockfd != fd)) 201 p++; 202 203 if (p != done) { 204 lwsl_err("%s: fd %d in lws_lookup again at %d\n", __func__, 205 fd, (int)(p - context->lws_lookup)); 206 assert(0); 207 } 208#endif 209} 210 211void 212delete_from_fdwsi(const struct lws_context *context, struct lws *wsi) 213{ 214 215 struct lws **p, **done; 216 217 if (!context->max_fds_unrelated_to_ulimit) 218 return; 219 220 221 /* slow fds handling */ 222 223 p = context->lws_lookup; 224 done = &p[context->max_fds]; 225 226 /* find the match */ 227 228 while (p != done && (!*p || (*p) != wsi)) 229 p++; 230 231 if (p != done) 232 *p = NULL; 233} 234 235void 236lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi) 237{ 238 struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; 239 240 if (context->event_loop_ops->io) 241 context->event_loop_ops->io(wsi, LWS_EV_START | LWS_EV_READ); 242 243 pt->fds[pt->fds_count++].revents = 0; 244} 245 246void 247lws_plat_delete_socket_from_fds(struct lws_context *context, 248 struct lws *wsi, int m) 249{ 250 struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; 251 252 if (context->event_loop_ops->io) 253 context->event_loop_ops->io(wsi, 254 LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE); 255 256 pt->fds_count--; 257} 258 259int 260lws_plat_change_pollfd(struct lws_context *context, 261 struct lws *wsi, struct lws_pollfd *pfd) 262{ 263 return 0; 264} 265