_ZN3uWS12TemplatedAppILb0EEC2ENS_20SocketContextOptionsE: 217| 5.84k| TemplatedApp(SocketContextOptions options = {}) { 218| 5.84k| httpContext = HttpContext::create(Loop::get(), options); 219| | 220| | /* Register default handler for 404 (can be overridden by user) */ 221| 5.84k| this->any("/*", [](auto *res, auto */*req*/) { 222| 5.84k| res->writeStatus("404 File Not Found"); 223| 5.84k| res->end("

File Not Found


uWebSockets/20 Server"); 224| 5.84k| }); 225| 5.84k| } _ZNK3uWS20SocketContextOptionscv27us_socket_context_options_tEv: 71| 5.84k| operator struct us_socket_context_options_t() const { 72| 5.84k| struct us_socket_context_options_t socket_context_options; 73| 5.84k| memcpy(&socket_context_options, this, sizeof(SocketContextOptions)); 74| 5.84k| return socket_context_options; 75| 5.84k| } _ZN3uWS12TemplatedAppILb0EE3anyENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEON5ofats13any_invocableIFvPNS_12HttpResponseILb0EEEPNS_11HttpRequestEEEE: 529| 5.84k| TemplatedApp &&any(std::string pattern, MoveOnlyFunction *, HttpRequest *)> &&handler) { 530| 5.84k| if (httpContext) { ------------------ | Branch (530:13): [True: 5.84k, False: 0] ------------------ 531| 5.84k| httpContext->onHttp("*", pattern, std::move(handler)); 532| 5.84k| } 533| 5.84k| return std::move(*this); 534| 5.84k| } _ZZN3uWS12TemplatedAppILb0EEC1ENS_20SocketContextOptionsEENKUlPT_PT0_E_clINS_12HttpResponseILb0EEENS_11HttpRequestEEEDaS4_S6_: 221| 7.55k| this->any("/*", [](auto *res, auto */*req*/) { 222| 7.55k| res->writeStatus("404 File Not Found"); 223| 7.55k| res->end("

File Not Found


uWebSockets/20 Server"); 224| 7.55k| }); _ZN3uWS12TemplatedAppILb0EED2Ev: 177| 11.6k| ~TemplatedApp() { 178| | /* Let's just put everything here */ 179| 11.6k| if (httpContext) { ------------------ | Branch (179:13): [True: 5.84k, False: 5.84k] ------------------ 180| 5.84k| httpContext->free(); 181| | 182| | /* Free all our webSocketContexts in a type less way */ 183| 11.6k| for (auto &webSocketContextDeleter : webSocketContextDeleters) { ------------------ | Branch (183:48): [True: 11.6k, False: 5.84k] ------------------ 184| 11.6k| webSocketContextDeleter(); 185| 11.6k| } 186| 5.84k| } 187| | 188| | /* Delete TopicTree */ 189| 11.6k| if (topicTree) { ------------------ | Branch (189:13): [True: 5.84k, False: 5.84k] ------------------ 190| 5.84k| delete topicTree; 191| | 192| | /* And unregister loop callbacks */ 193| | /* We must unregister any loop post handler here */ 194| 5.84k| Loop::get()->removePostHandler(topicTree); 195| 5.84k| Loop::get()->removePreHandler(topicTree); 196| 5.84k| } 197| 11.6k| } EpollEchoServer.cpp:_ZN3uWS12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOS1_NSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEEONS1_17WebSocketBehaviorIT_EE: 270| 11.6k| TemplatedApp &&ws(std::string pattern, WebSocketBehavior &&behavior) { 271| | /* Don't compile if alignment rules cannot be satisfied */ 272| 11.6k| static_assert(alignof(UserData) <= LIBUS_EXT_ALIGNMENT, 273| 11.6k| "µWebSockets cannot satisfy UserData alignment requirements. You need to recompile µSockets with LIBUS_EXT_ALIGNMENT adjusted accordingly."); 274| | 275| 11.6k| if (!httpContext) { ------------------ | Branch (275:13): [True: 0, False: 11.6k] ------------------ 276| 0| return std::move(*this); 277| 0| } 278| | 279| | /* Terminate on misleading idleTimeout values */ 280| 11.6k| if (behavior.idleTimeout && behavior.idleTimeout < 8) { ------------------ | Branch (280:13): [True: 11.6k, False: 0] | Branch (280:37): [True: 0, False: 11.6k] ------------------ 281| 0| std::cerr << "Error: idleTimeout must be either 0 or greater than 8!" << std::endl; 282| 0| std::terminate(); 283| 0| } 284| | 285| | /* Maximum idleTimeout is 16 minutes */ 286| 11.6k| if (behavior.idleTimeout > 240 * 4) { ------------------ | Branch (286:13): [True: 0, False: 11.6k] ------------------ 287| 0| std::cerr << "Error: idleTimeout must not be greater than 960 seconds!" << std::endl; 288| 0| std::terminate(); 289| 0| } 290| | 291| | /* Maximum maxLifetime is 4 hours */ 292| 11.6k| if (behavior.maxLifetime > 240) { ------------------ | Branch (292:13): [True: 0, False: 11.6k] ------------------ 293| 0| std::cerr << "Error: maxLifetime must not be greater than 240 minutes!" << std::endl; 294| 0| std::terminate(); 295| 0| } 296| | 297| | /* If we don't have a TopicTree yet, create one now */ 298| 11.6k| if (!topicTree) { ------------------ | Branch (298:13): [True: 5.84k, False: 5.84k] ------------------ 299| | 300| 5.84k| bool needsUncork = false; 301| 5.84k| topicTree = new TopicTree([needsUncork](Subscriber *s, TopicTreeMessage &message, TopicTree::IteratorFlags flags) mutable { 302| | /* Subscriber's user is the socket */ 303| | /* Unfortunately we need to cast is to PerSocketData = int 304| | * since many different WebSocketContexts use the same 305| | * TopicTree now */ 306| 5.84k| auto *ws = (WebSocket *) s->user; 307| | 308| | /* If this is the first message we try and cork */ 309| 5.84k| if (flags & TopicTree::IteratorFlags::FIRST) { 310| 5.84k| if (ws->canCork() && !ws->isCorked()) { 311| 5.84k| ((AsyncSocket *)ws)->cork(); 312| 5.84k| needsUncork = true; 313| 5.84k| } 314| 5.84k| } 315| | 316| | /* If we ever overstep maxBackpresure, exit immediately */ 317| 5.84k| if (WebSocket::SendStatus::DROPPED == ws->send(message.message, (OpCode)message.opCode, message.compress)) { 318| 5.84k| if (needsUncork) { 319| 5.84k| ((AsyncSocket *)ws)->uncork(); 320| 5.84k| needsUncork = false; 321| 5.84k| } 322| | /* Stop draining */ 323| 5.84k| return true; 324| 5.84k| } 325| | 326| | /* If this is the last message we uncork if we are corked */ 327| 5.84k| if (flags & TopicTree::IteratorFlags::LAST) { 328| | /* We should not uncork in all cases? */ 329| 5.84k| if (needsUncork) { 330| 5.84k| ((AsyncSocket *)ws)->uncork(); 331| 5.84k| } 332| 5.84k| } 333| | 334| | /* Success */ 335| 5.84k| return false; 336| 5.84k| }); 337| | 338| | /* And hook it up with the loop */ 339| | /* We empty for both pre and post just to make sure */ 340| 5.84k| Loop::get()->addPostHandler(topicTree, [topicTree = topicTree](Loop */*loop*/) { 341| | /* Commit pub/sub batches every loop iteration */ 342| 5.84k| topicTree->drain(); 343| 5.84k| }); 344| | 345| 5.84k| Loop::get()->addPreHandler(topicTree, [topicTree = topicTree](Loop */*loop*/) { 346| | /* Commit pub/sub batches every loop iteration */ 347| 5.84k| topicTree->drain(); 348| 5.84k| }); 349| 5.84k| } 350| | 351| | /* Every route has its own websocket context with its own behavior and user data type */ 352| 11.6k| auto *webSocketContext = WebSocketContext::create(Loop::get(), (us_socket_context_t *) httpContext, topicTree); 353| | 354| | /* We need to clear this later on */ 355| 11.6k| webSocketContextDeleters.push_back([webSocketContext]() { 356| 11.6k| webSocketContext->free(); 357| 11.6k| }); 358| | 359| | /* We also keep this list for easy closing */ 360| 11.6k| webSocketContexts.push_back((void *)webSocketContext); 361| | 362| | /* Quick fix to disable any compression if set */ 363| |#ifdef UWS_NO_ZLIB 364| | behavior.compression = DISABLED; 365| |#endif 366| | 367| | /* If we are the first one to use compression, initialize it */ 368| 11.6k| if (behavior.compression) { ------------------ | Branch (368:13): [True: 11.1k, False: 574] ------------------ 369| 11.1k| LoopData *loopData = (LoopData *) us_loop_ext(us_socket_context_loop(SSL, webSocketContext->getSocketContext())); 370| | 371| | /* Initialize loop's deflate inflate streams */ 372| 11.1k| if (!loopData->zlibContext) { ------------------ | Branch (372:17): [True: 5.56k, False: 5.56k] ------------------ 373| 5.56k| loopData->zlibContext = new ZlibContext; 374| 5.56k| loopData->inflationStream = new InflationStream(CompressOptions::DEDICATED_DECOMPRESSOR); 375| 5.56k| loopData->deflationStream = new DeflationStream(CompressOptions::DEDICATED_COMPRESSOR); 376| 5.56k| } 377| 11.1k| } 378| | 379| | /* Copy all handlers */ 380| 11.6k| webSocketContext->getExt()->openHandler = std::move(behavior.open); 381| 11.6k| webSocketContext->getExt()->messageHandler = std::move(behavior.message); 382| 11.6k| webSocketContext->getExt()->droppedHandler = std::move(behavior.dropped); 383| 11.6k| webSocketContext->getExt()->drainHandler = std::move(behavior.drain); 384| 11.6k| webSocketContext->getExt()->subscriptionHandler = std::move(behavior.subscription); 385| 11.6k| webSocketContext->getExt()->closeHandler = std::move([closeHandler = std::move(behavior.close)](WebSocket *ws, int code, std::string_view message) mutable { 386| 11.6k| if (closeHandler) { 387| 11.6k| closeHandler(ws, code, message); 388| 11.6k| } 389| | 390| | /* Destruct user data after returning from close handler */ 391| 11.6k| ((UserData *) ws->getUserData())->~UserData(); 392| 11.6k| }); 393| 11.6k| webSocketContext->getExt()->pingHandler = std::move(behavior.ping); 394| 11.6k| webSocketContext->getExt()->pongHandler = std::move(behavior.pong); 395| | 396| | /* Copy settings */ 397| 11.6k| webSocketContext->getExt()->maxPayloadLength = behavior.maxPayloadLength; 398| 11.6k| webSocketContext->getExt()->maxBackpressure = behavior.maxBackpressure; 399| 11.6k| webSocketContext->getExt()->closeOnBackpressureLimit = behavior.closeOnBackpressureLimit; 400| 11.6k| webSocketContext->getExt()->resetIdleTimeoutOnSend = behavior.resetIdleTimeoutOnSend; 401| 11.6k| webSocketContext->getExt()->sendPingsAutomatically = behavior.sendPingsAutomatically; 402| 11.6k| webSocketContext->getExt()->maxLifetime = behavior.maxLifetime; 403| 11.6k| webSocketContext->getExt()->compression = behavior.compression; 404| | 405| | /* Calculate idleTimeoutCompnents */ 406| 11.6k| webSocketContext->getExt()->calculateIdleTimeoutCompnents(behavior.idleTimeout); 407| | 408| 11.6k| httpContext->onHttp("GET", pattern, [webSocketContext, behavior = std::move(behavior)](auto *res, auto *req) mutable { 409| | 410| | /* If we have this header set, it's a websocket */ 411| 11.6k| std::string_view secWebSocketKey = req->getHeader("sec-websocket-key"); 412| 11.6k| if (secWebSocketKey.length() == 24) { 413| | 414| | /* Emit upgrade handler */ 415| 11.6k| if (behavior.upgrade) { 416| | 417| | /* Nasty, ugly Safari 15 hack */ 418| 11.6k| if (hasBrokenCompression(req->getHeader("user-agent"))) { 419| 11.6k| std::string_view secWebSocketExtensions = req->getHeader("sec-websocket-extensions"); 420| 11.6k| memset((void *) secWebSocketExtensions.data(), ' ', secWebSocketExtensions.length()); 421| 11.6k| } 422| | 423| 11.6k| behavior.upgrade(res, req, (struct us_socket_context_t *) webSocketContext); 424| 11.6k| } else { 425| | /* Default handler upgrades to WebSocket */ 426| 11.6k| std::string_view secWebSocketProtocol = req->getHeader("sec-websocket-protocol"); 427| 11.6k| std::string_view secWebSocketExtensions = req->getHeader("sec-websocket-extensions"); 428| | 429| | /* Safari 15 hack */ 430| 11.6k| if (hasBrokenCompression(req->getHeader("user-agent"))) { 431| 11.6k| secWebSocketExtensions = ""; 432| 11.6k| } 433| | 434| 11.6k| res->template upgrade({}, secWebSocketKey, secWebSocketProtocol, secWebSocketExtensions, (struct us_socket_context_t *) webSocketContext); 435| 11.6k| } 436| | 437| | /* We are going to get uncorked by the Http get return */ 438| | 439| | /* We do not need to check for any close or shutdown here as we immediately return from get handler */ 440| | 441| 11.6k| } else { 442| | /* Tell the router that we did not handle this request */ 443| 11.6k| req->setYield(true); 444| 11.6k| } 445| 11.6k| }, true); 446| 11.6k| return std::move(*this); 447| 11.6k| } EpollEchoServer.cpp:_ZZN3uWS12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOS1_NSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEEONS1_17WebSocketBehaviorIT_EEENUlPNS_10SubscriberERNS_16TopicTreeMessageENS_9TopicTreeISI_NS_19TopicTreeBigMessageEE13IteratorFlagsEE_clESH_SJ_SN_: 301| 34.2k| topicTree = new TopicTree([needsUncork](Subscriber *s, TopicTreeMessage &message, TopicTree::IteratorFlags flags) mutable { 302| | /* Subscriber's user is the socket */ 303| | /* Unfortunately we need to cast is to PerSocketData = int 304| | * since many different WebSocketContexts use the same 305| | * TopicTree now */ 306| 34.2k| auto *ws = (WebSocket *) s->user; 307| | 308| | /* If this is the first message we try and cork */ 309| 34.2k| if (flags & TopicTree::IteratorFlags::FIRST) { ------------------ | Branch (309:21): [True: 4.99k, False: 29.2k] ------------------ 310| 4.99k| if (ws->canCork() && !ws->isCorked()) { ------------------ | Branch (310:25): [True: 2.59k, False: 2.39k] | Branch (310:42): [True: 2.59k, False: 0] ------------------ 311| 2.59k| ((AsyncSocket *)ws)->cork(); 312| 2.59k| needsUncork = true; 313| 2.59k| } 314| 4.99k| } 315| | 316| | /* If we ever overstep maxBackpresure, exit immediately */ 317| 34.2k| if (WebSocket::SendStatus::DROPPED == ws->send(message.message, (OpCode)message.opCode, message.compress)) { ------------------ | Branch (317:21): [True: 0, False: 34.2k] ------------------ 318| 0| if (needsUncork) { ------------------ | Branch (318:25): [True: 0, False: 0] ------------------ 319| 0| ((AsyncSocket *)ws)->uncork(); 320| 0| needsUncork = false; 321| 0| } 322| | /* Stop draining */ 323| 0| return true; 324| 0| } 325| | 326| | /* If this is the last message we uncork if we are corked */ 327| 34.2k| if (flags & TopicTree::IteratorFlags::LAST) { ------------------ | Branch (327:21): [True: 4.99k, False: 29.2k] ------------------ 328| | /* We should not uncork in all cases? */ 329| 4.99k| if (needsUncork) { ------------------ | Branch (329:25): [True: 3.75k, False: 1.23k] ------------------ 330| 3.75k| ((AsyncSocket *)ws)->uncork(); 331| 3.75k| } 332| 4.99k| } 333| | 334| | /* Success */ 335| 34.2k| return false; 336| 34.2k| }); EpollEchoServer.cpp:_ZZN3uWS12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOS1_NSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEEONS1_17WebSocketBehaviorIT_EEENKUlPNS_4LoopEE_clESH_: 340| 2.18M| Loop::get()->addPostHandler(topicTree, [topicTree = topicTree](Loop */*loop*/) { 341| | /* Commit pub/sub batches every loop iteration */ 342| 2.18M| topicTree->drain(); 343| 2.18M| }); EpollEchoServer.cpp:_ZZN3uWS12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOS1_NSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEEONS1_17WebSocketBehaviorIT_EEENKUlPNS_4LoopEE0_clESH_: 345| 2.18M| Loop::get()->addPreHandler(topicTree, [topicTree = topicTree](Loop */*loop*/) { 346| | /* Commit pub/sub batches every loop iteration */ 347| 2.18M| topicTree->drain(); 348| 2.18M| }); EpollEchoServer.cpp:_ZZN3uWS12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOS1_NSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEEONS1_17WebSocketBehaviorIT_EEENKUlvE_clEv: 355| 11.6k| webSocketContextDeleters.push_back([webSocketContext]() { 356| 11.6k| webSocketContext->free(); 357| 11.6k| }); EpollEchoServer.cpp:_ZZN3uWS12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOS1_NSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEEONS1_17WebSocketBehaviorIT_EEENUlPNS_9WebSocketILb0ELb1ES3_EEiNS5_17basic_string_viewIcS8_EEE_clESI_iSK_: 385| 164k| webSocketContext->getExt()->closeHandler = std::move([closeHandler = std::move(behavior.close)](WebSocket *ws, int code, std::string_view message) mutable { 386| 164k| if (closeHandler) { ------------------ | Branch (386:17): [True: 164k, False: 0] ------------------ 387| 164k| closeHandler(ws, code, message); 388| 164k| } 389| | 390| | /* Destruct user data after returning from close handler */ 391| 164k| ((UserData *) ws->getUserData())->~UserData(); 392| 164k| }); EpollEchoServer.cpp:_ZZN3uWS12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOS1_NSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEEONS1_17WebSocketBehaviorIT_EEENUlPSD_PT0_E_clINS_12HttpResponseILb0EEENS_11HttpRequestEEEDaSG_SI_: 408| 169k| httpContext->onHttp("GET", pattern, [webSocketContext, behavior = std::move(behavior)](auto *res, auto *req) mutable { 409| | 410| | /* If we have this header set, it's a websocket */ 411| 169k| std::string_view secWebSocketKey = req->getHeader("sec-websocket-key"); 412| 169k| if (secWebSocketKey.length() == 24) { ------------------ | Branch (412:17): [True: 164k, False: 4.79k] ------------------ 413| | 414| | /* Emit upgrade handler */ 415| 164k| if (behavior.upgrade) { ------------------ | Branch (415:21): [True: 0, False: 164k] ------------------ 416| | 417| | /* Nasty, ugly Safari 15 hack */ 418| 0| if (hasBrokenCompression(req->getHeader("user-agent"))) { ------------------ | Branch (418:25): [True: 0, False: 0] ------------------ 419| 0| std::string_view secWebSocketExtensions = req->getHeader("sec-websocket-extensions"); 420| 0| memset((void *) secWebSocketExtensions.data(), ' ', secWebSocketExtensions.length()); 421| 0| } 422| | 423| 0| behavior.upgrade(res, req, (struct us_socket_context_t *) webSocketContext); 424| 164k| } else { 425| | /* Default handler upgrades to WebSocket */ 426| 164k| std::string_view secWebSocketProtocol = req->getHeader("sec-websocket-protocol"); 427| 164k| std::string_view secWebSocketExtensions = req->getHeader("sec-websocket-extensions"); 428| | 429| | /* Safari 15 hack */ 430| 164k| if (hasBrokenCompression(req->getHeader("user-agent"))) { ------------------ | Branch (430:25): [True: 247, False: 164k] ------------------ 431| 247| secWebSocketExtensions = ""; 432| 247| } 433| | 434| 164k| res->template upgrade({}, secWebSocketKey, secWebSocketProtocol, secWebSocketExtensions, (struct us_socket_context_t *) webSocketContext); 435| 164k| } 436| | 437| | /* We are going to get uncorked by the Http get return */ 438| | 439| | /* We do not need to check for any close or shutdown here as we immediately return from get handler */ 440| | 441| 164k| } else { 442| | /* Tell the router that we did not handle this request */ 443| 4.79k| req->setYield(true); 444| 4.79k| } 445| 169k| }, true); _ZN3uWS20hasBrokenCompressionENSt3__117basic_string_viewIcNS0_11char_traitsIcEEEE: 29| 164k| inline bool hasBrokenCompression(std::string_view userAgent) { 30| 164k| size_t posStart = userAgent.find(" Version/15."); 31| 164k| if (posStart == std::string_view::npos) return false; ------------------ | Branch (31:13): [True: 156k, False: 8.08k] ------------------ 32| 8.08k| posStart += 12; 33| | 34| 8.08k| size_t posEnd = userAgent.find(' ', posStart); 35| 8.08k| if (posEnd == std::string_view::npos) return false; ------------------ | Branch (35:13): [True: 771, False: 7.31k] ------------------ 36| | 37| 7.31k| unsigned int minorVersion = 0; 38| 7.31k| auto result = std::from_chars(userAgent.data() + posStart, userAgent.data() + posEnd, minorVersion); 39| 7.31k| if (result.ec != std::errc()) return false; ------------------ | Branch (39:13): [True: 1.15k, False: 6.15k] ------------------ 40| 6.15k| if (result.ptr != userAgent.data() + posEnd) return false; // do not accept trailing chars ------------------ | Branch (40:13): [True: 2.92k, False: 3.23k] ------------------ 41| 3.23k| if (minorVersion > 3) return false; // we target just Safari 15.0 - 15.3 ------------------ | Branch (41:13): [True: 2.32k, False: 908] ------------------ 42| | 43| 908| if (userAgent.find(" Safari/", posEnd) == std::string_view::npos) return false; ------------------ | Branch (43:13): [True: 661, False: 247] ------------------ 44| | 45| 247| return true; 46| 908| } _ZN3uWS12TemplatedAppILb0EE6listenEiON5ofats13any_invocableIFvP18us_listen_socket_tEEE: 555| 5.84k| TemplatedApp &&listen(int port, MoveOnlyFunction &&handler) { 556| 5.84k| handler(httpContext ? httpContext->listen(nullptr, port, 0) : nullptr); ------------------ | Branch (556:17): [True: 5.84k, False: 0] ------------------ 557| 5.84k| return std::move(*this); 558| 5.84k| } _ZN3uWS12TemplatedAppILb0EEC2EOS1_: 202| 5.84k| TemplatedApp(TemplatedApp &&other) { 203| | /* Move HttpContext */ 204| 5.84k| httpContext = other.httpContext; 205| 5.84k| other.httpContext = nullptr; 206| | 207| | /* Move webSocketContextDeleters */ 208| 5.84k| webSocketContextDeleters = std::move(other.webSocketContextDeleters); 209| | 210| 5.84k| webSocketContexts = std::move(other.webSocketContexts); 211| | 212| | /* Move TopicTree */ 213| 5.84k| topicTree = other.topicTree; 214| 5.84k| other.topicTree = nullptr; 215| 5.84k| } _ZN3uWS12TemplatedAppILb0EE3runEv: 590| 5.84k| TemplatedApp &&run() { 591| 5.84k| uWS::run(); 592| 5.84k| return std::move(*this); 593| 5.84k| } _ZN3uWS11AsyncSocketILb0EE4corkEv: 133| 642k| void cork() { 134| | /* Extra check for invalid corking of others */ 135| 642k| if (getLoopData()->corkOffset && getLoopData()->corkedSocket != this) { ------------------ | Branch (135:13): [True: 0, False: 642k] | Branch (135:42): [True: 0, False: 0] ------------------ 136| 0| std::cerr << "Error: Cork buffer must not be acquired without checking canCork!" << std::endl; 137| 0| std::terminate(); 138| 0| } 139| | 140| | /* What if another socket is corked? */ 141| 642k| getLoopData()->corkedSocket = this; 142| 642k| } _ZN3uWS11AsyncSocketILb0EE11getLoopDataEv: 85| 7.16M| LoopData *getLoopData() { 86| 7.16M| return (LoopData *) us_loop_ext(us_socket_context_loop(SSL, us_socket_context(SSL, (us_socket_t *) this))); 87| 7.16M| } _ZN3uWS11AsyncSocketILb0EE6uncorkEPKcib: 327| 643k| std::pair uncork(const char *src = nullptr, int length = 0, bool optionally = false) { 328| 643k| LoopData *loopData = getLoopData(); 329| | 330| 643k| if (loopData->corkedSocket == this) { ------------------ | Branch (330:13): [True: 642k, False: 1.15k] ------------------ 331| 642k| loopData->corkedSocket = nullptr; 332| | 333| 642k| if (loopData->corkOffset) { ------------------ | Branch (333:17): [True: 176k, False: 465k] ------------------ 334| | /* Corked data is already accounted for via its write call */ 335| 176k| auto [written, failed] = write(loopData->corkBuffer, (int) loopData->corkOffset, false, length); 336| 176k| loopData->corkOffset = 0; 337| | 338| 176k| if (failed) { ------------------ | Branch (338:21): [True: 161k, False: 14.9k] ------------------ 339| | /* We do not need to care for buffering here, write does that */ 340| 161k| return {0, true}; 341| 161k| } 342| 176k| } 343| | 344| | /* We should only return with new writes, not things written to cork already */ 345| 480k| return write(src, length, optionally, 0); 346| 642k| } else { 347| | /* We are not even corked! */ 348| 1.15k| return {0, false}; 349| 1.15k| } 350| 643k| } _ZN3uWS11AsyncSocketILb0EE5writeEPKcibi: 236| 4.83M| std::pair write(const char *src, int length, bool optionally = false, int nextLength = 0) { 237| | /* Fake success if closed, simple fix to allow uncork of closed socket to succeed */ 238| 4.83M| if (us_socket_is_closed(SSL, (us_socket_t *) this)) { ------------------ | Branch (238:13): [True: 424k, False: 4.40M] ------------------ 239| 424k| return {length, false}; 240| 424k| } 241| | 242| 4.40M| LoopData *loopData = getLoopData(); 243| 4.40M| AsyncSocketData *asyncSocketData = getAsyncSocketData(); 244| | 245| | /* We are limited if we have a per-socket buffer */ 246| 4.40M| if (asyncSocketData->buffer.length()) { ------------------ | Branch (246:13): [True: 124k, False: 4.28M] ------------------ 247| | /* Write off as much as we can */ 248| 124k| int written = us_socket_write(SSL, (us_socket_t *) this, asyncSocketData->buffer.data(), (int) asyncSocketData->buffer.length(), /*nextLength != 0 | */length); 249| | 250| | /* On failure return, otherwise continue down the function */ 251| 124k| if ((unsigned int) written < asyncSocketData->buffer.length()) { ------------------ | Branch (251:17): [True: 110k, False: 14.3k] ------------------ 252| | 253| | /* Update buffering (todo: we can do better here if we keep track of what happens to this guy later on) */ 254| 110k| asyncSocketData->buffer.erase((unsigned int) written); 255| | 256| 110k| if (optionally) { ------------------ | Branch (256:21): [True: 1.11k, False: 109k] ------------------ 257| | /* Thankfully we can exit early here */ 258| 1.11k| return {0, true}; 259| 109k| } else { 260| | /* This path is horrible and points towards erroneous usage */ 261| 109k| asyncSocketData->buffer.append(src, (unsigned int) length); 262| | 263| 109k| return {length, true}; 264| 109k| } 265| 110k| } 266| | 267| | /* At this point we simply have no buffer and can continue as normal */ 268| 14.3k| asyncSocketData->buffer.clear(); 269| 14.3k| } 270| | 271| 4.29M| if (length) { ------------------ | Branch (271:13): [True: 4.23M, False: 56.9k] ------------------ 272| 4.23M| if (loopData->corkedSocket == this) { ------------------ | Branch (272:17): [True: 4.06M, False: 173k] ------------------ 273| | /* We are corked */ 274| 4.06M| if (LoopData::CORK_BUFFER_SIZE - loopData->corkOffset >= (unsigned int) length) { ------------------ | Branch (274:21): [True: 4.06M, False: 0] ------------------ 275| | /* If the entire chunk fits in cork buffer */ 276| 4.06M| memcpy(loopData->corkBuffer + loopData->corkOffset, src, (unsigned int) length); 277| 4.06M| loopData->corkOffset += (unsigned int) length; 278| | /* Fall through to default return */ 279| 4.06M| } else { 280| | /* Strategy differences between SSL and non-SSL regarding syscall minimizing */ 281| 0| if constexpr (false) { ------------------ | Branch (281:35): [Folded - Ignored] ------------------ 282| | /* Cork up as much as we can */ 283| 0| unsigned int stripped = LoopData::CORK_BUFFER_SIZE - loopData->corkOffset; 284| 0| memcpy(loopData->corkBuffer + loopData->corkOffset, src, stripped); 285| 0| loopData->corkOffset = LoopData::CORK_BUFFER_SIZE; 286| | 287| 0| auto [written, failed] = uncork(src + stripped, length - (int) stripped, optionally); 288| 0| return {written + (int) stripped, failed}; 289| 0| } 290| | 291| | /* For non-SSL we take the penalty of two syscalls */ 292| 0| return uncork(src, length, optionally); 293| 0| } 294| 4.06M| } else { 295| | /* We are not corked */ 296| 173k| int written = us_socket_write(SSL, (us_socket_t *) this, src, length, nextLength != 0); 297| | 298| | /* Did we fail? */ 299| 173k| if (written < length) { ------------------ | Branch (299:21): [True: 162k, False: 10.5k] ------------------ 300| | /* If the write was optional then just bail out */ 301| 162k| if (optionally) { ------------------ | Branch (301:25): [True: 0, False: 162k] ------------------ 302| 0| return {written, true}; 303| 0| } 304| | 305| | /* Fall back to worst possible case (should be very rare for HTTP) */ 306| | /* At least we can reserve room for next chunk if we know it up front */ 307| 162k| if (nextLength) { ------------------ | Branch (307:25): [True: 0, False: 162k] ------------------ 308| 0| asyncSocketData->buffer.reserve(asyncSocketData->buffer.length() + (size_t) (length - written + nextLength)); 309| 0| } 310| | 311| | /* Buffer this chunk */ 312| 162k| asyncSocketData->buffer.append(src + written, (size_t) (length - written)); 313| | 314| | /* Return the failure */ 315| 162k| return {length, true}; 316| 162k| } 317| | /* Fall through to default return */ 318| 173k| } 319| 4.23M| } 320| | 321| | /* Default fall through return */ 322| 4.13M| return {length, false}; 323| 4.29M| } _ZN3uWS11AsyncSocketILb0EE7timeoutEj: 95| 253k| void timeout(unsigned int seconds) { 96| 253k| us_socket_timeout(SSL, (us_socket_t *) this, seconds); 97| 253k| } _ZN3uWS11AsyncSocketILb0EE17getBufferedAmountEv: 193| 203k| unsigned int getBufferedAmount() { 194| | /* We return the actual amount of bytes in backbuffer, including pendingRemoval */ 195| 203k| return (unsigned int) getAsyncSocketData()->buffer.totalLength(); 196| 203k| } _ZN3uWS11AsyncSocketILb0EE8shutdownEv: 100| 2.78k| void shutdown() { 101| 2.78k| us_socket_shutdown(SSL, (us_socket_t *) this); 102| 2.78k| } _ZN3uWS11AsyncSocketILb0EE5closeEv: 117| 90.8k| us_socket_t *close() { 118| 90.8k| return us_socket_close(SSL, (us_socket_t *) this, 0, nullptr); 119| 90.8k| } _ZN3uWS11AsyncSocketILb0EE18getAsyncSocketDataEv: 90| 6.48M| AsyncSocketData *getAsyncSocketData() { 91| 6.48M| return (AsyncSocketData *) us_socket_ext(SSL, (us_socket_t *) this); 92| 6.48M| } _ZN3uWS11AsyncSocketILb0EE8isCorkedEv: 145| 419k| bool isCorked() { 146| 419k| return getLoopData()->corkedSocket == this; 147| 419k| } _ZN3uWS11AsyncSocketILb0EE7canCorkEv: 150| 7.76k| bool canCork() { 151| 7.76k| return getLoopData()->corkedSocket == nullptr; 152| 7.76k| } _ZN3uWS11AsyncSocketILb0EE13getSendBufferEm: 155| 62.5k| std::pair getSendBuffer(size_t size) { 156| | /* First step is to determine if we already have backpressure or not */ 157| 62.5k| LoopData *loopData = getLoopData(); 158| 62.5k| BackPressure &backPressure = getAsyncSocketData()->buffer; 159| 62.5k| size_t existingBackpressure = backPressure.length(); 160| 62.5k| if ((!existingBackpressure) && (isCorked() || canCork()) && (loopData->corkOffset + size < LoopData::CORK_BUFFER_SIZE)) { ------------------ | Branch (160:13): [True: 12.0k, False: 50.4k] | Branch (160:41): [True: 9.32k, False: 2.76k] | Branch (160:55): [True: 1.80k, False: 966] | Branch (160:69): [True: 11.1k, False: 0] ------------------ 161| | /* Cork automatically if we can */ 162| 11.1k| if (isCorked()) { ------------------ | Branch (162:17): [True: 9.32k, False: 1.80k] ------------------ 163| 9.32k| char *sendBuffer = loopData->corkBuffer + loopData->corkOffset; 164| 9.32k| loopData->corkOffset += (unsigned int) size; 165| 9.32k| return {sendBuffer, SendBufferAttribute::NEEDS_NOTHING}; 166| 9.32k| } else { 167| 1.80k| cork(); 168| 1.80k| char *sendBuffer = loopData->corkBuffer + loopData->corkOffset; 169| 1.80k| loopData->corkOffset += (unsigned int) size; 170| 1.80k| return {sendBuffer, SendBufferAttribute::NEEDS_UNCORK}; 171| 1.80k| } 172| 51.4k| } else { 173| | 174| | /* If we are corked and there is already data in the cork buffer, 175| | mark how much is ours and reset it */ 176| 51.4k| unsigned int ourCorkOffset = 0; 177| 51.4k| if (isCorked() && loopData->corkOffset) { ------------------ | Branch (177:17): [True: 26.4k, False: 25.0k] | Branch (177:31): [True: 0, False: 26.4k] ------------------ 178| 0| ourCorkOffset = loopData->corkOffset; 179| 0| loopData->corkOffset = 0; 180| 0| } 181| | 182| | /* Fallback is to use the backpressure as buffer */ 183| 51.4k| backPressure.resize(ourCorkOffset + existingBackpressure + size); 184| | 185| | /* And copy corkbuffer in front */ 186| 51.4k| memcpy((char *) backPressure.data() + existingBackpressure, loopData->corkBuffer, ourCorkOffset); 187| | 188| 51.4k| return {(char *) backPressure.data() + ourCorkOffset + existingBackpressure, SendBufferAttribute::NEEDS_DRAIN}; 189| 51.4k| } 190| 62.5k| } _ZN3uWS11AsyncSocketILb0EE13corkUncheckedEv: 121| 164k| void corkUnchecked() { 122| | /* What if another socket is corked? */ 123| 164k| getLoopData()->corkedSocket = this; 124| 164k| } _ZN3uWS15AsyncSocketDataILb0EEC2Ev: 82| 1.63M| AsyncSocketData() = default; _ZN3uWS12BackPressureC2Ev: 32| 1.63M| BackPressure() = default; _ZN3uWS12BackPressure6lengthEv: 44| 4.71M| size_t length() { 45| 4.71M| return buffer.length() - pendingRemoval; 46| 4.71M| } _ZN3uWS12BackPressure4dataEv: 57| 227k| const char *data() { 58| 227k| return buffer.data() + pendingRemoval; 59| 227k| } _ZN3uWS12BackPressure5eraseEj: 36| 110k| void erase(unsigned int length) { 37| 110k| pendingRemoval += length; 38| | /* Always erase a minimum of 1/32th the current backpressure */ 39| 110k| if (pendingRemoval > (buffer.length() >> 5)) { ------------------ | Branch (39:13): [True: 73.5k, False: 36.8k] ------------------ 40| 73.5k| buffer.erase(0, pendingRemoval); 41| 73.5k| pendingRemoval = 0; 42| 73.5k| } 43| 110k| } _ZN3uWS12BackPressure6appendEPKcm: 33| 272k| void append(const char *data, size_t length) { 34| 272k| buffer.append(data, length); 35| 272k| } _ZN3uWS12BackPressure5clearEv: 47| 14.3k| void clear() { 48| 14.3k| pendingRemoval = 0; 49| 14.3k| buffer.clear(); 50| 14.3k| } _ZN3uWS12BackPressure11totalLengthEv: 64| 203k| size_t totalLength() { 65| 203k| return buffer.length(); 66| 203k| } _ZN3uWS12BackPressure6resizeEm: 54| 51.4k| void resize(size_t length) { 55| 51.4k| buffer.resize(length + pendingRemoval); 56| 51.4k| } _ZN3uWS12BackPressureC2EOS0_: 28| 328k| BackPressure(BackPressure &&other) { 29| 328k| buffer = std::move(other.buffer); 30| 328k| pendingRemoval = other.pendingRemoval; 31| 328k| } _ZN3uWS15AsyncSocketDataILb0EEC2EONS_12BackPressureE: 77| 164k| AsyncSocketData(BackPressure &&backpressure) : buffer(std::move(backpressure)) { 78| | 79| 164k| } _ZN3uWS11BloomFilter5resetEv: 75| 172k| void reset() { 76| 172k| filter.reset(); 77| 172k| } _ZN3uWS11BloomFilter3addENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE: 64| 509k| void add(std::string_view key) { 65| 509k| if (key.length() >= 2) { ------------------ | Branch (65:13): [True: 389k, False: 119k] ------------------ 66| 389k| ScrambleArea s = getFeatures(key); 67| 389k| s.val = perfectHash(s.val); 68| 389k| filter[s.p[0]] = 1; 69| 389k| filter[s.p[1]] = 1; 70| 389k| filter[s.p[2]] = 1; 71| 389k| filter[s.p[3]] = 1; 72| 389k| } 73| 509k| } _ZN3uWS11BloomFilter11getFeaturesENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE: 41| 1.91M| ScrambleArea getFeatures(std::string_view key) { 42| 1.91M| ScrambleArea s; 43| 1.91M| s.p[0] = reinterpret_cast(key[0]); 44| 1.91M| s.p[1] = reinterpret_cast(key[key.length() - 1]); 45| 1.91M| s.p[2] = reinterpret_cast(key[key.length() - 2]); 46| 1.91M| s.p[3] = reinterpret_cast(key[key.length() >> 1]); 47| 1.91M| return s; 48| 1.91M| } _ZN3uWS11BloomFilter11perfectHashEj: 32| 1.91M| static inline uint32_t perfectHash(uint32_t features) { 33| 1.91M| return features *= 1843993368; 34| 1.91M| } _ZN3uWS11BloomFilter9mightHaveENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE: 51| 1.52M| bool mightHave(std::string_view key) { 52| 1.52M| if (key.length() < 2) { ------------------ | Branch (52:13): [True: 0, False: 1.52M] ------------------ 53| 0| return true; 54| 0| } 55| | 56| 1.52M| ScrambleArea s = getFeatures(key); 57| 1.52M| s.val = perfectHash(s.val); 58| 1.52M| return filter[s.p[0]] && ------------------ | Branch (58:16): [True: 682k, False: 844k] ------------------ 59| 1.52M| filter[s.p[1]] && ------------------ | Branch (59:9): [True: 365k, False: 317k] ------------------ 60| 1.52M| filter[s.p[2]] && ------------------ | Branch (60:9): [True: 364k, False: 1.26k] ------------------ 61| 1.52M| filter[s.p[3]]; ------------------ | Branch (61:9): [True: 359k, False: 5.30k] ------------------ 62| 1.52M| } _ZN3uWS11HttpContextILb0EE6createEPNS_4LoopE27us_socket_context_options_t: 394| 5.84k| static HttpContext *create(Loop *loop, us_socket_context_options_t options = {}) { 395| 5.84k| HttpContext *httpContext; 396| | 397| 5.84k| httpContext = (HttpContext *) us_create_socket_context(SSL, (us_loop_t *) loop, sizeof(HttpContextData), options); 398| | 399| 5.84k| if (!httpContext) { ------------------ | Branch (399:13): [True: 0, False: 5.84k] ------------------ 400| 0| return nullptr; 401| 0| } 402| | 403| | /* Init socket context data */ 404| 5.84k| new ((HttpContextData *) us_socket_context_ext(SSL, (us_socket_context_t *) httpContext)) HttpContextData(); 405| 5.84k| return httpContext->init(); 406| 5.84k| } _ZN3uWS11HttpContextILb0EE4initEv: 70| 5.84k| HttpContext *init() { 71| | /* Handle socket connections */ 72| 5.84k| us_socket_context_on_open(SSL, getSocketContext(), [](us_socket_t *s, int /*is_client*/, char */*ip*/, int /*ip_length*/) { 73| | /* Any connected socket should timeout until it has a request */ 74| 5.84k| us_socket_timeout(SSL, s, HTTP_IDLE_TIMEOUT_S); 75| | 76| | /* Init socket ext */ 77| 5.84k| new (us_socket_ext(SSL, s)) HttpResponseData; 78| | 79| | /* Call filter */ 80| 5.84k| HttpContextData *httpContextData = getSocketContextDataS(s); 81| 5.84k| for (auto &f : httpContextData->filterHandlers) { 82| 5.84k| f((HttpResponse *) s, 1); 83| 5.84k| } 84| | 85| 5.84k| return s; 86| 5.84k| }); 87| | 88| | /* Handle socket disconnections */ 89| 5.84k| us_socket_context_on_close(SSL, getSocketContext(), [](us_socket_t *s, int /*code*/, void */*reason*/) { 90| | /* Get socket ext */ 91| 5.84k| HttpResponseData *httpResponseData = (HttpResponseData *) us_socket_ext(SSL, s); 92| | 93| | /* Call filter */ 94| 5.84k| HttpContextData *httpContextData = getSocketContextDataS(s); 95| 5.84k| for (auto &f : httpContextData->filterHandlers) { 96| 5.84k| f((HttpResponse *) s, -1); 97| 5.84k| } 98| | 99| | /* Signal broken HTTP request only if we have a pending request */ 100| 5.84k| if (httpResponseData->onAborted) { 101| 5.84k| httpResponseData->onAborted(); 102| 5.84k| } 103| | 104| | /* Destruct socket ext */ 105| 5.84k| httpResponseData->~HttpResponseData(); 106| | 107| 5.84k| return s; 108| 5.84k| }); 109| | 110| | /* Handle HTTP data streams */ 111| 5.84k| us_socket_context_on_data(SSL, getSocketContext(), [](us_socket_t *s, char *data, int length) { 112| | 113| | // total overhead is about 210k down to 180k 114| | // ~210k req/sec is the original perf with write in data 115| | // ~200k req/sec is with cork and formatting 116| | // ~190k req/sec is with http parsing 117| | // ~180k - 190k req/sec is with varying routing 118| | 119| 5.84k| HttpContextData *httpContextData = getSocketContextDataS(s); 120| | 121| | /* Do not accept any data while in shutdown state */ 122| 5.84k| if (us_socket_is_shut_down(SSL, (us_socket_t *) s)) { 123| 5.84k| return s; 124| 5.84k| } 125| | 126| 5.84k| HttpResponseData *httpResponseData = (HttpResponseData *) us_socket_ext(SSL, s); 127| | 128| | /* Cork this socket */ 129| 5.84k| ((AsyncSocket *) s)->cork(); 130| | 131| | /* Mark that we are inside the parser now */ 132| 5.84k| httpContextData->isParsingHttp = true; 133| | 134| | // clients need to know the cursor after http parse, not servers! 135| | // how far did we read then? we need to know to continue with websocket parsing data? or? 136| | 137| 5.84k| void *proxyParser = nullptr; 138| |#ifdef UWS_WITH_PROXY 139| | proxyParser = &httpResponseData->proxyParser; 140| |#endif 141| | 142| | /* The return value is entirely up to us to interpret. The HttpParser only care for whether the returned value is DIFFERENT or not from passed user */ 143| 5.84k| auto [err, returnedSocket] = httpResponseData->consumePostPadded(data, (unsigned int) length, s, proxyParser, [httpContextData](void *s, HttpRequest *httpRequest) -> void * { 144| | /* For every request we reset the timeout and hang until user makes action */ 145| | /* Warning: if we are in shutdown state, resetting the timer is a security issue! */ 146| 5.84k| us_socket_timeout(SSL, (us_socket_t *) s, 0); 147| | 148| | /* Reset httpResponse */ 149| 5.84k| HttpResponseData *httpResponseData = (HttpResponseData *) us_socket_ext(SSL, (us_socket_t *) s); 150| 5.84k| httpResponseData->offset = 0; 151| | 152| | /* Are we not ready for another request yet? Terminate the connection. */ 153| 5.84k| if (httpResponseData->state & HttpResponseData::HTTP_RESPONSE_PENDING) { 154| 5.84k| us_socket_close(SSL, (us_socket_t *) s, 0, nullptr); 155| 5.84k| return nullptr; 156| 5.84k| } 157| | 158| | /* Mark pending request and emit it */ 159| 5.84k| httpResponseData->state = HttpResponseData::HTTP_RESPONSE_PENDING; 160| | 161| | /* Mark this response as connectionClose if ancient or connection: close */ 162| 5.84k| if (httpRequest->isAncient() || httpRequest->getHeader("connection").length() == 5) { 163| 5.84k| httpResponseData->state |= HttpResponseData::HTTP_CONNECTION_CLOSE; 164| 5.84k| } 165| | 166| | /* Select the router based on SNI (only possible for SSL) */ 167| 5.84k| auto *selectedRouter = &httpContextData->router; 168| 5.84k| if constexpr (SSL) { 169| 5.84k| void *domainRouter = us_socket_server_name_userdata(SSL, (struct us_socket_t *) s); 170| 5.84k| if (domainRouter) { 171| 5.84k| selectedRouter = (decltype(selectedRouter)) domainRouter; 172| 5.84k| } 173| 5.84k| } 174| | 175| | /* Route the method and URL */ 176| 5.84k| selectedRouter->getUserData() = {(HttpResponse *) s, httpRequest}; 177| 5.84k| if (!selectedRouter->route(httpRequest->getCaseSensitiveMethod(), httpRequest->getUrl())) { 178| | /* We have to force close this socket as we have no handler for it */ 179| 5.84k| us_socket_close(SSL, (us_socket_t *) s, 0, nullptr); 180| 5.84k| return nullptr; 181| 5.84k| } 182| | 183| | /* First of all we need to check if this socket was deleted due to upgrade */ 184| 5.84k| if (httpContextData->upgradedWebSocket) { 185| | /* We differ between closed and upgraded below */ 186| 5.84k| return nullptr; 187| 5.84k| } 188| | 189| | /* Was the socket closed? */ 190| 5.84k| if (us_socket_is_closed(SSL, (struct us_socket_t *) s)) { 191| 5.84k| return nullptr; 192| 5.84k| } 193| | 194| | /* We absolutely have to terminate parsing if shutdown */ 195| 5.84k| if (us_socket_is_shut_down(SSL, (us_socket_t *) s)) { 196| 5.84k| return nullptr; 197| 5.84k| } 198| | 199| | /* Returning from a request handler without responding or attaching an onAborted handler is ill-use */ 200| 5.84k| if (!((HttpResponse *) s)->hasResponded() && !httpResponseData->onAborted) { 201| | /* Throw exception here? */ 202| 5.84k| std::cerr << "Error: Returning from a request handler without responding or attaching an abort handler is forbidden!" << std::endl; 203| 5.84k| std::terminate(); 204| 5.84k| } 205| | 206| | /* If we have not responded and we have a data handler, we need to timeout to enfore client sending the data */ 207| 5.84k| if (!((HttpResponse *) s)->hasResponded() && httpResponseData->inStream) { 208| 5.84k| us_socket_timeout(SSL, (us_socket_t *) s, HTTP_IDLE_TIMEOUT_S); 209| 5.84k| } 210| | 211| | /* Continue parsing */ 212| 5.84k| return s; 213| | 214| 5.84k| }, [httpResponseData](void *user, std::string_view data, bool fin) -> void * { 215| | /* We always get an empty chunk even if there is no data */ 216| 5.84k| if (httpResponseData->inStream) { 217| | 218| | /* Todo: can this handle timeout for non-post as well? */ 219| 5.84k| if (fin) { 220| | /* If we just got the last chunk (or empty chunk), disable timeout */ 221| 5.84k| us_socket_timeout(SSL, (struct us_socket_t *) user, 0); 222| 5.84k| } else { 223| | /* We still have some more data coming in later, so reset timeout */ 224| | /* Only reset timeout if we got enough bytes (16kb/sec) since last time we reset here */ 225| 5.84k| httpResponseData->received_bytes_per_timeout += (unsigned int) data.length(); 226| 5.84k| if (httpResponseData->received_bytes_per_timeout >= HTTP_RECEIVE_THROUGHPUT_BYTES * HTTP_IDLE_TIMEOUT_S) { 227| 5.84k| us_socket_timeout(SSL, (struct us_socket_t *) user, HTTP_IDLE_TIMEOUT_S); 228| 5.84k| httpResponseData->received_bytes_per_timeout = 0; 229| 5.84k| } 230| 5.84k| } 231| | 232| | /* We might respond in the handler, so do not change timeout after this */ 233| 5.84k| httpResponseData->inStream(data, fin); 234| | 235| | /* Was the socket closed? */ 236| 5.84k| if (us_socket_is_closed(SSL, (struct us_socket_t *) user)) { 237| 5.84k| return nullptr; 238| 5.84k| } 239| | 240| | /* We absolutely have to terminate parsing if shutdown */ 241| 5.84k| if (us_socket_is_shut_down(SSL, (us_socket_t *) user)) { 242| 5.84k| return nullptr; 243| 5.84k| } 244| | 245| | /* If we were given the last data chunk, reset data handler to ensure following 246| | * requests on the same socket won't trigger any previously registered behavior */ 247| 5.84k| if (fin) { 248| 5.84k| httpResponseData->inStream = nullptr; 249| 5.84k| } 250| 5.84k| } 251| 5.84k| return user; 252| 5.84k| }); 253| | 254| | /* Mark that we are no longer parsing Http */ 255| 5.84k| httpContextData->isParsingHttp = false; 256| | 257| | /* If we got fullptr that means the parser wants us to close the socket from error (same as calling the errorHandler) */ 258| 5.84k| if (returnedSocket == FULLPTR) { 259| | /* For errors, we only deliver them "at most once". We don't care if they get halfways delivered or not. */ 260| 5.84k| us_socket_write(SSL, s, httpErrorResponses[err].data(), (int) httpErrorResponses[err].length(), false); 261| 5.84k| us_socket_shutdown(SSL, s); 262| | /* Close any socket on HTTP errors */ 263| 5.84k| us_socket_close(SSL, s, 0, nullptr); 264| | /* This just makes the following code act as if the socket was closed from error inside the parser. */ 265| 5.84k| returnedSocket = nullptr; 266| 5.84k| } 267| | 268| | /* We need to uncork in all cases, except for nullptr (closed socket, or upgraded socket) */ 269| 5.84k| if (returnedSocket != nullptr) { 270| | /* Timeout on uncork failure */ 271| 5.84k| auto [written, failed] = ((AsyncSocket *) returnedSocket)->uncork(); 272| 5.84k| if (failed) { 273| | /* All Http sockets timeout by this, and this behavior match the one in HttpResponse::cork */ 274| | /* Warning: both HTTP_IDLE_TIMEOUT_S and HTTP_TIMEOUT_S are 10 seconds and both are used the same */ 275| 5.84k| ((AsyncSocket *) s)->timeout(HTTP_IDLE_TIMEOUT_S); 276| 5.84k| } 277| | 278| | /* We need to check if we should close this socket here now */ 279| 5.84k| if (httpResponseData->state & HttpResponseData::HTTP_CONNECTION_CLOSE) { 280| 5.84k| if ((httpResponseData->state & HttpResponseData::HTTP_RESPONSE_PENDING) == 0) { 281| 5.84k| if (((AsyncSocket *) s)->getBufferedAmount() == 0) { 282| 5.84k| ((AsyncSocket *) s)->shutdown(); 283| | /* We need to force close after sending FIN since we want to hinder 284| | * clients from keeping to send their huge data */ 285| 5.84k| ((AsyncSocket *) s)->close(); 286| 5.84k| } 287| 5.84k| } 288| 5.84k| } 289| | 290| 5.84k| return (us_socket_t *) returnedSocket; 291| 5.84k| } 292| | 293| | /* If we upgraded, check here (differ between nullptr close and nullptr upgrade) */ 294| 5.84k| if (httpContextData->upgradedWebSocket) { 295| | /* This path is only for upgraded websockets */ 296| 5.84k| AsyncSocket *asyncSocket = (AsyncSocket *) httpContextData->upgradedWebSocket; 297| | 298| | /* Uncork here as well (note: what if we failed to uncork and we then pub/sub before we even upgraded?) */ 299| 5.84k| auto [written, failed] = asyncSocket->uncork(); 300| | 301| | /* If we succeeded in uncorking, check if we have sent WebSocket FIN */ 302| 5.84k| if (!failed) { 303| 5.84k| WebSocketData *webSocketData = (WebSocketData *) asyncSocket->getAsyncSocketData(); 304| 5.84k| if (webSocketData->isShuttingDown) { 305| | /* In that case, also send TCP FIN (this is similar to what we have in ws drain handler) */ 306| 5.84k| asyncSocket->shutdown(); 307| 5.84k| } 308| 5.84k| } 309| | 310| | /* Reset upgradedWebSocket before we return */ 311| 5.84k| httpContextData->upgradedWebSocket = nullptr; 312| | 313| | /* Return the new upgraded websocket */ 314| 5.84k| return (us_socket_t *) asyncSocket; 315| 5.84k| } 316| | 317| | /* It is okay to uncork a closed socket and we need to */ 318| 5.84k| ((AsyncSocket *) s)->uncork(); 319| | 320| | /* We cannot return nullptr to the underlying stack in any case */ 321| 5.84k| return s; 322| 5.84k| }); 323| | 324| | /* Handle HTTP write out (note: SSL_read may trigger this spuriously, the app need to handle spurious calls) */ 325| 5.84k| us_socket_context_on_writable(SSL, getSocketContext(), [](us_socket_t *s) { 326| | 327| 5.84k| AsyncSocket *asyncSocket = (AsyncSocket *) s; 328| 5.84k| HttpResponseData *httpResponseData = (HttpResponseData *) asyncSocket->getAsyncSocketData(); 329| | 330| | /* Ask the developer to write data and return success (true) or failure (false), OR skip sending anything and return success (true). */ 331| 5.84k| if (httpResponseData->onWritable) { 332| | /* We are now writable, so hang timeout again, the user does not have to do anything so we should hang until end or tryEnd rearms timeout */ 333| 5.84k| us_socket_timeout(SSL, s, 0); 334| | 335| | /* We expect the developer to return whether or not write was successful (true). 336| | * If write was never called, the developer should still return true so that we may drain. */ 337| 5.84k| bool success = httpResponseData->callOnWritable(httpResponseData->offset); 338| | 339| | /* The developer indicated that their onWritable failed. */ 340| 5.84k| if (!success) { 341| | /* Skip testing if we can drain anything since that might perform an extra syscall */ 342| 5.84k| return s; 343| 5.84k| } 344| | 345| | /* We don't want to fall through since we don't want to mess with timeout. 346| | * It makes little sense to drain any backpressure when the user has registered onWritable. */ 347| 5.84k| return s; 348| 5.84k| } 349| | 350| | /* Drain any socket buffer, this might empty our backpressure and thus finish the request */ 351| 5.84k| /*auto [written, failed] = */asyncSocket->write(nullptr, 0, true, 0); 352| | 353| | /* Should we close this connection after a response - and is this response really done? */ 354| 5.84k| if (httpResponseData->state & HttpResponseData::HTTP_CONNECTION_CLOSE) { 355| 5.84k| if ((httpResponseData->state & HttpResponseData::HTTP_RESPONSE_PENDING) == 0) { 356| 5.84k| if (asyncSocket->getBufferedAmount() == 0) { 357| 5.84k| asyncSocket->shutdown(); 358| | /* We need to force close after sending FIN since we want to hinder 359| | * clients from keeping to send their huge data */ 360| 5.84k| asyncSocket->close(); 361| 5.84k| } 362| 5.84k| } 363| 5.84k| } 364| | 365| | /* Expect another writable event, or another request within the timeout */ 366| 5.84k| asyncSocket->timeout(HTTP_IDLE_TIMEOUT_S); 367| | 368| 5.84k| return s; 369| 5.84k| }); 370| | 371| | /* Handle FIN, HTTP does not support half-closed sockets, so simply close */ 372| 5.84k| us_socket_context_on_end(SSL, getSocketContext(), [](us_socket_t *s) { 373| | 374| | /* We do not care for half closed sockets */ 375| 5.84k| AsyncSocket *asyncSocket = (AsyncSocket *) s; 376| 5.84k| return asyncSocket->close(); 377| | 378| 5.84k| }); 379| | 380| | /* Handle socket timeouts, simply close them so to not confuse client with FIN */ 381| 5.84k| us_socket_context_on_timeout(SSL, getSocketContext(), [](us_socket_t *s) { 382| | 383| | /* Force close rather than gracefully shutdown and risk confusing the client with a complete download */ 384| 5.84k| AsyncSocket *asyncSocket = (AsyncSocket *) s; 385| 5.84k| return asyncSocket->close(); 386| | 387| 5.84k| }); 388| | 389| 5.84k| return this; 390| 5.84k| } _ZN3uWS11HttpContextILb0EE16getSocketContextEv: 53| 234k| us_socket_context_t *getSocketContext() { 54| 234k| return (us_socket_context_t *) this; 55| 234k| } _ZZN3uWS11HttpContextILb0EE4initEvENKUlP11us_socket_tiPciE_clES3_iS4_i: 72| 1.63M| us_socket_context_on_open(SSL, getSocketContext(), [](us_socket_t *s, int /*is_client*/, char */*ip*/, int /*ip_length*/) { 73| | /* Any connected socket should timeout until it has a request */ 74| 1.63M| us_socket_timeout(SSL, s, HTTP_IDLE_TIMEOUT_S); 75| | 76| | /* Init socket ext */ 77| 1.63M| new (us_socket_ext(SSL, s)) HttpResponseData; 78| | 79| | /* Call filter */ 80| 1.63M| HttpContextData *httpContextData = getSocketContextDataS(s); 81| 1.63M| for (auto &f : httpContextData->filterHandlers) { ------------------ | Branch (81:26): [True: 0, False: 1.63M] ------------------ 82| 0| f((HttpResponse *) s, 1); 83| 0| } 84| | 85| 1.63M| return s; 86| 1.63M| }); _ZN3uWS11HttpContextILb0EE21getSocketContextDataSEP11us_socket_t: 65| 3.69M| static HttpContextData *getSocketContextDataS(us_socket_t *s) { 66| 3.69M| return (HttpContextData *) us_socket_context_ext(SSL, getSocketContext(s)); 67| 3.69M| } _ZN3uWS11HttpContextILb0EE16getSocketContextEP11us_socket_t: 57| 3.69M| static us_socket_context_t *getSocketContext(us_socket_t *s) { 58| 3.69M| return (us_socket_context_t *) us_socket_context(SSL, s); 59| 3.69M| } _ZZN3uWS11HttpContextILb0EE4initEvENKUlP11us_socket_tiPvE_clES3_iS4_: 89| 1.46M| us_socket_context_on_close(SSL, getSocketContext(), [](us_socket_t *s, int /*code*/, void */*reason*/) { 90| | /* Get socket ext */ 91| 1.46M| HttpResponseData *httpResponseData = (HttpResponseData *) us_socket_ext(SSL, s); 92| | 93| | /* Call filter */ 94| 1.46M| HttpContextData *httpContextData = getSocketContextDataS(s); 95| 1.46M| for (auto &f : httpContextData->filterHandlers) { ------------------ | Branch (95:26): [True: 0, False: 1.46M] ------------------ 96| 0| f((HttpResponse *) s, -1); 97| 0| } 98| | 99| | /* Signal broken HTTP request only if we have a pending request */ 100| 1.46M| if (httpResponseData->onAborted) { ------------------ | Branch (100:17): [True: 0, False: 1.46M] ------------------ 101| 0| httpResponseData->onAborted(); 102| 0| } 103| | 104| | /* Destruct socket ext */ 105| 1.46M| httpResponseData->~HttpResponseData(); 106| | 107| 1.46M| return s; 108| 1.46M| }); _ZZN3uWS11HttpContextILb0EE4initEvENKUlP11us_socket_tPciE_clES3_S4_i: 111| 592k| us_socket_context_on_data(SSL, getSocketContext(), [](us_socket_t *s, char *data, int length) { 112| | 113| | // total overhead is about 210k down to 180k 114| | // ~210k req/sec is the original perf with write in data 115| | // ~200k req/sec is with cork and formatting 116| | // ~190k req/sec is with http parsing 117| | // ~180k - 190k req/sec is with varying routing 118| | 119| 592k| HttpContextData *httpContextData = getSocketContextDataS(s); 120| | 121| | /* Do not accept any data while in shutdown state */ 122| 592k| if (us_socket_is_shut_down(SSL, (us_socket_t *) s)) { ------------------ | Branch (122:17): [True: 0, False: 592k] ------------------ 123| 0| return s; 124| 0| } 125| | 126| 592k| HttpResponseData *httpResponseData = (HttpResponseData *) us_socket_ext(SSL, s); 127| | 128| | /* Cork this socket */ 129| 592k| ((AsyncSocket *) s)->cork(); 130| | 131| | /* Mark that we are inside the parser now */ 132| 592k| httpContextData->isParsingHttp = true; 133| | 134| | // clients need to know the cursor after http parse, not servers! 135| | // how far did we read then? we need to know to continue with websocket parsing data? or? 136| | 137| 592k| void *proxyParser = nullptr; 138| |#ifdef UWS_WITH_PROXY 139| | proxyParser = &httpResponseData->proxyParser; 140| |#endif 141| | 142| | /* The return value is entirely up to us to interpret. The HttpParser only care for whether the returned value is DIFFERENT or not from passed user */ 143| 592k| auto [err, returnedSocket] = httpResponseData->consumePostPadded(data, (unsigned int) length, s, proxyParser, [httpContextData](void *s, HttpRequest *httpRequest) -> void * { 144| | /* For every request we reset the timeout and hang until user makes action */ 145| | /* Warning: if we are in shutdown state, resetting the timer is a security issue! */ 146| 592k| us_socket_timeout(SSL, (us_socket_t *) s, 0); 147| | 148| | /* Reset httpResponse */ 149| 592k| HttpResponseData *httpResponseData = (HttpResponseData *) us_socket_ext(SSL, (us_socket_t *) s); 150| 592k| httpResponseData->offset = 0; 151| | 152| | /* Are we not ready for another request yet? Terminate the connection. */ 153| 592k| if (httpResponseData->state & HttpResponseData::HTTP_RESPONSE_PENDING) { 154| 592k| us_socket_close(SSL, (us_socket_t *) s, 0, nullptr); 155| 592k| return nullptr; 156| 592k| } 157| | 158| | /* Mark pending request and emit it */ 159| 592k| httpResponseData->state = HttpResponseData::HTTP_RESPONSE_PENDING; 160| | 161| | /* Mark this response as connectionClose if ancient or connection: close */ 162| 592k| if (httpRequest->isAncient() || httpRequest->getHeader("connection").length() == 5) { 163| 592k| httpResponseData->state |= HttpResponseData::HTTP_CONNECTION_CLOSE; 164| 592k| } 165| | 166| | /* Select the router based on SNI (only possible for SSL) */ 167| 592k| auto *selectedRouter = &httpContextData->router; 168| 592k| if constexpr (SSL) { 169| 592k| void *domainRouter = us_socket_server_name_userdata(SSL, (struct us_socket_t *) s); 170| 592k| if (domainRouter) { 171| 592k| selectedRouter = (decltype(selectedRouter)) domainRouter; 172| 592k| } 173| 592k| } 174| | 175| | /* Route the method and URL */ 176| 592k| selectedRouter->getUserData() = {(HttpResponse *) s, httpRequest}; 177| 592k| if (!selectedRouter->route(httpRequest->getCaseSensitiveMethod(), httpRequest->getUrl())) { 178| | /* We have to force close this socket as we have no handler for it */ 179| 592k| us_socket_close(SSL, (us_socket_t *) s, 0, nullptr); 180| 592k| return nullptr; 181| 592k| } 182| | 183| | /* First of all we need to check if this socket was deleted due to upgrade */ 184| 592k| if (httpContextData->upgradedWebSocket) { 185| | /* We differ between closed and upgraded below */ 186| 592k| return nullptr; 187| 592k| } 188| | 189| | /* Was the socket closed? */ 190| 592k| if (us_socket_is_closed(SSL, (struct us_socket_t *) s)) { 191| 592k| return nullptr; 192| 592k| } 193| | 194| | /* We absolutely have to terminate parsing if shutdown */ 195| 592k| if (us_socket_is_shut_down(SSL, (us_socket_t *) s)) { 196| 592k| return nullptr; 197| 592k| } 198| | 199| | /* Returning from a request handler without responding or attaching an onAborted handler is ill-use */ 200| 592k| if (!((HttpResponse *) s)->hasResponded() && !httpResponseData->onAborted) { 201| | /* Throw exception here? */ 202| 592k| std::cerr << "Error: Returning from a request handler without responding or attaching an abort handler is forbidden!" << std::endl; 203| 592k| std::terminate(); 204| 592k| } 205| | 206| | /* If we have not responded and we have a data handler, we need to timeout to enfore client sending the data */ 207| 592k| if (!((HttpResponse *) s)->hasResponded() && httpResponseData->inStream) { 208| 592k| us_socket_timeout(SSL, (us_socket_t *) s, HTTP_IDLE_TIMEOUT_S); 209| 592k| } 210| | 211| | /* Continue parsing */ 212| 592k| return s; 213| | 214| 592k| }, [httpResponseData](void *user, std::string_view data, bool fin) -> void * { 215| | /* We always get an empty chunk even if there is no data */ 216| 592k| if (httpResponseData->inStream) { 217| | 218| | /* Todo: can this handle timeout for non-post as well? */ 219| 592k| if (fin) { 220| | /* If we just got the last chunk (or empty chunk), disable timeout */ 221| 592k| us_socket_timeout(SSL, (struct us_socket_t *) user, 0); 222| 592k| } else { 223| | /* We still have some more data coming in later, so reset timeout */ 224| | /* Only reset timeout if we got enough bytes (16kb/sec) since last time we reset here */ 225| 592k| httpResponseData->received_bytes_per_timeout += (unsigned int) data.length(); 226| 592k| if (httpResponseData->received_bytes_per_timeout >= HTTP_RECEIVE_THROUGHPUT_BYTES * HTTP_IDLE_TIMEOUT_S) { 227| 592k| us_socket_timeout(SSL, (struct us_socket_t *) user, HTTP_IDLE_TIMEOUT_S); 228| 592k| httpResponseData->received_bytes_per_timeout = 0; 229| 592k| } 230| 592k| } 231| | 232| | /* We might respond in the handler, so do not change timeout after this */ 233| 592k| httpResponseData->inStream(data, fin); 234| | 235| | /* Was the socket closed? */ 236| 592k| if (us_socket_is_closed(SSL, (struct us_socket_t *) user)) { 237| 592k| return nullptr; 238| 592k| } 239| | 240| | /* We absolutely have to terminate parsing if shutdown */ 241| 592k| if (us_socket_is_shut_down(SSL, (us_socket_t *) user)) { 242| 592k| return nullptr; 243| 592k| } 244| | 245| | /* If we were given the last data chunk, reset data handler to ensure following 246| | * requests on the same socket won't trigger any previously registered behavior */ 247| 592k| if (fin) { 248| 592k| httpResponseData->inStream = nullptr; 249| 592k| } 250| 592k| } 251| 592k| return user; 252| 592k| }); 253| | 254| | /* Mark that we are no longer parsing Http */ 255| 592k| httpContextData->isParsingHttp = false; 256| | 257| | /* If we got fullptr that means the parser wants us to close the socket from error (same as calling the errorHandler) */ 258| 592k| if (returnedSocket == FULLPTR) { ------------------ | Branch (258:17): [True: 398k, False: 194k] ------------------ 259| | /* For errors, we only deliver them "at most once". We don't care if they get halfways delivered or not. */ 260| 398k| us_socket_write(SSL, s, httpErrorResponses[err].data(), (int) httpErrorResponses[err].length(), false); 261| 398k| us_socket_shutdown(SSL, s); 262| | /* Close any socket on HTTP errors */ 263| 398k| us_socket_close(SSL, s, 0, nullptr); 264| | /* This just makes the following code act as if the socket was closed from error inside the parser. */ 265| 398k| returnedSocket = nullptr; 266| 398k| } 267| | 268| | /* We need to uncork in all cases, except for nullptr (closed socket, or upgraded socket) */ 269| 592k| if (returnedSocket != nullptr) { ------------------ | Branch (269:17): [True: 29.8k, False: 562k] ------------------ 270| | /* Timeout on uncork failure */ 271| 29.8k| auto [written, failed] = ((AsyncSocket *) returnedSocket)->uncork(); 272| 29.8k| if (failed) { ------------------ | Branch (272:21): [True: 2.89k, False: 26.9k] ------------------ 273| | /* All Http sockets timeout by this, and this behavior match the one in HttpResponse::cork */ 274| | /* Warning: both HTTP_IDLE_TIMEOUT_S and HTTP_TIMEOUT_S are 10 seconds and both are used the same */ 275| 2.89k| ((AsyncSocket *) s)->timeout(HTTP_IDLE_TIMEOUT_S); 276| 2.89k| } 277| | 278| | /* We need to check if we should close this socket here now */ 279| 29.8k| if (httpResponseData->state & HttpResponseData::HTTP_CONNECTION_CLOSE) { ------------------ | Branch (279:21): [True: 1.00k, False: 28.8k] ------------------ 280| 1.00k| if ((httpResponseData->state & HttpResponseData::HTTP_RESPONSE_PENDING) == 0) { ------------------ | Branch (280:25): [True: 1.00k, False: 0] ------------------ 281| 1.00k| if (((AsyncSocket *) s)->getBufferedAmount() == 0) { ------------------ | Branch (281:29): [True: 341, False: 662] ------------------ 282| 341| ((AsyncSocket *) s)->shutdown(); 283| | /* We need to force close after sending FIN since we want to hinder 284| | * clients from keeping to send their huge data */ 285| 341| ((AsyncSocket *) s)->close(); 286| 341| } 287| 1.00k| } 288| 1.00k| } 289| | 290| 29.8k| return (us_socket_t *) returnedSocket; 291| 29.8k| } 292| | 293| | /* If we upgraded, check here (differ between nullptr close and nullptr upgrade) */ 294| 562k| if (httpContextData->upgradedWebSocket) { ------------------ | Branch (294:17): [True: 164k, False: 398k] ------------------ 295| | /* This path is only for upgraded websockets */ 296| 164k| AsyncSocket *asyncSocket = (AsyncSocket *) httpContextData->upgradedWebSocket; 297| | 298| | /* Uncork here as well (note: what if we failed to uncork and we then pub/sub before we even upgraded?) */ 299| 164k| auto [written, failed] = asyncSocket->uncork(); 300| | 301| | /* If we succeeded in uncorking, check if we have sent WebSocket FIN */ 302| 164k| if (!failed) { ------------------ | Branch (302:21): [True: 8.07k, False: 156k] ------------------ 303| 8.07k| WebSocketData *webSocketData = (WebSocketData *) asyncSocket->getAsyncSocketData(); 304| 8.07k| if (webSocketData->isShuttingDown) { ------------------ | Branch (304:25): [True: 0, False: 8.07k] ------------------ 305| | /* In that case, also send TCP FIN (this is similar to what we have in ws drain handler) */ 306| 0| asyncSocket->shutdown(); 307| 0| } 308| 8.07k| } 309| | 310| | /* Reset upgradedWebSocket before we return */ 311| 164k| httpContextData->upgradedWebSocket = nullptr; 312| | 313| | /* Return the new upgraded websocket */ 314| 164k| return (us_socket_t *) asyncSocket; 315| 164k| } 316| | 317| | /* It is okay to uncork a closed socket and we need to */ 318| 398k| ((AsyncSocket *) s)->uncork(); 319| | 320| | /* We cannot return nullptr to the underlying stack in any case */ 321| 398k| return s; 322| 562k| }); _ZZZN3uWS11HttpContextILb0EE4initEvENKUlP11us_socket_tPciE_clES3_S4_iENKUlPvPNS_11HttpRequestEE_clES6_S8_: 143| 171k| auto [err, returnedSocket] = httpResponseData->consumePostPadded(data, (unsigned int) length, s, proxyParser, [httpContextData](void *s, HttpRequest *httpRequest) -> void * { 144| | /* For every request we reset the timeout and hang until user makes action */ 145| | /* Warning: if we are in shutdown state, resetting the timer is a security issue! */ 146| 171k| us_socket_timeout(SSL, (us_socket_t *) s, 0); 147| | 148| | /* Reset httpResponse */ 149| 171k| HttpResponseData *httpResponseData = (HttpResponseData *) us_socket_ext(SSL, (us_socket_t *) s); 150| 171k| httpResponseData->offset = 0; 151| | 152| | /* Are we not ready for another request yet? Terminate the connection. */ 153| 171k| if (httpResponseData->state & HttpResponseData::HTTP_RESPONSE_PENDING) { ------------------ | Branch (153:21): [True: 0, False: 171k] ------------------ 154| 0| us_socket_close(SSL, (us_socket_t *) s, 0, nullptr); 155| 0| return nullptr; 156| 0| } 157| | 158| | /* Mark pending request and emit it */ 159| 171k| httpResponseData->state = HttpResponseData::HTTP_RESPONSE_PENDING; 160| | 161| | /* Mark this response as connectionClose if ancient or connection: close */ 162| 171k| if (httpRequest->isAncient() || httpRequest->getHeader("connection").length() == 5) { ------------------ | Branch (162:21): [True: 0, False: 171k] | Branch (162:21): [True: 843, False: 170k] | Branch (162:49): [True: 843, False: 170k] ------------------ 163| 843| httpResponseData->state |= HttpResponseData::HTTP_CONNECTION_CLOSE; 164| 843| } 165| | 166| | /* Select the router based on SNI (only possible for SSL) */ 167| 171k| auto *selectedRouter = &httpContextData->router; 168| 171k| if constexpr (SSL) { ------------------ | Branch (168:31): [Folded - Ignored] ------------------ 169| 171k| void *domainRouter = us_socket_server_name_userdata(SSL, (struct us_socket_t *) s); 170| 171k| if (domainRouter) { 171| 171k| selectedRouter = (decltype(selectedRouter)) domainRouter; 172| 171k| } 173| 171k| } 174| | 175| | /* Route the method and URL */ 176| 171k| selectedRouter->getUserData() = {(HttpResponse *) s, httpRequest}; 177| 171k| if (!selectedRouter->route(httpRequest->getCaseSensitiveMethod(), httpRequest->getUrl())) { ------------------ | Branch (177:21): [True: 0, False: 171k] ------------------ 178| | /* We have to force close this socket as we have no handler for it */ 179| 0| us_socket_close(SSL, (us_socket_t *) s, 0, nullptr); 180| 0| return nullptr; 181| 0| } 182| | 183| | /* First of all we need to check if this socket was deleted due to upgrade */ 184| 171k| if (httpContextData->upgradedWebSocket) { ------------------ | Branch (184:21): [True: 164k, False: 7.55k] ------------------ 185| | /* We differ between closed and upgraded below */ 186| 164k| return nullptr; 187| 164k| } 188| | 189| | /* Was the socket closed? */ 190| 7.55k| if (us_socket_is_closed(SSL, (struct us_socket_t *) s)) { ------------------ | Branch (190:21): [True: 0, False: 7.55k] ------------------ 191| 0| return nullptr; 192| 0| } 193| | 194| | /* We absolutely have to terminate parsing if shutdown */ 195| 7.55k| if (us_socket_is_shut_down(SSL, (us_socket_t *) s)) { ------------------ | Branch (195:21): [True: 0, False: 7.55k] ------------------ 196| 0| return nullptr; 197| 0| } 198| | 199| | /* Returning from a request handler without responding or attaching an onAborted handler is ill-use */ 200| 7.55k| if (!((HttpResponse *) s)->hasResponded() && !httpResponseData->onAborted) { ------------------ | Branch (200:21): [True: 0, False: 7.55k] | Branch (200:67): [True: 0, False: 0] ------------------ 201| | /* Throw exception here? */ 202| 0| std::cerr << "Error: Returning from a request handler without responding or attaching an abort handler is forbidden!" << std::endl; 203| 0| std::terminate(); 204| 0| } 205| | 206| | /* If we have not responded and we have a data handler, we need to timeout to enfore client sending the data */ 207| 7.55k| if (!((HttpResponse *) s)->hasResponded() && httpResponseData->inStream) { ------------------ | Branch (207:21): [True: 0, False: 7.55k] | Branch (207:67): [True: 0, False: 0] ------------------ 208| 0| us_socket_timeout(SSL, (us_socket_t *) s, HTTP_IDLE_TIMEOUT_S); 209| 0| } 210| | 211| | /* Continue parsing */ 212| 7.55k| return s; 213| | 214| 7.55k| }, [httpResponseData](void *user, std::string_view data, bool fin) -> void * { _ZZZN3uWS11HttpContextILb0EE4initEvENKUlP11us_socket_tPciE_clES3_S4_iENKUlPvNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEbE_clES6_SB_b: 214| 7.55k| }, [httpResponseData](void *user, std::string_view data, bool fin) -> void * { 215| | /* We always get an empty chunk even if there is no data */ 216| 7.55k| if (httpResponseData->inStream) { ------------------ | Branch (216:21): [True: 0, False: 7.55k] ------------------ 217| | 218| | /* Todo: can this handle timeout for non-post as well? */ 219| 0| if (fin) { ------------------ | Branch (219:25): [True: 0, False: 0] ------------------ 220| | /* If we just got the last chunk (or empty chunk), disable timeout */ 221| 0| us_socket_timeout(SSL, (struct us_socket_t *) user, 0); 222| 0| } else { 223| | /* We still have some more data coming in later, so reset timeout */ 224| | /* Only reset timeout if we got enough bytes (16kb/sec) since last time we reset here */ 225| 0| httpResponseData->received_bytes_per_timeout += (unsigned int) data.length(); 226| 0| if (httpResponseData->received_bytes_per_timeout >= HTTP_RECEIVE_THROUGHPUT_BYTES * HTTP_IDLE_TIMEOUT_S) { ------------------ | Branch (226:29): [True: 0, False: 0] ------------------ 227| 0| us_socket_timeout(SSL, (struct us_socket_t *) user, HTTP_IDLE_TIMEOUT_S); 228| 0| httpResponseData->received_bytes_per_timeout = 0; 229| 0| } 230| 0| } 231| | 232| | /* We might respond in the handler, so do not change timeout after this */ 233| 0| httpResponseData->inStream(data, fin); 234| | 235| | /* Was the socket closed? */ 236| 0| if (us_socket_is_closed(SSL, (struct us_socket_t *) user)) { ------------------ | Branch (236:25): [True: 0, False: 0] ------------------ 237| 0| return nullptr; 238| 0| } 239| | 240| | /* We absolutely have to terminate parsing if shutdown */ 241| 0| if (us_socket_is_shut_down(SSL, (us_socket_t *) user)) { ------------------ | Branch (241:25): [True: 0, False: 0] ------------------ 242| 0| return nullptr; 243| 0| } 244| | 245| | /* If we were given the last data chunk, reset data handler to ensure following 246| | * requests on the same socket won't trigger any previously registered behavior */ 247| 0| if (fin) { ------------------ | Branch (247:25): [True: 0, False: 0] ------------------ 248| 0| httpResponseData->inStream = nullptr; 249| 0| } 250| 0| } 251| 7.55k| return user; 252| 7.55k| }); _ZZN3uWS11HttpContextILb0EE4initEvENKUlP11us_socket_tE_clES3_: 325| 1.33k| us_socket_context_on_writable(SSL, getSocketContext(), [](us_socket_t *s) { 326| | 327| 1.33k| AsyncSocket *asyncSocket = (AsyncSocket *) s; 328| 1.33k| HttpResponseData *httpResponseData = (HttpResponseData *) asyncSocket->getAsyncSocketData(); 329| | 330| | /* Ask the developer to write data and return success (true) or failure (false), OR skip sending anything and return success (true). */ 331| 1.33k| if (httpResponseData->onWritable) { ------------------ | Branch (331:17): [True: 0, False: 1.33k] ------------------ 332| | /* We are now writable, so hang timeout again, the user does not have to do anything so we should hang until end or tryEnd rearms timeout */ 333| 0| us_socket_timeout(SSL, s, 0); 334| | 335| | /* We expect the developer to return whether or not write was successful (true). 336| | * If write was never called, the developer should still return true so that we may drain. */ 337| 0| bool success = httpResponseData->callOnWritable(httpResponseData->offset); 338| | 339| | /* The developer indicated that their onWritable failed. */ 340| 0| if (!success) { ------------------ | Branch (340:21): [True: 0, False: 0] ------------------ 341| | /* Skip testing if we can drain anything since that might perform an extra syscall */ 342| 0| return s; 343| 0| } 344| | 345| | /* We don't want to fall through since we don't want to mess with timeout. 346| | * It makes little sense to drain any backpressure when the user has registered onWritable. */ 347| 0| return s; 348| 0| } 349| | 350| | /* Drain any socket buffer, this might empty our backpressure and thus finish the request */ 351| 1.33k| /*auto [written, failed] = */asyncSocket->write(nullptr, 0, true, 0); 352| | 353| | /* Should we close this connection after a response - and is this response really done? */ 354| 1.33k| if (httpResponseData->state & HttpResponseData::HTTP_CONNECTION_CLOSE) { ------------------ | Branch (354:17): [True: 870, False: 462] ------------------ 355| 870| if ((httpResponseData->state & HttpResponseData::HTTP_RESPONSE_PENDING) == 0) { ------------------ | Branch (355:21): [True: 870, False: 0] ------------------ 356| 870| if (asyncSocket->getBufferedAmount() == 0) { ------------------ | Branch (356:25): [True: 203, False: 667] ------------------ 357| 203| asyncSocket->shutdown(); 358| | /* We need to force close after sending FIN since we want to hinder 359| | * clients from keeping to send their huge data */ 360| 203| asyncSocket->close(); 361| 203| } 362| 870| } 363| 870| } 364| | 365| | /* Expect another writable event, or another request within the timeout */ 366| 1.33k| asyncSocket->timeout(HTTP_IDLE_TIMEOUT_S); 367| | 368| 1.33k| return s; 369| 1.33k| }); _ZZN3uWS11HttpContextILb0EE4initEvENKUlP11us_socket_tE0_clES3_: 372| 82.8k| us_socket_context_on_end(SSL, getSocketContext(), [](us_socket_t *s) { 373| | 374| | /* We do not care for half closed sockets */ 375| 82.8k| AsyncSocket *asyncSocket = (AsyncSocket *) s; 376| 82.8k| return asyncSocket->close(); 377| | 378| 82.8k| }); _ZZN3uWS11HttpContextILb0EE4initEvENKUlP11us_socket_tE1_clES3_: 381| 7.40k| us_socket_context_on_timeout(SSL, getSocketContext(), [](us_socket_t *s) { 382| | 383| | /* Force close rather than gracefully shutdown and risk confusing the client with a complete download */ 384| 7.40k| AsyncSocket *asyncSocket = (AsyncSocket *) s; 385| 7.40k| return asyncSocket->close(); 386| | 387| 7.40k| }); _ZN3uWS11HttpContextILb0EE6onHttpENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEES8_ON5ofats13any_invocableIFvPNS_12HttpResponseILb0EEEPNS_11HttpRequestEEEEb: 423| 17.5k| void onHttp(std::string method, std::string pattern, MoveOnlyFunction *, HttpRequest *)> &&handler, bool upgrade = false) { 424| 17.5k| HttpContextData *httpContextData = getSocketContextData(); 425| | 426| | /* Todo: This is ugly, fix */ 427| 17.5k| std::vector methods; 428| 17.5k| if (method == "*") { ------------------ | Branch (428:13): [True: 5.84k, False: 11.6k] ------------------ 429| 5.84k| methods = {"*"}; 430| 11.6k| } else { 431| 11.6k| methods = {method}; 432| 11.6k| } 433| | 434| 17.5k| uint32_t priority = method == "*" ? httpContextData->currentRouter->LOW_PRIORITY : (upgrade ? httpContextData->currentRouter->HIGH_PRIORITY : httpContextData->currentRouter->MEDIUM_PRIORITY); ------------------ | Branch (434:29): [True: 5.84k, False: 11.6k] | Branch (434:93): [True: 11.6k, False: 0] ------------------ 435| | 436| | /* If we are passed nullptr then remove this */ 437| 17.5k| if (!handler) { ------------------ | Branch (437:13): [True: 0, False: 17.5k] ------------------ 438| 0| httpContextData->currentRouter->remove(methods[0], pattern, priority); 439| 0| return; 440| 0| } 441| | 442| | /* Record this route's parameter offsets */ 443| 17.5k| std::map> parameterOffsets; 444| 17.5k| unsigned short offset = 0; 445| 99.4k| for (unsigned int i = 0; i < pattern.length(); i++) { ------------------ | Branch (445:34): [True: 81.8k, False: 17.5k] ------------------ 446| 81.8k| if (pattern[i] == ':') { ------------------ | Branch (446:17): [True: 0, False: 81.8k] ------------------ 447| 0| i++; 448| 0| unsigned int start = i; 449| 0| while (i < pattern.length() && pattern[i] != '/') { ------------------ | Branch (449:24): [True: 0, False: 0] | Branch (449:48): [True: 0, False: 0] ------------------ 450| 0| i++; 451| 0| } 452| 0| parameterOffsets[std::string(pattern.data() + start, i - start)] = offset; 453| | //std::cout << "<" << std::string(pattern.data() + start, i - start) << "> is offset " << offset; 454| 0| offset++; 455| 0| } 456| 81.8k| } 457| | 458| 17.5k| httpContextData->currentRouter->add(methods, pattern, [handler = std::move(handler), parameterOffsets = std::move(parameterOffsets)](auto *r) mutable { 459| 17.5k| auto user = r->getUserData(); 460| 17.5k| user.httpRequest->setYield(false); 461| 17.5k| user.httpRequest->setParameters(r->getParameters()); 462| 17.5k| user.httpRequest->setParameterOffsets(¶meterOffsets); 463| | 464| | /* Middleware? Automatically respond to expectations */ 465| 17.5k| std::string_view expect = user.httpRequest->getHeader("expect"); 466| 17.5k| if (expect.length() && expect == "100-continue") { 467| 17.5k| user.httpResponse->writeContinue(); 468| 17.5k| } 469| | 470| 17.5k| handler(user.httpResponse, user.httpRequest); 471| | 472| | /* If any handler yielded, the router will keep looking for a suitable handler. */ 473| 17.5k| if (user.httpRequest->getYield()) { 474| 17.5k| return false; 475| 17.5k| } 476| 17.5k| return true; 477| 17.5k| }, priority); 478| 17.5k| } _ZN3uWS11HttpContextILb0EE20getSocketContextDataEv: 61| 187k| HttpContextData *getSocketContextData() { 62| 187k| return (HttpContextData *) us_socket_context_ext(SSL, getSocketContext()); 63| 187k| } _ZZN3uWS11HttpContextILb0EE6onHttpENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEES8_ON5ofats13any_invocableIFvPNS_12HttpResponseILb0EEEPNS_11HttpRequestEEEEbENUlPT_E_clINS_10HttpRouterINS_15HttpContextDataILb0EE10RouterDataEEEEEDaSK_: 458| 176k| httpContextData->currentRouter->add(methods, pattern, [handler = std::move(handler), parameterOffsets = std::move(parameterOffsets)](auto *r) mutable { 459| 176k| auto user = r->getUserData(); 460| 176k| user.httpRequest->setYield(false); 461| 176k| user.httpRequest->setParameters(r->getParameters()); 462| 176k| user.httpRequest->setParameterOffsets(¶meterOffsets); 463| | 464| | /* Middleware? Automatically respond to expectations */ 465| 176k| std::string_view expect = user.httpRequest->getHeader("expect"); 466| 176k| if (expect.length() && expect == "100-continue") { ------------------ | Branch (466:17): [True: 753, False: 175k] | Branch (466:36): [True: 197, False: 556] ------------------ 467| 197| user.httpResponse->writeContinue(); 468| 197| } 469| | 470| 176k| handler(user.httpResponse, user.httpRequest); 471| | 472| | /* If any handler yielded, the router will keep looking for a suitable handler. */ 473| 176k| if (user.httpRequest->getYield()) { ------------------ | Branch (473:17): [True: 4.79k, False: 171k] ------------------ 474| 4.79k| return false; 475| 4.79k| } 476| 171k| return true; 477| 176k| }, priority); _ZN3uWS11HttpContextILb0EE4freeEv: 409| 5.84k| void free() { 410| | /* Destruct socket context data */ 411| 5.84k| HttpContextData *httpContextData = getSocketContextData(); 412| 5.84k| httpContextData->~HttpContextData(); 413| | 414| | /* Free the socket context in whole */ 415| 5.84k| us_socket_context_free(SSL, getSocketContext()); 416| 5.84k| } _ZN3uWS11HttpContextILb0EE6listenEPKcii: 481| 5.84k| us_listen_socket_t *listen(const char *host, int port, int options) { 482| 5.84k| return us_socket_context_listen(SSL, getSocketContext(), host, port, options, sizeof(HttpResponseData)); 483| 5.84k| } _ZN3uWS12optional_ptrIcEENSt3__18optionalIPT_EES4_: 47| 2|std::optional optional_ptr(T *ptr) { 48| 2| return ptr ? std::optional(ptr) : std::nullopt; ------------------ | Branch (48:12): [True: 0, False: 2] ------------------ 49| 2|} _ZN3uWS10HttpParser17consumePostPaddedEPcjPvS2_ON5ofats13any_invocableIFS2_S2_PNS_11HttpRequestEEEEONS4_IFS2_S2_NSt3__117basic_string_viewIcNSA_11char_traitsIcEEEEbEEE: 583| 592k| std::pair consumePostPadded(char *data, unsigned int length, void *user, void *reserved, MoveOnlyFunction &&requestHandler, MoveOnlyFunction &&dataHandler) { 584| | 585| | /* This resets BloomFilter by construction, but later we also reset it again. 586| | * Optimize this to skip resetting twice (req could be made global) */ 587| 592k| HttpRequest req; 588| | 589| 592k| if (remainingStreamingBytes) { ------------------ | Branch (589:13): [True: 0, False: 592k] ------------------ 590| | 591| | /* It's either chunked or with a content-length */ 592| 0| if (isParsingChunkedEncoding(remainingStreamingBytes)) { ------------------ | Branch (592:17): [True: 0, False: 0] ------------------ 593| 0| std::string_view dataToConsume(data, length); 594| 0| for (auto chunk : uWS::ChunkIterator(&dataToConsume, &remainingStreamingBytes)) { ------------------ | Branch (594:33): [True: 0, False: 0] ------------------ 595| 0| dataHandler(user, chunk, chunk.length() == 0); 596| 0| } 597| 0| if (isParsingInvalidChunkedEncoding(remainingStreamingBytes)) { ------------------ | Branch (597:21): [True: 0, False: 0] ------------------ 598| 0| return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR}; 599| 0| } 600| 0| data = (char *) dataToConsume.data(); 601| 0| length = (unsigned int) dataToConsume.length(); 602| 0| } else { 603| | // this is exactly the same as below! 604| | // todo: refactor this 605| 0| if (remainingStreamingBytes >= length) { ------------------ | Branch (605:21): [True: 0, False: 0] ------------------ 606| 0| void *returnedUser = dataHandler(user, std::string_view(data, length), remainingStreamingBytes == length); 607| 0| remainingStreamingBytes -= length; 608| 0| return {0, returnedUser}; 609| 0| } else { 610| 0| void *returnedUser = dataHandler(user, std::string_view(data, remainingStreamingBytes), true); 611| | 612| 0| data += (unsigned int) remainingStreamingBytes; 613| 0| length -= (unsigned int) remainingStreamingBytes; 614| | 615| 0| remainingStreamingBytes = 0; 616| | 617| 0| if (returnedUser != user) { ------------------ | Branch (617:25): [True: 0, False: 0] ------------------ 618| 0| return {0, returnedUser}; 619| 0| } 620| 0| } 621| 0| } 622| | 623| 592k| } else if (fallback.length()) { ------------------ | Branch (623:20): [True: 16.2k, False: 576k] ------------------ 624| 16.2k| unsigned int had = (unsigned int) fallback.length(); 625| | 626| 16.2k| size_t maxCopyDistance = std::min(MAX_FALLBACK_SIZE - fallback.length(), (size_t) length); 627| | 628| | /* We don't want fallback to be short string optimized, since we want to move it */ 629| 16.2k| fallback.reserve(fallback.length() + maxCopyDistance + std::max(MINIMUM_HTTP_POST_PADDING, sizeof(std::string))); 630| 16.2k| fallback.append(data, maxCopyDistance); 631| | 632| | // break here on break 633| 16.2k| std::pair consumed = fenceAndConsumePostPadded(fallback.data(), (unsigned int) fallback.length(), user, reserved, &req, requestHandler, dataHandler); 634| 16.2k| if (consumed.second != user) { ------------------ | Branch (634:17): [True: 1.80k, False: 14.4k] ------------------ 635| 1.80k| return consumed; 636| 1.80k| } 637| | 638| 14.4k| if (consumed.first) { ------------------ | Branch (638:17): [True: 1.60k, False: 12.8k] ------------------ 639| | 640| | /* This logic assumes that we consumed everything in fallback buffer. 641| | * This is critically important, as we will get an integer overflow in case 642| | * of "had" being larger than what we consumed, and that we would drop data */ 643| 1.60k| fallback.clear(); 644| 1.60k| data += consumed.first - had; 645| 1.60k| length -= consumed.first - had; 646| | 647| 1.60k| if (remainingStreamingBytes) { ------------------ | Branch (647:21): [True: 0, False: 1.60k] ------------------ 648| | /* It's either chunked or with a content-length */ 649| 0| if (isParsingChunkedEncoding(remainingStreamingBytes)) { ------------------ | Branch (649:25): [True: 0, False: 0] ------------------ 650| 0| std::string_view dataToConsume(data, length); 651| 0| for (auto chunk : uWS::ChunkIterator(&dataToConsume, &remainingStreamingBytes)) { ------------------ | Branch (651:41): [True: 0, False: 0] ------------------ 652| 0| dataHandler(user, chunk, chunk.length() == 0); 653| 0| } 654| 0| if (isParsingInvalidChunkedEncoding(remainingStreamingBytes)) { ------------------ | Branch (654:29): [True: 0, False: 0] ------------------ 655| 0| return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR}; 656| 0| } 657| 0| data = (char *) dataToConsume.data(); 658| 0| length = (unsigned int) dataToConsume.length(); 659| 0| } else { 660| | // this is exactly the same as above! 661| 0| if (remainingStreamingBytes >= (unsigned int) length) { ------------------ | Branch (661:29): [True: 0, False: 0] ------------------ 662| 0| void *returnedUser = dataHandler(user, std::string_view(data, length), remainingStreamingBytes == (unsigned int) length); 663| 0| remainingStreamingBytes -= length; 664| 0| return {0, returnedUser}; 665| 0| } else { 666| 0| void *returnedUser = dataHandler(user, std::string_view(data, remainingStreamingBytes), true); 667| | 668| 0| data += (unsigned int) remainingStreamingBytes; 669| 0| length -= (unsigned int) remainingStreamingBytes; 670| | 671| 0| remainingStreamingBytes = 0; 672| | 673| 0| if (returnedUser != user) { ------------------ | Branch (673:33): [True: 0, False: 0] ------------------ 674| 0| return {0, returnedUser}; 675| 0| } 676| 0| } 677| 0| } 678| 0| } 679| | 680| 12.8k| } else { 681| 12.8k| if (fallback.length() == MAX_FALLBACK_SIZE) { ------------------ | Branch (681:21): [True: 196, False: 12.6k] ------------------ 682| 196| return {HTTP_ERROR_431_REQUEST_HEADER_FIELDS_TOO_LARGE, FULLPTR}; 683| 196| } 684| 12.6k| return {0, user}; 685| 12.8k| } 686| 14.4k| } 687| | 688| 578k| std::pair consumed = fenceAndConsumePostPadded(data, length, user, reserved, &req, requestHandler, dataHandler); 689| 578k| if (consumed.second != user) { ------------------ | Branch (689:13): [True: 560k, False: 17.2k] ------------------ 690| 560k| return consumed; 691| 560k| } 692| | 693| 17.2k| data += consumed.first; 694| 17.2k| length -= consumed.first; 695| | 696| 17.2k| if (length) { ------------------ | Branch (696:13): [True: 15.4k, False: 1.81k] ------------------ 697| 15.4k| if (length < MAX_FALLBACK_SIZE) { ------------------ | Branch (697:17): [True: 15.4k, False: 0] ------------------ 698| 15.4k| fallback.append(data, length); 699| 15.4k| } else { 700| 0| return {HTTP_ERROR_431_REQUEST_HEADER_FIELDS_TOO_LARGE, FULLPTR}; 701| 0| } 702| 15.4k| } 703| | 704| | // added for now 705| 17.2k| return {0, user}; 706| 17.2k| } _ZN3uWS10HttpParser25fenceAndConsumePostPaddedILi1EEENSt3__14pairIjPvEEPcjS4_S4_PNS_11HttpRequestERN5ofats13any_invocableIFS4_S4_S8_EEERNSA_IFS4_S4_NS2_17basic_string_viewIcNS2_11char_traitsIcEEEEbEEE: 448| 16.2k| std::pair fenceAndConsumePostPadded(char *data, unsigned int length, void *user, void *reserved, HttpRequest *req, MoveOnlyFunction &requestHandler, MoveOnlyFunction &dataHandler) { 449| | 450| | /* How much data we CONSUMED (to throw away) */ 451| 16.2k| unsigned int consumedTotal = 0; 452| 16.2k| unsigned int err = 0; 453| | 454| | /* Fence two bytes past end of our buffer (buffer has post padded margins). 455| | * This is to always catch scan for \r but not for \r\n. */ 456| 16.2k| data[length] = '\r'; 457| 16.2k| data[length + 1] = 'a'; /* Anything that is not \n, to trigger "invalid request" */ 458| | 459| 16.2k| for (unsigned int consumed; length && (consumed = getHeaders(data, data + length, req->headers, reserved, err)); ) { ------------------ | Branch (459:37): [True: 16.2k, False: 0] | Branch (459:47): [True: 3.40k, False: 12.8k] ------------------ 460| 3.40k| data += consumed; 461| 3.40k| length -= consumed; 462| 3.40k| consumedTotal += consumed; 463| | 464| | /* Even if we could parse it, check for length here as well */ 465| 3.40k| if (consumed > MAX_FALLBACK_SIZE) { ------------------ | Branch (465:17): [True: 0, False: 3.40k] ------------------ 466| 0| return {HTTP_ERROR_431_REQUEST_HEADER_FIELDS_TOO_LARGE, FULLPTR}; 467| 0| } 468| | 469| | /* Store HTTP version (ancient 1.0 or 1.1) */ 470| 3.40k| req->ancientHttp = false; 471| | 472| | /* Add all headers to bloom filter */ 473| 3.40k| req->bf.reset(); 474| 11.1k| for (HttpRequest::Header *h = req->headers; (++h)->key.length(); ) { ------------------ | Branch (474:57): [True: 7.69k, False: 3.40k] ------------------ 475| 7.69k| req->bf.add(h->key); 476| 7.69k| } 477| | 478| | /* Break if no host header (but we can have empty string which is different from nullptr) */ 479| 3.40k| if (!req->getHeader("host").data()) { ------------------ | Branch (479:17): [True: 481, False: 2.92k] ------------------ 480| 481| return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR}; 481| 481| } 482| | 483| | /* RFC 9112 6.3 484| | * If a message is received with both a Transfer-Encoding and a Content-Length header field, 485| | * the Transfer-Encoding overrides the Content-Length. Such a message might indicate an attempt 486| | * to perform request smuggling (Section 11.2) or response splitting (Section 11.1) and 487| | * ought to be handled as an error. */ 488| 2.92k| std::string_view transferEncodingString = req->getHeader("transfer-encoding"); 489| 2.92k| std::string_view contentLengthString = req->getHeader("content-length"); 490| 2.92k| if (transferEncodingString.length() && contentLengthString.length()) { ------------------ | Branch (490:17): [True: 0, False: 2.92k] | Branch (490:52): [True: 0, False: 0] ------------------ 491| | /* Returning fullptr is the same as calling the errorHandler */ 492| | /* We could be smart and set an error in the context along with this, to indicate what 493| | * http error response we might want to return */ 494| 0| return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR}; 495| 0| } 496| | 497| | /* Parse query */ 498| 2.92k| const char *querySeparatorPtr = (const char *) memchr(req->headers->value.data(), '?', req->headers->value.length()); 499| 2.92k| req->querySeparator = (unsigned int) ((querySeparatorPtr ? querySeparatorPtr : req->headers->value.data() + req->headers->value.length()) - req->headers->value.data()); ------------------ | Branch (499:52): [True: 1.05k, False: 1.87k] ------------------ 500| | 501| | /* If returned socket is not what we put in we need 502| | * to break here as we either have upgraded to 503| | * WebSockets or otherwise closed the socket. */ 504| 2.92k| void *returnedUser = requestHandler(user, req); 505| 2.92k| if (returnedUser != user) { ------------------ | Branch (505:17): [True: 1.32k, False: 1.60k] ------------------ 506| | /* We are upgraded to WebSocket or otherwise broken */ 507| 1.32k| return {consumedTotal, returnedUser}; 508| 1.32k| } 509| | 510| | /* The rules at play here according to RFC 9112 for requests are essentially: 511| | * If both content-length and transfer-encoding then invalid message; must break. 512| | * If has transfer-encoding then must be chunked regardless of value. 513| | * If content-length then fixed length even if 0. 514| | * If none of the above then fixed length is 0. */ 515| | 516| | /* RFC 9112 6.3 517| | * If a message is received with both a Transfer-Encoding and a Content-Length header field, 518| | * the Transfer-Encoding overrides the Content-Length. */ 519| 1.60k| if (transferEncodingString.length()) { ------------------ | Branch (519:17): [True: 0, False: 1.60k] ------------------ 520| | 521| | /* If a proxy sent us the transfer-encoding header that 100% means it must be chunked or else the proxy is 522| | * not RFC 9112 compliant. Therefore it is always better to assume this is the case, since that entirely eliminates 523| | * all forms of transfer-encoding obfuscation tricks. We just rely on the header. */ 524| | 525| | /* RFC 9112 6.3 526| | * If a Transfer-Encoding header field is present in a request and the chunked transfer coding is not the 527| | * final encoding, the message body length cannot be determined reliably; the server MUST respond with the 528| | * 400 (Bad Request) status code and then close the connection. */ 529| | 530| | /* In this case we fail later by having the wrong interpretation (assuming chunked). 531| | * This could be made stricter but makes no difference either way, unless forwarding the identical message as a proxy. */ 532| | 533| 0| remainingStreamingBytes = STATE_IS_CHUNKED; 534| | /* If consume minimally, we do not want to consume anything but we want to mark this as being chunked */ 535| 0| if (!CONSUME_MINIMALLY) { ------------------ | Branch (535:21): [Folded - Ignored] ------------------ 536| | /* Go ahead and parse it (todo: better heuristics for emitting FIN to the app level) */ 537| 0| std::string_view dataToConsume(data, length); 538| 0| for (auto chunk : uWS::ChunkIterator(&dataToConsume, &remainingStreamingBytes)) { ------------------ | Branch (538:37): [True: 0, False: 0] ------------------ 539| 0| dataHandler(user, chunk, chunk.length() == 0); 540| 0| } 541| 0| if (isParsingInvalidChunkedEncoding(remainingStreamingBytes)) { ------------------ | Branch (541:25): [True: 0, False: 0] ------------------ 542| 0| return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR}; 543| 0| } 544| 0| unsigned int consumed = (length - (unsigned int) dataToConsume.length()); 545| 0| data = (char *) dataToConsume.data(); 546| 0| length = (unsigned int) dataToConsume.length(); 547| 0| consumedTotal += consumed; 548| 0| } 549| 1.60k| } else if (contentLengthString.length()) { ------------------ | Branch (549:24): [True: 0, False: 1.60k] ------------------ 550| 0| remainingStreamingBytes = toUnsignedInteger(contentLengthString); 551| 0| if (remainingStreamingBytes == UINT64_MAX) { ------------------ | Branch (551:21): [True: 0, False: 0] ------------------ 552| | /* Parser error */ 553| 0| return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR}; 554| 0| } 555| | 556| 0| if (!CONSUME_MINIMALLY) { ------------------ | Branch (556:21): [Folded - Ignored] ------------------ 557| 0| unsigned int emittable = (unsigned int) std::min(remainingStreamingBytes, length); 558| 0| dataHandler(user, std::string_view(data, emittable), emittable == remainingStreamingBytes); 559| 0| remainingStreamingBytes -= emittable; 560| | 561| 0| data += emittable; 562| 0| length -= emittable; 563| 0| consumedTotal += emittable; 564| 0| } 565| 1.60k| } else { 566| | /* If we came here without a body; emit an empty data chunk to signal no data */ 567| 1.60k| dataHandler(user, {}, true); 568| 1.60k| } 569| | 570| | /* Consume minimally should break as easrly as possible */ 571| 1.60k| if (CONSUME_MINIMALLY) { ------------------ | Branch (571:17): [Folded - Ignored] ------------------ 572| 1.60k| break; 573| 1.60k| } 574| 1.60k| } 575| | /* Whenever we return FULLPTR, the interpretation of "consumed" should be the HttpError enum. */ 576| 14.4k| if (err) { ------------------ | Branch (576:13): [True: 0, False: 14.4k] ------------------ 577| 0| return {err, FULLPTR}; 578| 0| } 579| 14.4k| return {consumedTotal, user}; 580| 14.4k| } _ZN3uWS10HttpParser10getHeadersEPcS1_PNS_11HttpRequest6HeaderEPvRj: 337| 598k| static unsigned int getHeaders(char *postPaddedBuffer, char *end, struct HttpRequest::Header *headers, void *reserved, unsigned int &err) { 338| 598k| char *preliminaryKey, *preliminaryValue, *start = postPaddedBuffer; 339| | 340| | #ifdef UWS_WITH_PROXY 341| | /* ProxyParser is passed as reserved parameter */ 342| | ProxyParser *pp = (ProxyParser *) reserved; 343| | 344| | /* Parse PROXY protocol */ 345| | auto [done, offset] = pp->parse({postPaddedBuffer, (size_t) (end - postPaddedBuffer)}); 346| | if (!done) { 347| | /* We do not reset the ProxyParser (on filure) since it is tied to this 348| | * connection, which is really only supposed to ever get one PROXY frame 349| | * anyways. We do however allow multiple PROXY frames to be sent (overwrites former). */ 350| | return 0; 351| | } else { 352| | /* We have consumed this data so skip it */ 353| | postPaddedBuffer += offset; 354| | } 355| | #else 356| | /* This one is unused */ 357| 598k| (void) reserved; 358| 598k| (void) end; 359| 598k| #endif 360| | 361| | /* It is critical for fallback buffering logic that we only return with success 362| | * if we managed to parse a complete HTTP request (minus data). Returning success 363| | * for PROXY means we can end up succeeding, yet leaving bytes in the fallback buffer 364| | * which is then removed, and our counters to flip due to overflow and we end up with a crash */ 365| | 366| | /* The request line is different from the field names / field values */ 367| 598k| if (!(postPaddedBuffer = consumeRequestLine(postPaddedBuffer, headers[0]))) { ------------------ | Branch (367:13): [True: 397k, False: 201k] ------------------ 368| | /* Error - invalid request line */ 369| | /* Assuming it is 505 HTTP Version Not Supported */ 370| 397k| err = HTTP_ERROR_505_HTTP_VERSION_NOT_SUPPORTED; 371| 397k| return 0; 372| 397k| } 373| 201k| headers++; 374| | 375| 603k| for (unsigned int i = 1; i < UWS_HTTP_MAX_HEADERS_COUNT - 1; i++) { ------------------ | | 53| 603k|#define UWS_HTTP_MAX_HEADERS_COUNT 100 ------------------ | Branch (375:34): [True: 603k, False: 66] ------------------ 376| | /* Lower case and consume the field name */ 377| 603k| preliminaryKey = postPaddedBuffer; 378| 603k| postPaddedBuffer = (char *) consumeFieldName(postPaddedBuffer); 379| 603k| headers->key = std::string_view(preliminaryKey, (size_t) (postPaddedBuffer - preliminaryKey)); 380| | 381| | /* We should not accept whitespace between key and colon, so colon must foloow immediately */ 382| 603k| if (postPaddedBuffer[0] != ':') { ------------------ | Branch (382:17): [True: 6.29k, False: 596k] ------------------ 383| | /* Error: invalid chars in field name */ 384| 6.29k| return 0; 385| 6.29k| } 386| 596k| postPaddedBuffer++; 387| | 388| 596k| preliminaryValue = postPaddedBuffer; 389| | /* The goal of this call is to find next "\r\n", or any invalid field value chars, fast */ 390| 598k| while (true) { ------------------ | Branch (390:20): [Folded - Ignored] ------------------ 391| 598k| postPaddedBuffer = (char *) tryConsumeFieldValue(postPaddedBuffer); 392| | /* If this is not CR then we caught some stinky invalid char on the way */ 393| 598k| if (postPaddedBuffer[0] != '\r') { ------------------ | Branch (393:21): [True: 4.37k, False: 593k] ------------------ 394| | /* If TAB then keep searching */ 395| 4.37k| if (postPaddedBuffer[0] == '\t') { ------------------ | Branch (395:25): [True: 1.50k, False: 2.86k] ------------------ 396| 1.50k| postPaddedBuffer++; 397| 1.50k| continue; 398| 1.50k| } 399| | /* Error - invalid chars in field value */ 400| 2.86k| return 0; 401| 4.37k| } 402| 593k| break; 403| 598k| } 404| | /* We fence end[0] with \r, followed by end[1] being something that is "not \n", to signify "not found". 405| | * This way we can have this one single check to see if we found \r\n WITHIN our allowed search space. */ 406| 593k| if (postPaddedBuffer[1] == '\n') { ------------------ | Branch (406:17): [True: 576k, False: 17.2k] ------------------ 407| | /* Store this header, it is valid */ 408| 576k| headers->value = std::string_view(preliminaryValue, (size_t) (postPaddedBuffer - preliminaryValue)); 409| 576k| postPaddedBuffer += 2; 410| | 411| | /* Trim trailing whitespace (SP, HTAB) */ 412| 740k| while (headers->value.length() && headers->value.back() < 33) { ------------------ | Branch (412:24): [True: 700k, False: 39.9k] | Branch (412:51): [True: 163k, False: 536k] ------------------ 413| 163k| headers->value.remove_suffix(1); 414| 163k| } 415| | 416| | /* Trim initial whitespace (SP, HTAB) */ 417| 616k| while (headers->value.length() && headers->value.front() < 33) { ------------------ | Branch (417:24): [True: 576k, False: 39.9k] | Branch (417:51): [True: 39.3k, False: 536k] ------------------ 418| 39.3k| headers->value.remove_prefix(1); 419| 39.3k| } 420| | 421| 576k| headers++; 422| | 423| | /* We definitely have at least one header (or request line), so check if we are done */ 424| 576k| if (*postPaddedBuffer == '\r') { ------------------ | Branch (424:21): [True: 174k, False: 401k] ------------------ 425| 174k| if (postPaddedBuffer[1] == '\n') { ------------------ | Branch (425:25): [True: 172k, False: 1.76k] ------------------ 426| | /* This cann take the very last header space */ 427| 172k| headers->key = std::string_view(nullptr, 0); 428| 172k| return (unsigned int) ((postPaddedBuffer + 2) - start); 429| 172k| } else { 430| | /* \r\n\r plus non-\n letter is malformed request, or simply out of search space */ 431| 1.76k| return 0; 432| 1.76k| } 433| 174k| } 434| 576k| } else { 435| | /* We are either out of search space or this is a malformed request */ 436| 17.2k| return 0; 437| 17.2k| } 438| 593k| } 439| | /* We ran out of header space, too large request */ 440| 66| return 0; 441| 201k| } _ZN3uWS10HttpParser18consumeRequestLineEPcRNS_11HttpRequest6HeaderE: 293| 598k| static inline char *consumeRequestLine(char *data, HttpRequest::Header &header) { 294| | /* Scan until single SP, assume next is / (origin request) */ 295| 598k| char *start = data; 296| | /* This catches the post padded CR and fails */ 297| 1.97M| while (data[0] > 32) data++; ------------------ | Branch (297:16): [True: 1.37M, False: 598k] ------------------ 298| 598k| if (data[0] == 32 && data[1] == '/') { ------------------ | Branch (298:13): [True: 239k, False: 359k] | Branch (298:30): [True: 209k, False: 29.4k] ------------------ 299| 209k| header.key = {start, (size_t) (data - start)}; 300| 209k| data++; 301| | /* Scan for less than 33 (catches post padded CR and fails) */ 302| 209k| start = data; 303| 364k| for (; true; data += 8) { ------------------ | Branch (303:20): [Folded - Ignored] ------------------ 304| 364k| uint64_t word; 305| 364k| memcpy(&word, data, sizeof(uint64_t)); 306| 364k| if (hasLess(word, 33)) { ------------------ | Branch (306:21): [True: 209k, False: 154k] ------------------ 307| 776k| while (*(unsigned char *)data > 32) data++; ------------------ | Branch (307:28): [True: 567k, False: 209k] ------------------ 308| | /* Now we stand on space */ 309| 209k| header.value = {start, (size_t) (data - start)}; 310| | /* Check that the following is http 1.1 */ 311| 209k| if (memcmp(" HTTP/1.1\r\n", data, 11) == 0) { ------------------ | Branch (311:25): [True: 201k, False: 8.42k] ------------------ 312| 201k| return data + 11; 313| 201k| } 314| 8.42k| return nullptr; 315| 209k| } 316| 364k| } 317| 209k| } 318| 388k| return nullptr; 319| 598k| } _ZN3uWS10HttpParser7hasLessEmm: 220| 1.80M| static inline uint64_t hasLess(uint64_t x, uint64_t n) { 221| 1.80M| return (((x)-~0ULL/255*(n))&~(x)&~0ULL/255*128); 222| 1.80M| } _ZN3uWS10HttpParser16consumeFieldNameEPc: 264| 603k| static inline void *consumeFieldName(char *p) { 265| | /* Best case fast path (particularly useful with clang) */ 266| 1.03M| while (true) { ------------------ | Branch (266:16): [Folded - Ignored] ------------------ 267| 1.03M| while ((*p >= 65) & (*p <= 90)) [[likely]] { ------------------ | Branch (267:20): [True: 5.31k, False: 1.03M] ------------------ 268| 5.31k| *p |= 32; 269| 5.31k| p++; 270| 5.31k| } 271| 5.39M| while (((*p >= 97) & (*p <= 122))) [[likely]] { ------------------ | Branch (271:20): [True: 4.36M, False: 1.03M] ------------------ 272| 4.36M| p++; 273| 4.36M| } 274| 1.03M| if (*p == ':') { ------------------ | Branch (274:17): [True: 593k, False: 437k] ------------------ 275| 593k| return (void *)p; 276| 593k| } 277| 437k| if (*p == '-') { ------------------ | Branch (277:17): [True: 425k, False: 12.5k] ------------------ 278| 425k| p++; 279| 425k| } else if (!((*p >= 65) & (*p <= 90))) { ------------------ | Branch (279:24): [True: 9.24k, False: 3.31k] ------------------ 280| | /* Exit fast path parsing */ 281| 9.24k| break; 282| 9.24k| } 283| 437k| } 284| | 285| | /* Generic */ 286| 97.0k| while (isFieldNameByteFastLowercased(*(unsigned char *)p)) { ------------------ | Branch (286:16): [True: 87.8k, False: 9.24k] ------------------ 287| 87.8k| p++; 288| 87.8k| } 289| 9.24k| return (void *)p; 290| 603k| } _ZN3uWS10HttpParser29isFieldNameByteFastLowercasedERh: 249| 97.0k| static inline bool isFieldNameByteFastLowercased(unsigned char &in) { 250| | /* Most common is lowercase alpha and hyphen */ 251| 97.0k| if (((in >= 97) & (in <= 122)) | (in == '-')) [[likely]] { ------------------ | Branch (251:13): [True: 79.5k, False: 17.4k] ------------------ 252| 79.5k| return true; 253| | /* Second is upper case alpha */ 254| 79.5k| } else if ((in >= 65) & (in <= 90)) [[unlikely]] { ------------------ | Branch (254:20): [True: 687, False: 16.8k] ------------------ 255| 687| in |= 32; 256| 687| return true; 257| | /* These are rarely used but still valid */ 258| 16.8k| } else if (isUnlikelyFieldNameByte(in)) [[unlikely]] { ------------------ | Branch (258:20): [True: 7.56k, False: 9.24k] ------------------ 259| 7.56k| return true; 260| 7.56k| } 261| 9.24k| return false; 262| 97.0k| } _ZN3uWS10HttpParser23isUnlikelyFieldNameByteEh: 243| 16.8k| { 244| | /* Digits and 14 of the 15 non-alphanum characters (lacking hyphen) */ 245| 16.8k| return ((c == '~') | (c == '|') | (c == '`') | (c == '_') | (c == '^') | (c == '.') | (c == '+') ------------------ | Branch (245:16): [True: 1.83k, False: 14.9k] ------------------ 246| 16.8k| | (c == '*') | (c == '!')) || ((c >= 48) & (c <= 57)) || ((c <= 39) & (c >= 35)); ------------------ | Branch (246:43): [True: 4.35k, False: 10.6k] | Branch (246:70): [True: 1.37k, False: 9.24k] ------------------ 247| 16.8k| } _ZN3uWS10HttpParser20tryConsumeFieldValueEPc: 325| 598k| static inline void *tryConsumeFieldValue(char *p) { 326| 1.44M| for (; true; p += 8) { ------------------ | Branch (326:16): [Folded - Ignored] ------------------ 327| 1.44M| uint64_t word; 328| 1.44M| memcpy(&word, p, sizeof(uint64_t)); 329| 1.44M| if (hasLess(word, 32)) { ------------------ | Branch (329:17): [True: 598k, False: 842k] ------------------ 330| 2.11M| while (*(unsigned char *)p > 31) p++; ------------------ | Branch (330:24): [True: 1.52M, False: 598k] ------------------ 331| 598k| return (void *)p; 332| 598k| } 333| 1.44M| } 334| 598k| } _ZN3uWS11HttpRequest9getHeaderENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE: 115| 1.52M| std::string_view getHeader(std::string_view lowerCasedHeader) { 116| 1.52M| if (bf.mightHave(lowerCasedHeader)) { ------------------ | Branch (116:13): [True: 359k, False: 1.16M] ------------------ 117| 862k| for (Header *h = headers; (++h)->key.length(); ) { ------------------ | Branch (117:39): [True: 859k, False: 2.79k] ------------------ 118| 859k| if (h->key.length() == lowerCasedHeader.length() && !strncmp(h->key.data(), lowerCasedHeader.data(), lowerCasedHeader.length())) { ------------------ | Branch (118:21): [True: 359k, False: 500k] | Branch (118:69): [True: 356k, False: 2.83k] ------------------ 119| 356k| return h->value; 120| 356k| } 121| 859k| } 122| 359k| } 123| 1.17M| return std::string_view(nullptr, 0); 124| 1.52M| } _ZN3uWS10HttpParser25fenceAndConsumePostPaddedILi0EEENSt3__14pairIjPvEEPcjS4_S4_PNS_11HttpRequestERN5ofats13any_invocableIFS4_S4_S8_EEERNSA_IFS4_S4_NS2_17basic_string_viewIcNS2_11char_traitsIcEEEEbEEE: 448| 578k| std::pair fenceAndConsumePostPadded(char *data, unsigned int length, void *user, void *reserved, HttpRequest *req, MoveOnlyFunction &requestHandler, MoveOnlyFunction &dataHandler) { 449| | 450| | /* How much data we CONSUMED (to throw away) */ 451| 578k| unsigned int consumedTotal = 0; 452| 578k| unsigned int err = 0; 453| | 454| | /* Fence two bytes past end of our buffer (buffer has post padded margins). 455| | * This is to always catch scan for \r but not for \r\n. */ 456| 578k| data[length] = '\r'; 457| 578k| data[length + 1] = 'a'; /* Anything that is not \n, to trigger "invalid request" */ 458| | 459| 584k| for (unsigned int consumed; length && (consumed = getHeaders(data, data + length, req->headers, reserved, err)); ) { ------------------ | Branch (459:37): [True: 582k, False: 1.81k] | Branch (459:47): [True: 169k, False: 412k] ------------------ 460| 169k| data += consumed; 461| 169k| length -= consumed; 462| 169k| consumedTotal += consumed; 463| | 464| | /* Even if we could parse it, check for length here as well */ 465| 169k| if (consumed > MAX_FALLBACK_SIZE) { ------------------ | Branch (465:17): [True: 0, False: 169k] ------------------ 466| 0| return {HTTP_ERROR_431_REQUEST_HEADER_FIELDS_TOO_LARGE, FULLPTR}; 467| 0| } 468| | 469| | /* Store HTTP version (ancient 1.0 or 1.1) */ 470| 169k| req->ancientHttp = false; 471| | 472| | /* Add all headers to bloom filter */ 473| 169k| req->bf.reset(); 474| 671k| for (HttpRequest::Header *h = req->headers; (++h)->key.length(); ) { ------------------ | Branch (474:57): [True: 501k, False: 169k] ------------------ 475| 501k| req->bf.add(h->key); 476| 501k| } 477| | 478| | /* Break if no host header (but we can have empty string which is different from nullptr) */ 479| 169k| if (!req->getHeader("host").data()) { ------------------ | Branch (479:17): [True: 607, False: 168k] ------------------ 480| 607| return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR}; 481| 607| } 482| | 483| | /* RFC 9112 6.3 484| | * If a message is received with both a Transfer-Encoding and a Content-Length header field, 485| | * the Transfer-Encoding overrides the Content-Length. Such a message might indicate an attempt 486| | * to perform request smuggling (Section 11.2) or response splitting (Section 11.1) and 487| | * ought to be handled as an error. */ 488| 168k| std::string_view transferEncodingString = req->getHeader("transfer-encoding"); 489| 168k| std::string_view contentLengthString = req->getHeader("content-length"); 490| 168k| if (transferEncodingString.length() && contentLengthString.length()) { ------------------ | Branch (490:17): [True: 0, False: 168k] | Branch (490:52): [True: 0, False: 0] ------------------ 491| | /* Returning fullptr is the same as calling the errorHandler */ 492| | /* We could be smart and set an error in the context along with this, to indicate what 493| | * http error response we might want to return */ 494| 0| return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR}; 495| 0| } 496| | 497| | /* Parse query */ 498| 168k| const char *querySeparatorPtr = (const char *) memchr(req->headers->value.data(), '?', req->headers->value.length()); 499| 168k| req->querySeparator = (unsigned int) ((querySeparatorPtr ? querySeparatorPtr : req->headers->value.data() + req->headers->value.length()) - req->headers->value.data()); ------------------ | Branch (499:52): [True: 21.5k, False: 147k] ------------------ 500| | 501| | /* If returned socket is not what we put in we need 502| | * to break here as we either have upgraded to 503| | * WebSockets or otherwise closed the socket. */ 504| 168k| void *returnedUser = requestHandler(user, req); 505| 168k| if (returnedUser != user) { ------------------ | Branch (505:17): [True: 162k, False: 5.95k] ------------------ 506| | /* We are upgraded to WebSocket or otherwise broken */ 507| 162k| return {consumedTotal, returnedUser}; 508| 162k| } 509| | 510| | /* The rules at play here according to RFC 9112 for requests are essentially: 511| | * If both content-length and transfer-encoding then invalid message; must break. 512| | * If has transfer-encoding then must be chunked regardless of value. 513| | * If content-length then fixed length even if 0. 514| | * If none of the above then fixed length is 0. */ 515| | 516| | /* RFC 9112 6.3 517| | * If a message is received with both a Transfer-Encoding and a Content-Length header field, 518| | * the Transfer-Encoding overrides the Content-Length. */ 519| 5.95k| if (transferEncodingString.length()) { ------------------ | Branch (519:17): [True: 0, False: 5.95k] ------------------ 520| | 521| | /* If a proxy sent us the transfer-encoding header that 100% means it must be chunked or else the proxy is 522| | * not RFC 9112 compliant. Therefore it is always better to assume this is the case, since that entirely eliminates 523| | * all forms of transfer-encoding obfuscation tricks. We just rely on the header. */ 524| | 525| | /* RFC 9112 6.3 526| | * If a Transfer-Encoding header field is present in a request and the chunked transfer coding is not the 527| | * final encoding, the message body length cannot be determined reliably; the server MUST respond with the 528| | * 400 (Bad Request) status code and then close the connection. */ 529| | 530| | /* In this case we fail later by having the wrong interpretation (assuming chunked). 531| | * This could be made stricter but makes no difference either way, unless forwarding the identical message as a proxy. */ 532| | 533| 0| remainingStreamingBytes = STATE_IS_CHUNKED; 534| | /* If consume minimally, we do not want to consume anything but we want to mark this as being chunked */ 535| 0| if (!CONSUME_MINIMALLY) { ------------------ | Branch (535:21): [Folded - Ignored] ------------------ 536| | /* Go ahead and parse it (todo: better heuristics for emitting FIN to the app level) */ 537| 0| std::string_view dataToConsume(data, length); 538| 0| for (auto chunk : uWS::ChunkIterator(&dataToConsume, &remainingStreamingBytes)) { ------------------ | Branch (538:37): [True: 0, False: 0] ------------------ 539| 0| dataHandler(user, chunk, chunk.length() == 0); 540| 0| } 541| 0| if (isParsingInvalidChunkedEncoding(remainingStreamingBytes)) { ------------------ | Branch (541:25): [True: 0, False: 0] ------------------ 542| 0| return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR}; 543| 0| } 544| 0| unsigned int consumed = (length - (unsigned int) dataToConsume.length()); 545| 0| data = (char *) dataToConsume.data(); 546| 0| length = (unsigned int) dataToConsume.length(); 547| 0| consumedTotal += consumed; 548| 0| } 549| 5.95k| } else if (contentLengthString.length()) { ------------------ | Branch (549:24): [True: 0, False: 5.95k] ------------------ 550| 0| remainingStreamingBytes = toUnsignedInteger(contentLengthString); 551| 0| if (remainingStreamingBytes == UINT64_MAX) { ------------------ | Branch (551:21): [True: 0, False: 0] ------------------ 552| | /* Parser error */ 553| 0| return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR}; 554| 0| } 555| | 556| 0| if (!CONSUME_MINIMALLY) { ------------------ | Branch (556:21): [Folded - Ignored] ------------------ 557| 0| unsigned int emittable = (unsigned int) std::min(remainingStreamingBytes, length); 558| 0| dataHandler(user, std::string_view(data, emittable), emittable == remainingStreamingBytes); 559| 0| remainingStreamingBytes -= emittable; 560| | 561| 0| data += emittable; 562| 0| length -= emittable; 563| 0| consumedTotal += emittable; 564| 0| } 565| 5.95k| } else { 566| | /* If we came here without a body; emit an empty data chunk to signal no data */ 567| 5.95k| dataHandler(user, {}, true); 568| 5.95k| } 569| | 570| | /* Consume minimally should break as easrly as possible */ 571| 5.95k| if (CONSUME_MINIMALLY) { ------------------ | Branch (571:17): [Folded - Ignored] ------------------ 572| 0| break; 573| 0| } 574| 5.95k| } 575| | /* Whenever we return FULLPTR, the interpretation of "consumed" should be the HttpError enum. */ 576| 414k| if (err) { ------------------ | Branch (576:13): [True: 397k, False: 17.2k] ------------------ 577| 397k| return {err, FULLPTR}; 578| 397k| } 579| 17.2k| return {consumedTotal, user}; 580| 414k| } _ZN3uWS11HttpRequest9isAncientEv: 72| 171k| bool isAncient() { 73| 171k| return ancientHttp; 74| 171k| } _ZN3uWS11HttpRequest22getCaseSensitiveMethodEv: 135| 171k| std::string_view getCaseSensitiveMethod() { 136| 171k| return std::string_view(headers->key.data(), headers->key.length()); 137| 171k| } _ZN3uWS11HttpRequest6getUrlEv: 126| 171k| std::string_view getUrl() { 127| 171k| return std::string_view(headers->value.data(), querySeparator); 128| 171k| } _ZN3uWS11HttpRequest8setYieldEb: 111| 181k| void setYield(bool yield) { 112| 181k| didYield = yield; 113| 181k| } _ZN3uWS11HttpRequest13setParametersENSt3__14pairIiPNS1_17basic_string_viewIcNS1_11char_traitsIcEEEEEE: 166| 176k| void setParameters(std::pair parameters) { 167| 176k| currentParameters = parameters; 168| 176k| } _ZN3uWS11HttpRequest19setParameterOffsetsEPNSt3__13mapINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEtNS1_4lessIvEENS6_INS1_4pairIKS8_tEEEEEE: 170| 176k| void setParameterOffsets(std::map> *offsets) { 171| 176k| currentParameterOffsets = offsets; 172| 176k| } _ZN3uWS11HttpRequest8getYieldEv: 76| 176k| bool getYield() { 77| 176k| return didYield; 78| 176k| } _ZN3uWS12HttpResponseILb0EE12hasRespondedEv: 490| 15.1k| bool hasResponded() { 491| 15.1k| HttpResponseData *httpResponseData = getHttpResponseData(); 492| | 493| 15.1k| return !(httpResponseData->state & HttpResponseData::HTTP_RESPONSE_PENDING); 494| 15.1k| } _ZN3uWS12HttpResponseILb0EE19getHttpResponseDataEv: 52| 1.69M| HttpResponseData *getHttpResponseData() { 53| 1.69M| return (HttpResponseData *) Super::getAsyncSocketData(); 54| 1.69M| } _ZN3uWS12HttpResponseILb0EE13writeContinueEv: 377| 197| HttpResponse *writeContinue() { 378| 197| Super::write("HTTP/1.1 100 Continue\r\n\r\n", 25); 379| 197| return this; 380| 197| } _ZN3uWS12HttpResponseILb0EE11writeStatusENSt3__117basic_string_viewIcNS2_11char_traitsIcEEEE: 383| 1.18M| HttpResponse *writeStatus(std::string_view status) { 384| 1.18M| HttpResponseData *httpResponseData = getHttpResponseData(); 385| | 386| | /* Do not allow writing more than one status */ 387| 1.18M| if (httpResponseData->state & HttpResponseData::HTTP_STATUS_CALLED) { ------------------ | Branch (387:13): [True: 1.01M, False: 171k] ------------------ 388| 1.01M| return this; 389| 1.01M| } 390| | 391| | /* Update status */ 392| 171k| httpResponseData->state |= HttpResponseData::HTTP_STATUS_CALLED; 393| | 394| 171k| Super::write("HTTP/1.1 ", 9); 395| 171k| Super::write(status.data(), (int) status.length()); 396| 171k| Super::write("\r\n", 2); 397| 171k| return this; 398| 1.18M| } _ZN3uWS12HttpResponseILb0EE3endENSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEb: 432| 7.55k| void end(std::string_view data = {}, bool closeConnection = false) { 433| 7.55k| internalEnd(data, data.length(), false, true, closeConnection); 434| 7.55k| } _ZN3uWS12HttpResponseILb0EE11internalEndENSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEmbbb: 92| 171k| bool internalEnd(std::string_view data, uintmax_t totalSize, bool optional, bool allowContentLength = true, bool closeConnection = false) { 93| | /* Write status if not already done */ 94| 171k| writeStatus(HTTP_200_OK); 95| | 96| | /* If no total size given then assume this chunk is everything */ 97| 171k| if (!totalSize) { ------------------ | Branch (97:13): [True: 164k, False: 7.55k] ------------------ 98| 164k| totalSize = data.length(); 99| 164k| } 100| | 101| 171k| HttpResponseData *httpResponseData = getHttpResponseData(); 102| | 103| | /* In some cases, such as when refusing huge data we want to close the connection when drained */ 104| 171k| if (closeConnection) { ------------------ | Branch (104:13): [True: 0, False: 171k] ------------------ 105| | 106| | /* HTTP 1.1 must send this back unless the client already sent it to us. 107| | * It is a connection close when either of the two parties say so but the 108| | * one party must tell the other one so. 109| | * 110| | * This check also serves to limit writing the header only once. */ 111| 0| if ((httpResponseData->state & HttpResponseData::HTTP_CONNECTION_CLOSE) == 0) { ------------------ | Branch (111:17): [True: 0, False: 0] ------------------ 112| 0| writeHeader("Connection", "close"); 113| 0| } 114| | 115| 0| httpResponseData->state |= HttpResponseData::HTTP_CONNECTION_CLOSE; 116| 0| } 117| | 118| 171k| if (httpResponseData->state & HttpResponseData::HTTP_WRITE_CALLED) { ------------------ | Branch (118:13): [True: 0, False: 171k] ------------------ 119| | 120| | /* We do not have tryWrite-like functionalities, so ignore optional in this path */ 121| | 122| | /* Do not allow sending 0 chunk here */ 123| 0| if (data.length()) { ------------------ | Branch (123:17): [True: 0, False: 0] ------------------ 124| 0| Super::write("\r\n", 2); 125| 0| writeUnsignedHex((unsigned int) data.length()); 126| 0| Super::write("\r\n", 2); 127| | 128| | /* Ignoring optional for now */ 129| 0| Super::write(data.data(), (int) data.length()); 130| 0| } 131| | 132| | /* Terminating 0 chunk */ 133| 0| Super::write("\r\n0\r\n\r\n", 7); 134| | 135| 0| httpResponseData->markDone(); 136| | 137| | /* We need to check if we should close this socket here now */ 138| 0| if (!Super::isCorked()) { ------------------ | Branch (138:17): [True: 0, False: 0] ------------------ 139| 0| if (httpResponseData->state & HttpResponseData::HTTP_CONNECTION_CLOSE) { ------------------ | Branch (139:21): [True: 0, False: 0] ------------------ 140| 0| if ((httpResponseData->state & HttpResponseData::HTTP_RESPONSE_PENDING) == 0) { ------------------ | Branch (140:25): [True: 0, False: 0] ------------------ 141| 0| if (((AsyncSocket *) this)->getBufferedAmount() == 0) { ------------------ | Branch (141:29): [True: 0, False: 0] ------------------ 142| 0| ((AsyncSocket *) this)->shutdown(); 143| | /* We need to force close after sending FIN since we want to hinder 144| | * clients from keeping to send their huge data */ 145| 0| ((AsyncSocket *) this)->close(); 146| 0| return true; 147| 0| } 148| 0| } 149| 0| } 150| 0| } 151| | 152| | /* tryEnd can never fail when in chunked mode, since we do not have tryWrite (yet), only write */ 153| 0| Super::timeout(HTTP_TIMEOUT_S); 154| 0| return true; 155| 171k| } else { 156| | /* Write content-length on first call */ 157| 171k| if (!(httpResponseData->state & HttpResponseData::HTTP_END_CALLED)) { ------------------ | Branch (157:17): [True: 171k, False: 0] ------------------ 158| | /* Write mark, this propagates to WebSockets too */ 159| 171k| writeMark(); 160| | 161| | /* WebSocket upgrades does not allow content-length */ 162| 171k| if (allowContentLength) { ------------------ | Branch (162:21): [True: 7.55k, False: 164k] ------------------ 163| | /* Even zero is a valid content-length */ 164| 7.55k| Super::write("Content-Length: ", 16); 165| 7.55k| writeUnsigned64(totalSize); 166| 7.55k| Super::write("\r\n\r\n", 4); 167| 164k| } else { 168| 164k| Super::write("\r\n", 2); 169| 164k| } 170| | 171| | /* Mark end called */ 172| 171k| httpResponseData->state |= HttpResponseData::HTTP_END_CALLED; 173| 171k| } 174| | 175| | /* Even if we supply no new data to write, its failed boolean is useful to know 176| | * if it failed to drain any prior failed header writes */ 177| | 178| | /* Write as much as possible without causing backpressure */ 179| 171k| size_t written = 0; 180| 171k| bool failed = false; 181| 179k| while (written < data.length() && !failed) { ------------------ | Branch (181:20): [True: 7.55k, False: 171k] | Branch (181:47): [True: 7.55k, False: 0] ------------------ 182| | /* uSockets only deals with int sizes, so pass chunks of max signed int size */ 183| 7.55k| auto writtenFailed = Super::write(data.data() + written, (int) std::min(data.length() - written, INT_MAX), optional); 184| | 185| 7.55k| written += (size_t) writtenFailed.first; 186| 7.55k| failed = writtenFailed.second; 187| 7.55k| } 188| | 189| 171k| httpResponseData->offset += written; 190| | 191| | /* Success is when we wrote the entire thing without any failures */ 192| 171k| bool success = written == data.length() && !failed; ------------------ | Branch (192:28): [True: 171k, False: 0] | Branch (192:56): [True: 171k, False: 453] ------------------ 193| | 194| | /* If we are now at the end, start a timeout. Also start a timeout if we failed. */ 195| 171k| if (!success || httpResponseData->offset == totalSize) { ------------------ | Branch (195:17): [True: 453, False: 171k] | Branch (195:29): [True: 171k, False: 0] ------------------ 196| 171k| Super::timeout(HTTP_TIMEOUT_S); 197| 171k| } 198| | 199| | /* Remove onAborted function if we reach the end */ 200| 171k| if (httpResponseData->offset == totalSize) { ------------------ | Branch (200:17): [True: 171k, False: 0] ------------------ 201| 171k| httpResponseData->markDone(); 202| | 203| | /* We need to check if we should close this socket here now */ 204| 171k| if (!Super::isCorked()) { ------------------ | Branch (204:21): [True: 0, False: 171k] ------------------ 205| 0| if (httpResponseData->state & HttpResponseData::HTTP_CONNECTION_CLOSE) { ------------------ | Branch (205:25): [True: 0, False: 0] ------------------ 206| 0| if ((httpResponseData->state & HttpResponseData::HTTP_RESPONSE_PENDING) == 0) { ------------------ | Branch (206:29): [True: 0, False: 0] ------------------ 207| 0| if (((AsyncSocket *) this)->getBufferedAmount() == 0) { ------------------ | Branch (207:33): [True: 0, False: 0] ------------------ 208| 0| ((AsyncSocket *) this)->shutdown(); 209| | /* We need to force close after sending FIN since we want to hinder 210| | * clients from keeping to send their huge data */ 211| 0| ((AsyncSocket *) this)->close(); 212| 0| } 213| 0| } 214| 0| } 215| 0| } 216| 171k| } 217| | 218| 171k| return success; 219| 171k| } 220| 171k| } _ZN3uWS12HttpResponseILb0EE11writeHeaderENSt3__117basic_string_viewIcNS2_11char_traitsIcEEEES6_: 401| 840k| HttpResponse *writeHeader(std::string_view key, std::string_view value) { 402| 840k| writeStatus(HTTP_200_OK); 403| | 404| 840k| Super::write(key.data(), (int) key.length()); 405| 840k| Super::write(": ", 2); 406| 840k| Super::write(value.data(), (int) value.length()); 407| 840k| Super::write("\r\n", 2); 408| 840k| return this; 409| 840k| } _ZN3uWS12HttpResponseILb0EE9writeMarkEv: 77| 171k| void writeMark() { 78| | /* Date is always written */ 79| 171k| writeHeader("Date", std::string_view(((LoopData *) us_loop_ext(us_socket_context_loop(SSL, (us_socket_context(SSL, (us_socket_t *) this)))))->date, 29)); 80| | 81| | /* You can disable this altogether */ 82| 171k|#ifndef UWS_HTTPRESPONSE_NO_WRITEMARK 83| 171k| if (!Super::getLoopData()->noMark) { ------------------ | Branch (83:13): [True: 171k, False: 0] ------------------ 84| | /* We only expose major version */ 85| 171k| writeHeader("uWebSockets", "20"); 86| 171k| } 87| 171k|#endif 88| 171k| } _ZN3uWS12HttpResponseILb0EE15writeUnsigned64Em: 68| 7.55k| void writeUnsigned64(uint64_t value) { 69| 7.55k| char buf[20]; 70| 7.55k| int length = utils::u64toa(value, buf); 71| | 72| | /* For now we do this copy */ 73| 7.55k| Super::write(buf, length); 74| 7.55k| } EpollEchoServer.cpp:_ZN3uWS12HttpResponseILb0EE7upgradeIZ4testvE13PerSocketDataEEvOT_NSt3__117basic_string_viewIcNS6_11char_traitsIcEEEESA_SA_P19us_socket_context_t: 239| 164k| struct us_socket_context_t *webSocketContext) { 240| | 241| | /* Extract needed parameters from WebSocketContextData */ 242| 164k| WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, webSocketContext); 243| | 244| | /* Note: OpenSSL can be used here to speed this up somewhat */ 245| 164k| char secWebSocketAccept[29] = {}; 246| 164k| WebSocketHandshake::generate(secWebSocketKey.data(), secWebSocketAccept); 247| | 248| 164k| writeStatus("101 Switching Protocols") 249| 164k| ->writeHeader("Upgrade", "websocket") 250| 164k| ->writeHeader("Connection", "Upgrade") 251| 164k| ->writeHeader("Sec-WebSocket-Accept", secWebSocketAccept); 252| | 253| | /* Select first subprotocol if present */ 254| 164k| if (secWebSocketProtocol.length()) { ------------------ | Branch (254:13): [True: 411, False: 163k] ------------------ 255| 411| writeHeader("Sec-WebSocket-Protocol", secWebSocketProtocol.substr(0, secWebSocketProtocol.find(','))); 256| 411| } 257| | 258| | /* Negotiate compression */ 259| 164k| bool perMessageDeflate = false; 260| 164k| CompressOptions compressOptions = CompressOptions::DISABLED; 261| 164k| if (secWebSocketExtensions.length() && webSocketContextData->compression != DISABLED) { ------------------ | Branch (261:13): [True: 8.44k, False: 155k] | Branch (261:48): [True: 8.07k, False: 374] ------------------ 262| | 263| | /* Make sure to map SHARED_DECOMPRESSOR to windowBits = 0, not 1 */ 264| 8.07k| int wantedInflationWindow = 0; 265| 8.07k| if ((webSocketContextData->compression & CompressOptions::_DECOMPRESSOR_MASK) != CompressOptions::SHARED_DECOMPRESSOR) { ------------------ | Branch (265:17): [True: 8.07k, False: 0] ------------------ 266| 8.07k| wantedInflationWindow = (webSocketContextData->compression & CompressOptions::_DECOMPRESSOR_MASK) >> 8; 267| 8.07k| } 268| | 269| | /* Map from selected compressor (this automatically maps SHARED_COMPRESSOR to windowBits 0, not 1) */ 270| 8.07k| int wantedCompressionWindow = (webSocketContextData->compression & CompressOptions::_COMPRESSOR_MASK) >> 4; 271| | 272| 8.07k| auto [negCompression, negCompressionWindow, negInflationWindow, negResponse] = 273| 8.07k| negotiateCompression(true, wantedCompressionWindow, wantedInflationWindow, 274| 8.07k| secWebSocketExtensions); 275| | 276| 8.07k| if (negCompression) { ------------------ | Branch (276:17): [True: 3.71k, False: 4.36k] ------------------ 277| 3.71k| perMessageDeflate = true; 278| | 279| | /* Map from negotiated windowBits to compressor and decompressor */ 280| 3.71k| if (negCompressionWindow == 0) { ------------------ | Branch (280:21): [True: 1.50k, False: 2.21k] ------------------ 281| 1.50k| compressOptions = CompressOptions::SHARED_COMPRESSOR; 282| 2.21k| } else { 283| 2.21k| compressOptions = (CompressOptions) ((uint32_t) (negCompressionWindow << 4) 284| 2.21k| | (uint32_t) (negCompressionWindow - 7)); 285| | 286| | /* If we are dedicated and have the 3kb then correct any 4kb to 3kb, 287| | * (they both share the windowBits = 9) */ 288| 2.21k| if (webSocketContextData->compression & DEDICATED_COMPRESSOR_3KB) { ------------------ | Branch (288:25): [True: 2.21k, False: 0] ------------------ 289| 2.21k| compressOptions = DEDICATED_COMPRESSOR_3KB; 290| 2.21k| } 291| 2.21k| } 292| | 293| | /* Here we modify the above compression with negotiated decompressor */ 294| 3.71k| if (negInflationWindow == 0) { ------------------ | Branch (294:21): [True: 3.71k, False: 0] ------------------ 295| 3.71k| compressOptions = CompressOptions(compressOptions | CompressOptions::SHARED_DECOMPRESSOR); 296| 3.71k| } else { 297| 0| compressOptions = CompressOptions(compressOptions | (negInflationWindow << 8)); 298| 0| } 299| | 300| 3.71k| writeHeader("Sec-WebSocket-Extensions", negResponse); 301| 3.71k| } 302| 8.07k| } 303| | 304| 164k| internalEnd({nullptr, 0}, 0, false, false); 305| | 306| | /* Grab the httpContext from res */ 307| 164k| HttpContext *httpContext = (HttpContext *) us_socket_context(SSL, (struct us_socket_t *) this); 308| | 309| | /* Move any backpressure out of HttpResponse */ 310| 164k| BackPressure backpressure(std::move(((AsyncSocketData *) getHttpResponseData())->buffer)); 311| | 312| | /* Destroy HttpResponseData */ 313| 164k| getHttpResponseData()->~HttpResponseData(); 314| | 315| | /* Before we adopt and potentially change socket, check if we are corked */ 316| 164k| bool wasCorked = Super::isCorked(); 317| | 318| | /* Adopting a socket invalidates it, do not rely on it directly to carry any data */ 319| 164k| WebSocket *webSocket = (WebSocket *) us_socket_context_adopt_socket(SSL, 320| 164k| (us_socket_context_t *) webSocketContext, (us_socket_t *) this, sizeof(WebSocketData) + sizeof(UserData)); 321| | 322| | /* For whatever reason we were corked, update cork to the new socket */ 323| 164k| if (wasCorked) { ------------------ | Branch (323:13): [True: 164k, False: 0] ------------------ 324| 164k| webSocket->AsyncSocket::corkUnchecked(); 325| 164k| } 326| | 327| | /* Initialize websocket with any moved backpressure intact */ 328| 164k| webSocket->init(perMessageDeflate, compressOptions, std::move(backpressure)); 329| | 330| | /* We should only mark this if inside the parser; if upgrading "async" we cannot set this */ 331| 164k| HttpContextData *httpContextData = httpContext->getSocketContextData(); 332| 164k| if (httpContextData->isParsingHttp) { ------------------ | Branch (332:13): [True: 164k, False: 0] ------------------ 333| | /* We need to tell the Http parser that we changed socket */ 334| 164k| httpContextData->upgradedWebSocket = webSocket; 335| 164k| } 336| | 337| | /* Arm maxLifetime timeout */ 338| 164k| us_socket_long_timeout(SSL, (us_socket_t *) webSocket, webSocketContextData->maxLifetime); 339| | 340| | /* Arm idleTimeout */ 341| 164k| us_socket_timeout(SSL, (us_socket_t *) webSocket, webSocketContextData->idleTimeoutComponents.first); 342| | 343| | /* Move construct the UserData right before calling open handler */ 344| 164k| new (webSocket->getUserData()) UserData(std::move(userData)); 345| | 346| | /* Emit open event and start the timeout */ 347| 164k| if (webSocketContextData->openHandler) { ------------------ | Branch (347:13): [True: 164k, False: 0] ------------------ 348| 164k| webSocketContextData->openHandler(webSocket); 349| 164k| } 350| 164k| } _ZN3uWS16HttpResponseDataILb0EE8markDoneEv: 37| 171k| void markDone() { 38| 171k| onAborted = nullptr; 39| | /* Also remove onWritable so that we do not emit when draining behind the scenes. */ 40| 171k| onWritable = nullptr; 41| | 42| | /* We are done with this request */ 43| 171k| state &= ~HttpResponseData::HTTP_RESPONSE_PENDING; 44| 171k| } _ZN3uWS10HttpRouterINS_15HttpContextDataILb0EE10RouterDataEEC2Ev: 243| 5.84k| HttpRouter() { 244| | /* Always have ANY route */ 245| 5.84k| getNode(&root, std::string(ANY_METHOD_TOKEN.data(), ANY_METHOD_TOKEN.length()), false); 246| 5.84k| } _ZN3uWS10HttpRouterINS_15HttpContextDataILb0EE10RouterDataEE4NodeC2ENSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEE: 63| 35.0k| Node(std::string name) : name(name) {} _ZN3uWS10HttpRouterINS_15HttpContextDataILb0EE10RouterDataEE7getNodeEPNS4_4NodeENSt3__112basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEb: 81| 40.9k| Node *getNode(Node *parent, std::string child, bool isHighPriority) { 82| 40.9k| for (std::unique_ptr &node : parent->children) { ------------------ | Branch (82:42): [True: 23.3k, False: 29.2k] ------------------ 83| 23.3k| if (node->name == child && node->isHighPriority == isHighPriority) { ------------------ | Branch (83:17): [True: 11.6k, False: 11.6k] | Branch (83:40): [True: 11.6k, False: 0] ------------------ 84| 11.6k| return node.get(); 85| 11.6k| } 86| 23.3k| } 87| | 88| | /* Insert sorted, but keep order if parent is root (we sort methods by priority elsewhere) */ 89| 29.2k| std::unique_ptr newNode(new Node(child)); 90| 29.2k| newNode->isHighPriority = isHighPriority; 91| 29.2k| return parent->children.emplace(std::upper_bound(parent->children.begin(), parent->children.end(), newNode, [parent, this](auto &a, auto &b) { 92| | 93| 29.2k| if (a->isHighPriority != b->isHighPriority) { 94| 29.2k| return a->isHighPriority; 95| 29.2k| } 96| | 97| 29.2k| return b->name.length() && (parent != &root) && (lexicalOrder(b->name) < lexicalOrder(a->name)); 98| 29.2k| }), std::move(newNode))->get(); 99| 40.9k| } _ZZN3uWS10HttpRouterINS_15HttpContextDataILb0EE10RouterDataEE7getNodeEPNS4_4NodeENSt3__112basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEbENKUlRT_RT0_E_clIKNS7_10unique_ptrIS5_NS7_14default_deleteIS5_EEEESN_EEDaSF_SH_: 91| 11.6k| return parent->children.emplace(std::upper_bound(parent->children.begin(), parent->children.end(), newNode, [parent, this](auto &a, auto &b) { 92| | 93| 11.6k| if (a->isHighPriority != b->isHighPriority) { ------------------ | Branch (93:17): [True: 0, False: 11.6k] ------------------ 94| 0| return a->isHighPriority; 95| 0| } 96| | 97| 11.6k| return b->name.length() && (parent != &root) && (lexicalOrder(b->name) < lexicalOrder(a->name)); ------------------ | Branch (97:20): [True: 11.6k, False: 0] | Branch (97:40): [True: 5.84k, False: 5.84k] | Branch (97:61): [True: 0, False: 5.84k] ------------------ 98| 11.6k| }), std::move(newNode))->get(); _ZN3uWS10HttpRouterINS_15HttpContextDataILb0EE10RouterDataEE12lexicalOrderERNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEE: 67| 11.6k| int lexicalOrder(std::string &name) { 68| 11.6k| if (!name.length()) { ------------------ | Branch (68:13): [True: 0, False: 11.6k] ------------------ 69| 0| return 2; 70| 0| } 71| 11.6k| if (name[0] == ':') { ------------------ | Branch (71:13): [True: 0, False: 11.6k] ------------------ 72| 0| return 1; 73| 0| } 74| 11.6k| if (name[0] == '*') { ------------------ | Branch (74:13): [True: 5.84k, False: 5.84k] ------------------ 75| 5.84k| return 0; 76| 5.84k| } 77| 5.84k| return 2; 78| 11.6k| } _ZN3uWS10HttpRouterINS_15HttpContextDataILb0EE10RouterDataEE11getUserDataEv: 252| 348k| USERDATA &getUserData() { 253| 348k| return userData; 254| 348k| } _ZN3uWS10HttpRouterINS_15HttpContextDataILb0EE10RouterDataEE5routeENSt3__117basic_string_viewIcNS5_11char_traitsIcEEEES9_: 257| 171k| bool route(std::string_view method, std::string_view url) { 258| | /* Reset url parsing cache */ 259| 171k| setUrl(url); 260| 171k| routeParameters.reset(); 261| | 262| | /* Begin by finding the method node */ 263| 176k| for (auto &p : root.children) { ------------------ | Branch (263:22): [True: 176k, False: 4.59k] ------------------ 264| 176k| if (p->name == method) { ------------------ | Branch (264:17): [True: 167k, False: 9.18k] ------------------ 265| | /* Then route the url */ 266| 167k| if (executeHandlers(p.get(), 0, userData)) { ------------------ | Branch (266:21): [True: 164k, False: 2.95k] ------------------ 267| 164k| return true; 268| 164k| } else { 269| 2.95k| break; 270| 2.95k| } 271| 167k| } 272| 176k| } 273| | 274| | /* Always test any route last */ 275| 7.55k| return executeHandlers(root.children.back().get(), 0, userData); 276| 171k| } _ZN3uWS10HttpRouterINS_15HttpContextDataILb0EE10RouterDataEE6setUrlENSt3__117basic_string_viewIcNS5_11char_traitsIcEEEE: 124| 201k| inline void setUrl(std::string_view url) { 125| | 126| | /* Todo: URL may also start with "http://domain/" or "*", not only "/" */ 127| | 128| | /* We expect to stand on a slash */ 129| 201k| currentUrl = url; 130| 201k| urlSegmentTop = -1; 131| 201k| } _ZN3uWS10HttpRouterINS_15HttpContextDataILb0EE10RouterDataEE15RouteParameters5resetEv: 108| 171k| void reset() { 109| 171k| paramsTop = -1; 110| 171k| } _ZN3uWS10HttpRouterINS_15HttpContextDataILb0EE10RouterDataEE15executeHandlersEPNS4_4NodeEiRS3_: 168| 307k| bool executeHandlers(Node *parent, int urlSegment, USERDATA &userData) { 169| | 170| 307k| auto [segment, isStop] = getUrlSegment(urlSegment); 171| | 172| | /* If we are on STOP, return where we may stand */ 173| 307k| if (isStop) { ------------------ | Branch (173:13): [True: 132k, False: 175k] ------------------ 174| | /* We have reached accross the entire URL with no stoppage, execute */ 175| 132k| for (uint32_t handler : parent->handlers) { ------------------ | Branch (175:35): [True: 132k, False: 1.83k] ------------------ 176| 132k| if (handlers[handler & HANDLER_MASK](this)) { ------------------ | Branch (176:21): [True: 130k, False: 1.83k] ------------------ 177| 130k| return true; 178| 130k| } 179| 132k| } 180| | /* We reached the end, so go back */ 181| 1.83k| return false; 182| 132k| } 183| | 184| 211k| for (auto &p : parent->children) { ------------------ | Branch (184:22): [True: 211k, False: 3.38k] ------------------ 185| 211k| if (p->name.length() && p->name[0] == '*') { ------------------ | Branch (185:17): [True: 211k, False: 0] | Branch (185:37): [True: 44.3k, False: 167k] ------------------ 186| | /* Wildcard match (can be seen as a shortcut) */ 187| 44.3k| for (uint32_t handler : p->handlers) { ------------------ | Branch (187:39): [True: 44.3k, False: 2.95k] ------------------ 188| 44.3k| if (handlers[handler & HANDLER_MASK](this)) { ------------------ | Branch (188:25): [True: 41.3k, False: 2.95k] ------------------ 189| 41.3k| return true; 190| 41.3k| } 191| 44.3k| } 192| 167k| } else if (p->name.length() && p->name[0] == ':' && segment.length()) { ------------------ | Branch (192:24): [True: 167k, False: 0] | Branch (192:44): [True: 0, False: 167k] | Branch (192:65): [True: 0, False: 0] ------------------ 193| | /* Parameter match */ 194| 0| routeParameters.push(segment); 195| 0| if (executeHandlers(p.get(), urlSegment + 1, userData)) { ------------------ | Branch (195:21): [True: 0, False: 0] ------------------ 196| 0| return true; 197| 0| } 198| 0| routeParameters.pop(); 199| 167k| } else if (p->name == segment) { ------------------ | Branch (199:24): [True: 132k, False: 34.5k] ------------------ 200| | /* Static match */ 201| 132k| if (executeHandlers(p.get(), urlSegment + 1, userData)) { ------------------ | Branch (201:21): [True: 130k, False: 2.25k] ------------------ 202| 130k| return true; 203| 130k| } 204| 132k| } 205| 211k| } 206| 3.38k| return false; 207| 175k| } _ZN3uWS10HttpRouterINS_15HttpContextDataILb0EE10RouterDataEE13getUrlSegmentEi: 134| 383k| inline std::pair getUrlSegment(int urlSegment) { 135| 383k| if (urlSegment > urlSegmentTop) { ------------------ | Branch (135:13): [True: 351k, False: 32.1k] ------------------ 136| | /* Signal as STOP when we have no more URL or stack space */ 137| 351k| if (!currentUrl.length() || urlSegment > int(MAX_URL_SEGMENTS - 1)) { ------------------ | Branch (137:17): [True: 149k, False: 201k] | Branch (137:41): [True: 0, False: 201k] ------------------ 138| 149k| return {{}, true}; 139| 149k| } 140| | 141| | /* We always stand on a slash here, so step over it */ 142| 201k| currentUrl.remove_prefix(1); 143| | 144| 201k| auto segmentLength = currentUrl.find('/'); 145| 201k| if (segmentLength == std::string::npos) { ------------------ | Branch (145:17): [True: 200k, False: 1.46k] ------------------ 146| 200k| segmentLength = currentUrl.length(); 147| | 148| | /* Push to url segment vector */ 149| 200k| urlSegmentVector[urlSegment] = currentUrl.substr(0, segmentLength); 150| 200k| urlSegmentTop++; 151| | 152| | /* Update currentUrl */ 153| 200k| currentUrl = currentUrl.substr(segmentLength); 154| 200k| } else { 155| | /* Push to url segment vector */ 156| 1.46k| urlSegmentVector[urlSegment] = currentUrl.substr(0, segmentLength); 157| 1.46k| urlSegmentTop++; 158| | 159| | /* Update currentUrl */ 160| 1.46k| currentUrl = currentUrl.substr(segmentLength); 161| 1.46k| } 162| 201k| } 163| | /* In any case we return it */ 164| 233k| return {urlSegmentVector[urlSegment], false}; 165| 383k| } _ZN3uWS10HttpRouterINS_15HttpContextDataILb0EE10RouterDataEE6removeENSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEESB_j: 360| 17.5k| void remove(std::string method, std::string pattern, uint32_t priority) { 361| 17.5k| uint32_t handler = findHandler(method, pattern, priority); 362| 17.5k| if (handler == UINT32_MAX) { ------------------ | Branch (362:13): [True: 17.5k, False: 0] ------------------ 363| | /* Not found or already removed, do nothing */ 364| 17.5k| return; 365| 17.5k| } 366| | 367| | /* Cull the entire tree */ 368| | /* For all nodes in depth first tree traveral; 369| | * if node contains handler - remove the handler - 370| | * if node holds no handlers after removal, remove the node and return */ 371| 0| cullNode(nullptr, &root, handler); 372| | 373| | /* Now remove the actual handler */ 374| 0| handlers.erase(handlers.begin() + (handler & HANDLER_MASK)); 375| 0| } _ZN3uWS10HttpRouterINS_15HttpContextDataILb0EE10RouterDataEE11findHandlerENSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEESB_j: 210| 17.5k| uint32_t findHandler(std::string method, std::string pattern, uint32_t priority) { 211| 17.5k| for (std::unique_ptr &node : root.children) { ------------------ | Branch (211:42): [True: 17.5k, False: 5.84k] ------------------ 212| 17.5k| if (method == node->name) { ------------------ | Branch (212:17): [True: 11.6k, False: 5.84k] ------------------ 213| 11.6k| setUrl(pattern); 214| 11.6k| Node *n = node.get(); 215| 11.6k| for (int i = 0; !getUrlSegment(i).second; i++) { ------------------ | Branch (215:33): [True: 11.6k, False: 0] ------------------ 216| | /* Go to next segment or quit */ 217| 11.6k| std::string segment = std::string(getUrlSegment(i).first); 218| 11.6k| Node *next = nullptr; 219| 11.6k| for (std::unique_ptr &child : n->children) { ------------------ | Branch (219:55): [True: 5.84k, False: 11.6k] ------------------ 220| 5.84k| if (child->name == segment && child->isHighPriority == (priority == HIGH_PRIORITY)) { ------------------ | Branch (220:29): [True: 0, False: 5.84k] | Branch (220:55): [True: 0, False: 0] ------------------ 221| 0| next = child.get(); 222| 0| break; 223| 0| } 224| 5.84k| } 225| 11.6k| if (!next) { ------------------ | Branch (225:25): [True: 11.6k, False: 0] ------------------ 226| 11.6k| return UINT32_MAX; 227| 11.6k| } 228| 0| n = next; 229| 0| } 230| | /* Seek for a priority match in the found node */ 231| 0| for (unsigned int i = 0; i < n->handlers.size(); i++) { ------------------ | Branch (231:42): [True: 0, False: 0] ------------------ 232| 0| if ((n->handlers[i] & ~HANDLER_MASK) == priority) { ------------------ | Branch (232:25): [True: 0, False: 0] ------------------ 233| 0| return n->handlers[i]; 234| 0| } 235| 0| } 236| 0| return UINT32_MAX; 237| 0| } 238| 17.5k| } 239| 5.84k| return UINT32_MAX; 240| 17.5k| } _ZN3uWS10HttpRouterINS_15HttpContextDataILb0EE10RouterDataEE3addENSt3__16vectorINS5_12basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEENSA_ISC_EEEESC_ON5ofats13any_invocableIFbPS4_EEEj: 279| 17.5k| void add(std::vector methods, std::string pattern, MoveOnlyFunction &&handler, uint32_t priority = MEDIUM_PRIORITY) { 280| | /* First remove existing handler */ 281| 17.5k| remove(methods[0], pattern, priority); 282| | 283| 17.5k| for (std::string method : methods) { ------------------ | Branch (283:33): [True: 17.5k, False: 17.5k] ------------------ 284| | /* Lookup method */ 285| 17.5k| Node *node = getNode(&root, method, false); 286| | /* Iterate over all segments */ 287| 17.5k| setUrl(pattern); 288| 35.0k| for (int i = 0; !getUrlSegment(i).second; i++) { ------------------ | Branch (288:29): [True: 17.5k, False: 17.5k] ------------------ 289| 17.5k| std::string strippedSegment(getUrlSegment(i).first); 290| 17.5k| if (strippedSegment.length() && strippedSegment[0] == ':') { ------------------ | Branch (290:21): [True: 17.5k, False: 0] | Branch (290:49): [True: 0, False: 17.5k] ------------------ 291| | /* Parameter routes must be named only : */ 292| 0| strippedSegment = ":"; 293| 0| } 294| 17.5k| node = getNode(node, strippedSegment, priority == HIGH_PRIORITY); 295| 17.5k| } 296| | /* Insert handler in order sorted by priority (most significant 1 byte) */ 297| 17.5k| node->handlers.insert(std::upper_bound(node->handlers.begin(), node->handlers.end(), (uint32_t) (priority | handlers.size())), (uint32_t) (priority | handlers.size())); 298| 17.5k| } 299| | 300| | /* Alloate this handler */ 301| 17.5k| handlers.emplace_back(std::move(handler)); 302| | 303| | /* ANY method must be last, GET must be first */ 304| 17.5k| std::sort(root.children.begin(), root.children.end(), [](const auto &a, const auto &b) { 305| | /* Assuming the list of methods is unique, non-repeating */ 306| 17.5k| if (a->name == "GET") { 307| 17.5k| return true; 308| 17.5k| } else if (b->name == "GET") { 309| 17.5k| return false; 310| 17.5k| } else if (a->name == ANY_METHOD_TOKEN) { 311| 17.5k| return false; 312| 17.5k| } else if (b->name == ANY_METHOD_TOKEN) { 313| 17.5k| return true; 314| 17.5k| } else { 315| 17.5k| return a->name < b->name; 316| 17.5k| } 317| 17.5k| }); 318| 17.5k| } _ZZN3uWS10HttpRouterINS_15HttpContextDataILb0EE10RouterDataEE3addENSt3__16vectorINS5_12basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEENSA_ISC_EEEESC_ON5ofats13any_invocableIFbPS4_EEEjENKUlRKT_RKT0_E_clINS5_10unique_ptrINS4_4NodeENS5_14default_deleteISU_EEEESX_EEDaSN_SQ_: 304| 11.6k| std::sort(root.children.begin(), root.children.end(), [](const auto &a, const auto &b) { 305| | /* Assuming the list of methods is unique, non-repeating */ 306| 11.6k| if (a->name == "GET") { ------------------ | Branch (306:17): [True: 5.84k, False: 5.84k] ------------------ 307| 5.84k| return true; 308| 5.84k| } else if (b->name == "GET") { ------------------ | Branch (308:24): [True: 5.84k, False: 0] ------------------ 309| 5.84k| return false; 310| 5.84k| } else if (a->name == ANY_METHOD_TOKEN) { ------------------ | Branch (310:24): [True: 0, False: 0] ------------------ 311| 0| return false; 312| 0| } else if (b->name == ANY_METHOD_TOKEN) { ------------------ | Branch (312:24): [True: 0, False: 0] ------------------ 313| 0| return true; 314| 0| } else { 315| 0| return a->name < b->name; 316| 0| } 317| 11.6k| }); _ZN3uWS10HttpRouterINS_15HttpContextDataILb0EE10RouterDataEE13getParametersEv: 248| 176k| std::pair getParameters() { 249| 176k| return {routeParameters.paramsTop, routeParameters.params}; 250| 176k| } _ZN3uWS4Loop3getEPv: 111| 60.0k| static Loop *get(void *existingNativeLoop = nullptr) { 112| 60.0k| if (!getLazyLoop().loop) { ------------------ | Branch (112:13): [True: 5.84k, False: 54.2k] ------------------ 113| | /* If we are given a native loop pointer we pass that to uSockets and let it deal with it */ 114| 5.84k| if (existingNativeLoop) { ------------------ | Branch (114:17): [True: 0, False: 5.84k] ------------------ 115| | /* Todo: here we want to pass the pointer, not a boolean */ 116| 0| getLazyLoop().loop = create(existingNativeLoop); 117| | /* We cannot register automatic free here, must be manually done */ 118| 5.84k| } else { 119| 5.84k| getLazyLoop().loop = create(nullptr); 120| 5.84k| getLazyLoop().cleanMe = true; 121| 5.84k| } 122| 5.84k| } 123| | 124| 60.0k| return getLazyLoop().loop; 125| 60.0k| } _ZN3uWS4Loop11getLazyLoopEv: 103| 137k| static LoopCleaner &getLazyLoop() { 104| 137k| static thread_local LoopCleaner lazyLoop; 105| 137k| return lazyLoop; 106| 137k| } _ZN3uWS4Loop11LoopCleanerD2Ev: 94| 1| ~LoopCleaner() { 95| 1| if(loop && cleanMe) { ------------------ | Branch (95:16): [True: 0, False: 1] | Branch (95:24): [True: 0, False: 0] ------------------ 96| 0| loop->free(); 97| 0| } 98| 1| } _ZN3uWS4Loop6createEPv: 76| 5.84k| static Loop *create(void *hint) { 77| 5.84k| Loop *loop = ((Loop *) us_create_loop(hint, wakeupCb, preCb, postCb, sizeof(LoopData)))->init(); 78| | 79| | /* We also need some timers (should live off the one 4 second timer rather) */ 80| 5.84k| LoopData *loopData = (LoopData *) us_loop_ext((struct us_loop_t *) loop); 81| 5.84k| loopData->dateTimer = us_create_timer((struct us_loop_t *) loop, 1, sizeof(LoopData *)); 82| 5.84k| memcpy(us_timer_ext(loopData->dateTimer), &loopData, sizeof(LoopData *)); 83| 5.84k| us_timer_set(loopData->dateTimer, [](struct us_timer_t *t) { 84| 5.84k| LoopData *loopData; 85| 5.84k| memcpy(&loopData, us_timer_ext(t), sizeof(LoopData *)); 86| 5.84k| loopData->updateDate(); 87| 5.84k| }, 1000, 1000); 88| | 89| 5.84k| return loop; 90| 5.84k| } _ZN3uWS4Loop8wakeupCbEP9us_loop_t: 30| 1.63M| static void wakeupCb(us_loop_t *loop) { 31| 1.63M| LoopData *loopData = (LoopData *) us_loop_ext(loop); 32| | 33| | /* Swap current deferQueue */ 34| 1.63M| loopData->deferMutex.lock(); 35| 1.63M| int oldDeferQueue = loopData->currentDeferQueue; 36| 1.63M| loopData->currentDeferQueue = (loopData->currentDeferQueue + 1) % 2; 37| 1.63M| loopData->deferMutex.unlock(); 38| | 39| | /* Drain the queue */ 40| 1.63M| for (auto &x : loopData->deferQueues[oldDeferQueue]) { ------------------ | Branch (40:22): [True: 3.78k, False: 1.63M] ------------------ 41| 3.78k| x(); 42| 3.78k| } 43| 1.63M| loopData->deferQueues[oldDeferQueue].clear(); 44| 1.63M| } _ZN3uWS4Loop5preCbEP9us_loop_t: 46| 2.18M| static void preCb(us_loop_t *loop) { 47| 2.18M| LoopData *loopData = (LoopData *) us_loop_ext(loop); 48| | 49| 2.18M| for (auto &p : loopData->preHandlers) { ------------------ | Branch (49:22): [True: 2.18M, False: 2.18M] ------------------ 50| 2.18M| p.second((Loop *) loop); 51| 2.18M| } 52| 2.18M| } _ZN3uWS4Loop6postCbEP9us_loop_t: 54| 2.18M| static void postCb(us_loop_t *loop) { 55| 2.18M| LoopData *loopData = (LoopData *) us_loop_ext(loop); 56| | 57| 2.18M| for (auto &p : loopData->postHandlers) { ------------------ | Branch (57:22): [True: 2.18M, False: 2.18M] ------------------ 58| 2.18M| p.second((Loop *) loop); 59| 2.18M| } 60| | 61| | /* After every event loop iteration, we must not hold the cork buffer */ 62| 2.18M| if (loopData->corkedSocket) { ------------------ | Branch (62:13): [True: 0, False: 2.18M] ------------------ 63| 0| std::cerr << "Error: Cork buffer must not be held across event loop iterations!" << std::endl; 64| 0| std::terminate(); 65| 0| } 66| 2.18M| } _ZN3uWS4Loop4initEv: 71| 5.84k| Loop *init() { 72| 5.84k| new (us_loop_ext((us_loop_t *) this)) LoopData; 73| 5.84k| return this; 74| 5.84k| } _ZZN3uWS4Loop6createEPvENKUlP10us_timer_tE_clES3_: 83| 1.62M| us_timer_set(loopData->dateTimer, [](struct us_timer_t *t) { 84| 1.62M| LoopData *loopData; 85| 1.62M| memcpy(&loopData, us_timer_ext(t), sizeof(LoopData *)); 86| 1.62M| loopData->updateDate(); 87| 1.62M| }, 1000, 1000); _ZN3uWS4Loop4freeEv: 128| 5.84k| void free() { 129| 5.84k| LoopData *loopData = (LoopData *) us_loop_ext((us_loop_t *) this); 130| | 131| | /* Stop and free dateTimer first */ 132| 5.84k| us_timer_close(loopData->dateTimer); 133| | 134| 5.84k| loopData->~LoopData(); 135| | /* uSockets will track whether this loop is owned by us or a borrowed alien loop */ 136| 5.84k| us_loop_free((us_loop_t *) this); 137| | 138| | /* Reset lazyLoop */ 139| 5.84k| getLazyLoop().loop = nullptr; 140| 5.84k| } _ZN3uWS4Loop17removePostHandlerEPv: 149| 5.84k| void removePostHandler(void *key) { 150| 5.84k| LoopData *loopData = (LoopData *) us_loop_ext((us_loop_t *) this); 151| | 152| 5.84k| loopData->postHandlers.erase(key); 153| 5.84k| } _ZN3uWS4Loop16removePreHandlerEPv: 162| 5.84k| void removePreHandler(void *key) { 163| 5.84k| LoopData *loopData = (LoopData *) us_loop_ext((us_loop_t *) this); 164| | 165| 5.84k| loopData->preHandlers.erase(key); 166| 5.84k| } _ZN3uWS4Loop14addPostHandlerEPvON5ofats13any_invocableIFvPS0_EEE: 142| 5.84k| void addPostHandler(void *key, MoveOnlyFunction &&handler) { 143| 5.84k| LoopData *loopData = (LoopData *) us_loop_ext((us_loop_t *) this); 144| | 145| 5.84k| loopData->postHandlers.emplace(key, std::move(handler)); 146| 5.84k| } _ZN3uWS4Loop13addPreHandlerEPvON5ofats13any_invocableIFvPS0_EEE: 155| 5.84k| void addPreHandler(void *key, MoveOnlyFunction &&handler) { 156| 5.84k| LoopData *loopData = (LoopData *) us_loop_ext((us_loop_t *) this); 157| | 158| 5.84k| loopData->preHandlers.emplace(key, std::move(handler)); 159| 5.84k| } _ZN3uWS4Loop5deferEON5ofats13any_invocableIFvvEEE: 169| 7.41k| void defer(MoveOnlyFunction &&cb) { 170| 7.41k| LoopData *loopData = (LoopData *) us_loop_ext((us_loop_t *) this); 171| | 172| | //if (std::thread::get_id() == ) // todo: add fast path for same thread id 173| 7.41k| loopData->deferMutex.lock(); 174| 7.41k| loopData->deferQueues[loopData->currentDeferQueue].emplace_back(std::move(cb)); 175| 7.41k| loopData->deferMutex.unlock(); 176| | 177| 7.41k| us_wakeup_loop((us_loop_t *) this); 178| 7.41k| } _ZN3uWS3runEv: 198| 5.84k|inline void run() { 199| 5.84k| Loop::get()->run(); 200| 5.84k|} _ZN3uWS4Loop3runEv: 181| 5.84k| void run() { 182| 5.84k| us_loop_run((us_loop_t *) this); 183| 5.84k| } _ZN3uWS8LoopDataC2Ev: 49| 5.84k| LoopData() { 50| 5.84k| updateDate(); 51| 5.84k| } _ZN3uWS8LoopData10updateDateEv: 63| 1.63M| void updateDate() { 64| 1.63M| time_t now = time(0); 65| 1.63M| struct tm tstruct = {}; 66| |#ifdef _WIN32 67| | /* Micro, fucking soft never follows spec. */ 68| | gmtime_s(&tstruct, &now); 69| |#else 70| 1.63M| gmtime_r(&now, &tstruct); 71| 1.63M|#endif 72| 1.63M| static const char wday_name[][4] = { 73| 1.63M| "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 74| 1.63M| }; 75| 1.63M| static const char mon_name[][4] = { 76| 1.63M| "Jan", "Feb", "Mar", "Apr", "May", "Jun", 77| 1.63M| "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 78| 1.63M| }; 79| 1.63M| snprintf(date, 32, "%.3s, %.2u %.3s %.4u %.2u:%.2u:%.2u GMT", 80| 1.63M| wday_name[tstruct.tm_wday], 81| 1.63M| tstruct.tm_mday % 99, 82| 1.63M| mon_name[tstruct.tm_mon], 83| 1.63M| (1900 + tstruct.tm_year) % 9999, 84| 1.63M| tstruct.tm_hour % 99, 85| 1.63M| tstruct.tm_min % 99, 86| 1.63M| tstruct.tm_sec % 99); 87| 1.63M| } _ZN3uWS8LoopDataD2Ev: 53| 5.84k| ~LoopData() { 54| | /* If we have had App.ws called with compression we need to clear this */ 55| 5.84k| if (zlibContext) { ------------------ | Branch (55:13): [True: 5.56k, False: 287] ------------------ 56| 5.56k| delete zlibContext; 57| 5.56k| delete inflationStream; 58| 5.56k| delete deflationStream; 59| 5.56k| } 60| 5.84k| delete [] corkBuffer; 61| 5.84k| } _ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEP19us_socket_context_tEEC2EDn: 187| 11.6k| any_invocable_impl(std::nullptr_t) noexcept {} EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEEC2EDn: 187| 35.0k| any_invocable_impl(std::nullptr_t) noexcept {} EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEiiEEC2EDn: 187| 23.3k| any_invocable_impl(std::nullptr_t) noexcept {} _ZN5ofats10any_detail18any_invocable_implIvLb0EJP18us_listen_socket_tEED2Ev: 206| 5.84k| ~any_invocable_impl() { destroy(); } _ZN5ofats10any_detail18any_invocable_implIvLb0EJP18us_listen_socket_tEE7destroyEv: 239| 5.84k| void destroy() noexcept { 240| 5.84k| if (handle_) { ------------------ | Branch (240:9): [True: 5.84k, False: 0] ------------------ 241| 5.84k| handle_(action::destroy, &storage_, nullptr); 242| 5.84k| handle_ = nullptr; 243| 5.84k| } 244| 5.84k| } EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEED2Ev: 206| 81.8k| ~any_invocable_impl() { destroy(); } EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE7destroyEv: 239| 81.8k| void destroy() noexcept { 240| 81.8k| if (handle_) { ------------------ | Branch (240:9): [True: 23.3k, False: 58.4k] ------------------ 241| 23.3k| handle_(action::destroy, &storage_, nullptr); 242| 23.3k| handle_ = nullptr; 243| 23.3k| } 244| 81.8k| } EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEiiEED2Ev: 206| 58.4k| ~any_invocable_impl() { destroy(); } EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEiiEE7destroyEv: 239| 58.4k| void destroy() noexcept { 240| 58.4k| if (handle_) { ------------------ | Branch (240:9): [True: 0, False: 58.4k] ------------------ 241| 0| handle_(action::destroy, &storage_, nullptr); 242| 0| handle_ = nullptr; 243| 0| } 244| 58.4k| } EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEED2Ev: 206| 116k| ~any_invocable_impl() { destroy(); } EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE7destroyEv: 239| 116k| void destroy() noexcept { 240| 116k| if (handle_) { ------------------ | Branch (240:9): [True: 23.3k, False: 93.5k] ------------------ 241| 23.3k| handle_(action::destroy, &storage_, nullptr); 242| 23.3k| handle_ = nullptr; 243| 23.3k| } 244| 116k| } EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEED2Ev: 206| 116k| ~any_invocable_impl() { destroy(); } EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEE7destroyEv: 239| 116k| void destroy() noexcept { 240| 116k| if (handle_) { ------------------ | Branch (240:9): [True: 23.3k, False: 93.5k] ------------------ 241| 23.3k| handle_(action::destroy, &storage_, nullptr); 242| 23.3k| handle_ = nullptr; 243| 23.3k| } 244| 116k| } EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEED2Ev: 206| 116k| ~any_invocable_impl() { destroy(); } EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEE7destroyEv: 239| 116k| void destroy() noexcept { 240| 116k| if (handle_) { ------------------ | Branch (240:9): [True: 11.6k, False: 105k] ------------------ 241| 11.6k| handle_(action::destroy, &storage_, nullptr); 242| 11.6k| handle_ = nullptr; 243| 11.6k| } 244| 116k| } _ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEP19us_socket_context_tEED2Ev: 206| 35.0k| ~any_invocable_impl() { destroy(); } _ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEP19us_socket_context_tEE7destroyEv: 239| 35.0k| void destroy() noexcept { 240| 35.0k| if (handle_) { ------------------ | Branch (240:9): [True: 0, False: 35.0k] ------------------ 241| 0| handle_(action::destroy, &storage_, nullptr); 242| 0| handle_ = nullptr; 243| 0| } 244| 35.0k| } _ZN5ofats13any_invocableIFvvEEclEv: 345| 15.4k| R operator()(ArgTypes... args) cv ref noexcept(noex) { \ 346| 15.4k| return base_type::call(std::forward(args)...); \ 347| 15.4k| } \ _ZN5ofats10any_detail18any_invocable_implIvLb0EJEE4callEv: 246| 15.4k| R call(ArgTypes... args) noexcept(is_noexcept) { 247| 15.4k| return call_(storage_, std::forward(args)...); 248| 15.4k| } _ZN5ofats10any_detail18any_invocable_implIvLb0EJEED2Ev: 206| 1.85M| ~any_invocable_impl() { destroy(); } _ZN5ofats10any_detail18any_invocable_implIvLb0EJEE7destroyEv: 239| 1.85M| void destroy() noexcept { 240| 1.85M| if (handle_) { ------------------ | Branch (240:9): [True: 19.1k, False: 1.83M] ------------------ 241| 19.1k| handle_(action::destroy, &storage_, nullptr); 242| 19.1k| handle_ = nullptr; 243| 19.1k| } 244| 1.85M| } _ZN5ofats13any_invocableIFvPN3uWS4LoopEEEclES3_: 345| 4.36M| R operator()(ArgTypes... args) cv ref noexcept(noex) { \ 346| 4.36M| return base_type::call(std::forward(args)...); \ 347| 4.36M| } \ _ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS4LoopEEE4callES4_: 246| 4.36M| R call(ArgTypes... args) noexcept(is_noexcept) { 247| 4.36M| return call_(storage_, std::forward(args)...); 248| 4.36M| } _ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS4LoopEEED2Ev: 206| 23.3k| ~any_invocable_impl() { destroy(); } _ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS4LoopEEE7destroyEv: 239| 23.3k| void destroy() noexcept { 240| 23.3k| if (handle_) { ------------------ | Branch (240:9): [True: 11.6k, False: 11.6k] ------------------ 241| 11.6k| handle_(action::destroy, &storage_, nullptr); 242| 11.6k| handle_ = nullptr; 243| 11.6k| } 244| 23.3k| } _ZN5ofats10any_detail18any_invocable_implIvLb0EJPKcEEC2Ev: 186| 5.84k| any_invocable_impl() noexcept = default; _ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterINS2_15HttpContextDataILb0EE10RouterDataEEEEED2Ev: 206| 52.6k| ~any_invocable_impl() { destroy(); } _ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterINS2_15HttpContextDataILb0EE10RouterDataEEEEE7destroyEv: 239| 52.6k| void destroy() noexcept { 240| 52.6k| if (handle_) { ------------------ | Branch (240:9): [True: 17.5k, False: 35.0k] ------------------ 241| 17.5k| handle_(action::destroy, &storage_, nullptr); 242| 17.5k| handle_ = nullptr; 243| 17.5k| } 244| 52.6k| } _ZN5ofats10any_detail18any_invocable_implIvLb0EJPKcEED2Ev: 206| 5.84k| ~any_invocable_impl() { destroy(); } _ZN5ofats10any_detail18any_invocable_implIvLb0EJPKcEE7destroyEv: 239| 5.84k| void destroy() noexcept { 240| 5.84k| if (handle_) { ------------------ | Branch (240:9): [True: 0, False: 5.84k] ------------------ 241| 0| handle_(action::destroy, &storage_, nullptr); 242| 0| handle_ = nullptr; 243| 0| } 244| 5.84k| } _ZN5ofats10any_detail18any_invocable_implIbLb0EJmEEC2Ev: 186| 1.63M| any_invocable_impl() noexcept = default; _ZN5ofats10any_detail18any_invocable_implIvLb0EJEEC2Ev: 186| 1.65M| any_invocable_impl() noexcept = default; _ZN5ofats10any_detail18any_invocable_implIvLb0EJNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEbEEC2Ev: 186| 1.63M| any_invocable_impl() noexcept = default; _ZNK5ofats10any_detail18any_invocable_implIvLb0EJEEcvbEv: 228| 1.46M| explicit operator bool() const noexcept { return handle_ != nullptr; } _ZN5ofats10any_detail18any_invocable_implIvLb0EJNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEbEED2Ev: 206| 1.63M| ~any_invocable_impl() { destroy(); } _ZN5ofats10any_detail18any_invocable_implIvLb0EJNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEbEE7destroyEv: 239| 1.63M| void destroy() noexcept { 240| 1.63M| if (handle_) { ------------------ | Branch (240:9): [True: 0, False: 1.63M] ------------------ 241| 0| handle_(action::destroy, &storage_, nullptr); 242| 0| handle_ = nullptr; 243| 0| } 244| 1.63M| } _ZN5ofats10any_detail18any_invocable_implIbLb0EJmEED2Ev: 206| 1.80M| ~any_invocable_impl() { destroy(); } _ZN5ofats10any_detail18any_invocable_implIbLb0EJmEE7destroyEv: 239| 1.80M| void destroy() noexcept { 240| 1.80M| if (handle_) { ------------------ | Branch (240:9): [True: 0, False: 1.80M] ------------------ 241| 0| handle_(action::destroy, &storage_, nullptr); 242| 0| handle_ = nullptr; 243| 0| } 244| 1.80M| } _ZN5ofats13any_invocableIFPvS1_NSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEbEEclES1_S6_b: 345| 7.55k| R operator()(ArgTypes... args) cv ref noexcept(noex) { \ 346| 7.55k| return base_type::call(std::forward(args)...); \ 347| 7.55k| } \ _ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE4callES2_S7_b: 246| 7.55k| R call(ArgTypes... args) noexcept(is_noexcept) { 247| 7.55k| return call_(storage_, std::forward(args)...); 248| 7.55k| } _ZN5ofats13any_invocableIFPvS1_PN3uWS11HttpRequestEEEclES1_S4_: 345| 171k| R operator()(ArgTypes... args) cv ref noexcept(noex) { \ 346| 171k| return base_type::call(std::forward(args)...); \ 347| 171k| } \ _ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_PN3uWS11HttpRequestEEE4callES2_S5_: 246| 171k| R call(ArgTypes... args) noexcept(is_noexcept) { 247| 171k| return call_(storage_, std::forward(args)...); 248| 171k| } _ZN5ofats13any_invocableIFPvS1_PN3uWS11HttpRequestEEEC2IZZNS2_11HttpContextILb0EE4initEvENKUlP11us_socket_tPciE_clESB_SC_iEUlS1_S4_E_vEEOT_: 303| 592k| any_invocable(F&& f) { \ 304| 592k| base_type::template create>(std::forward(f)); \ 305| 592k| } \ _ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_PN3uWS11HttpRequestEEEC2Ev: 186| 592k| any_invocable_impl() noexcept = default; _ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_PN3uWS11HttpRequestEEE6createIZZNS3_11HttpContextILb0EE4initEvENKUlP11us_socket_tPciE_clESB_SC_iEUlS2_S5_E_JSE_EEEvDpOT0_: 232| 592k| void create(Args&&... args) { 233| 592k| using hdl = handler; 234| 592k| hdl::create(storage_, std::forward(args)...); 235| 592k| handle_ = &hdl::handle; 236| 592k| call_ = &hdl::call; 237| 592k| } _ZN5ofats10any_detail14handler_traitsIPvJS2_PN3uWS11HttpRequestEEE13small_handlerIZZNS3_11HttpContextILb0EE4initEvENKUlP11us_socket_tPciE_clESB_SC_iEUlS2_S5_E_E6createIJSE_EEEvRNS0_7storageEDpOT_: 118| 592k| static void create(storage& s, Args&&... args) { 119| 592k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 592k| } _ZN5ofats10any_detail14handler_traitsIPvJS2_PN3uWS11HttpRequestEEE12handler_baseINS6_13small_handlerIZZNS3_11HttpContextILb0EE4initEvENKUlP11us_socket_tPciE_clESC_SD_iEUlS2_S5_E_EEE6handleENS0_6actionEPNS0_7storageESK_: 103| 592k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 592k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 592k] ------------------ 105| 592k| case (action::destroy): ------------------ | Branch (105:9): [True: 592k, False: 0] ------------------ 106| 592k| Derived::destroy(*current); 107| 592k| break; 108| 0| case (action::move): ------------------ | Branch (108:9): [True: 0, False: 592k] ------------------ 109| 0| Derived::move(*current, *other); 110| 0| break; 111| 592k| } 112| 592k| } _ZN5ofats10any_detail14handler_traitsIPvJS2_PN3uWS11HttpRequestEEE13small_handlerIZZNS3_11HttpContextILb0EE4initEvENKUlP11us_socket_tPciE_clESB_SC_iEUlS2_S5_E_E7destroyERNS0_7storageE: 122| 592k| static void destroy(storage& s) noexcept { 123| 592k| T& value = *static_cast(static_cast(&s.buf_)); 124| 592k| value.~T(); 125| 592k| } _ZN5ofats10any_detail14handler_traitsIPvJS2_PN3uWS11HttpRequestEEE13small_handlerIZZNS3_11HttpContextILb0EE4initEvENKUlP11us_socket_tPciE_clESB_SC_iEUlS2_S5_E_E4callERNS0_7storageES2_S5_: 132| 171k| static R call(storage& s, ArgTypes... args) { 133| 171k| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 171k| std::forward(args)...); 135| 171k| } _ZN5ofats13any_invocableIFbPN3uWS10HttpRouterINS1_15HttpContextDataILb0EE10RouterDataEEEEEclES7_: 345| 176k| R operator()(ArgTypes... args) cv ref noexcept(noex) { \ 346| 176k| return base_type::call(std::forward(args)...); \ 347| 176k| } \ _ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterINS2_15HttpContextDataILb0EE10RouterDataEEEEE4callES8_: 246| 176k| R call(ArgTypes... args) noexcept(is_noexcept) { 247| 176k| return call_(storage_, std::forward(args)...); 248| 176k| } _ZNK5ofats10any_detail18any_invocable_implIvLb0EJNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEbEEcvbEv: 228| 7.55k| explicit operator bool() const noexcept { return handle_ != nullptr; } _ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_PN3uWS11HttpRequestEEED2Ev: 206| 592k| ~any_invocable_impl() { destroy(); } _ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_PN3uWS11HttpRequestEEE7destroyEv: 239| 592k| void destroy() noexcept { 240| 592k| if (handle_) { ------------------ | Branch (240:9): [True: 592k, False: 0] ------------------ 241| 592k| handle_(action::destroy, &storage_, nullptr); 242| 592k| handle_ = nullptr; 243| 592k| } 244| 592k| } _ZN5ofats13any_invocableIFPvS1_NSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEbEEC2IZZN3uWS11HttpContextILb0EE4initEvENKUlP11us_socket_tPciE_clESE_SF_iEUlS1_S6_bE_vEEOT_: 303| 592k| any_invocable(F&& f) { \ 304| 592k| base_type::template create>(std::forward(f)); \ 305| 592k| } \ _ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEEC2Ev: 186| 592k| any_invocable_impl() noexcept = default; _ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE6createIZZN3uWS11HttpContextILb0EE4initEvENKUlP11us_socket_tPciE_clESE_SF_iEUlS2_S7_bE_JSH_EEEvDpOT0_: 232| 592k| void create(Args&&... args) { 233| 592k| using hdl = handler; 234| 592k| hdl::create(storage_, std::forward(args)...); 235| 592k| handle_ = &hdl::handle; 236| 592k| call_ = &hdl::call; 237| 592k| } _ZN5ofats10any_detail14handler_traitsIPvJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE13small_handlerIZZN3uWS11HttpContextILb0EE4initEvENKUlP11us_socket_tPciE_clESE_SF_iEUlS2_S7_bE_E6createIJSH_EEEvRNS0_7storageEDpOT_: 118| 592k| static void create(storage& s, Args&&... args) { 119| 592k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 592k| } _ZN5ofats10any_detail14handler_traitsIPvJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE12handler_baseINS8_13small_handlerIZZN3uWS11HttpContextILb0EE4initEvENKUlP11us_socket_tPciE_clESF_SG_iEUlS2_S7_bE_EEE6handleENS0_6actionEPNS0_7storageESN_: 103| 592k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 592k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 592k] ------------------ 105| 592k| case (action::destroy): ------------------ | Branch (105:9): [True: 592k, False: 0] ------------------ 106| 592k| Derived::destroy(*current); 107| 592k| break; 108| 0| case (action::move): ------------------ | Branch (108:9): [True: 0, False: 592k] ------------------ 109| 0| Derived::move(*current, *other); 110| 0| break; 111| 592k| } 112| 592k| } _ZN5ofats10any_detail14handler_traitsIPvJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE13small_handlerIZZN3uWS11HttpContextILb0EE4initEvENKUlP11us_socket_tPciE_clESE_SF_iEUlS2_S7_bE_E7destroyERNS0_7storageE: 122| 592k| static void destroy(storage& s) noexcept { 123| 592k| T& value = *static_cast(static_cast(&s.buf_)); 124| 592k| value.~T(); 125| 592k| } _ZN5ofats10any_detail14handler_traitsIPvJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE13small_handlerIZZN3uWS11HttpContextILb0EE4initEvENKUlP11us_socket_tPciE_clESE_SF_iEUlS2_S7_bE_E4callERNS0_7storageES2_S7_b: 132| 7.55k| static R call(storage& s, ArgTypes... args) { 133| 7.55k| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 7.55k| std::forward(args)...); 135| 7.55k| } _ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEED2Ev: 206| 592k| ~any_invocable_impl() { destroy(); } _ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE7destroyEv: 239| 592k| void destroy() noexcept { 240| 592k| if (handle_) { ------------------ | Branch (240:9): [True: 592k, False: 0] ------------------ 241| 592k| handle_(action::destroy, &storage_, nullptr); 242| 592k| handle_ = nullptr; 243| 592k| } 244| 592k| } _ZNK5ofats10any_detail18any_invocable_implIbLb0EJmEEcvbEv: 228| 1.33k| explicit operator bool() const noexcept { return handle_ != nullptr; } _ZN5ofats10any_detail18any_invocable_implIbLb0EJmEE4swapERS2_: 208| 171k| void swap(any_invocable_impl& rhs) noexcept { 209| 171k| if (handle_) { ------------------ | Branch (209:9): [True: 0, False: 171k] ------------------ 210| 0| if (rhs.handle_) { ------------------ | Branch (210:11): [True: 0, False: 0] ------------------ 211| 0| storage tmp; 212| 0| handle_(action::move, &tmp, &storage_); 213| 0| rhs.handle_(action::move, &storage_, &rhs.storage_); 214| 0| handle_(action::move, &rhs.storage_, &tmp); 215| 0| std::swap(handle_, rhs.handle_); 216| 0| std::swap(call_, rhs.call_); 217| 0| } else { 218| 0| rhs.swap(*this); 219| 0| } 220| 171k| } else if (rhs.handle_) { ------------------ | Branch (220:16): [True: 0, False: 171k] ------------------ 221| 0| rhs.handle_(action::move, &storage_, &rhs.storage_); 222| 0| handle_ = rhs.handle_; 223| 0| call_ = rhs.call_; 224| 0| rhs.handle_ = nullptr; 225| 0| } 226| 171k| } _ZNK5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEEEcvbEv: 228| 17.5k| explicit operator bool() const noexcept { return handle_ != nullptr; } _ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterINS2_15HttpContextDataILb0EE10RouterDataEEEEEC2EOS9_: 188| 35.0k| any_invocable_impl(any_invocable_impl&& rhs) noexcept { 189| 35.0k| if (rhs.handle_) { ------------------ | Branch (189:9): [True: 35.0k, False: 0] ------------------ 190| 35.0k| handle_ = rhs.handle_; 191| 35.0k| handle_(action::move, &storage_, &rhs.storage_); 192| 35.0k| call_ = rhs.call_; 193| 35.0k| rhs.handle_ = nullptr; 194| 35.0k| } 195| 35.0k| } _ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEEEC2EOS8_: 188| 35.0k| any_invocable_impl(any_invocable_impl&& rhs) noexcept { 189| 35.0k| if (rhs.handle_) { ------------------ | Branch (189:9): [True: 35.0k, False: 0] ------------------ 190| 35.0k| handle_ = rhs.handle_; 191| 35.0k| handle_(action::move, &storage_, &rhs.storage_); 192| 35.0k| call_ = rhs.call_; 193| 35.0k| rhs.handle_ = nullptr; 194| 35.0k| } 195| 35.0k| } _ZN5ofats13any_invocableIFbPN3uWS10HttpRouterINS1_15HttpContextDataILb0EE10RouterDataEEEEEC2IZNS1_11HttpContextILb0EE6onHttpENSt3__112basic_stringIcNSD_11char_traitsIcEENSD_9allocatorIcEEEESJ_ONS0_IFvPNS1_12HttpResponseILb0EEEPNS1_11HttpRequestEEEEbEUlPT_E_vEEOSS_: 303| 17.5k| any_invocable(F&& f) { \ 304| 17.5k| base_type::template create>(std::forward(f)); \ 305| 17.5k| } \ _ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterINS2_15HttpContextDataILb0EE10RouterDataEEEEEC2Ev: 186| 17.5k| any_invocable_impl() noexcept = default; _ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterINS2_15HttpContextDataILb0EE10RouterDataEEEEE6createIZNS2_11HttpContextILb0EE6onHttpENSt3__112basic_stringIcNSD_11char_traitsIcEENSD_9allocatorIcEEEESJ_ONS_13any_invocableIFvPNS2_12HttpResponseILb0EEEPNS2_11HttpRequestEEEEbEUlPT_E_JSV_EEEvDpOT0_: 232| 17.5k| void create(Args&&... args) { 233| 17.5k| using hdl = handler; 234| 17.5k| hdl::create(storage_, std::forward(args)...); 235| 17.5k| handle_ = &hdl::handle; 236| 17.5k| call_ = &hdl::call; 237| 17.5k| } _ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterINS2_15HttpContextDataILb0EE10RouterDataEEEEE13large_handlerIZNS2_11HttpContextILb0EE6onHttpENSt3__112basic_stringIcNSD_11char_traitsIcEENSD_9allocatorIcEEEESJ_ONS_13any_invocableIFvPNS2_12HttpResponseILb0EEEPNS2_11HttpRequestEEEEbEUlPT_E_E6createIJSV_EEEvRNS0_7storageEDpOT_: 141| 17.5k| static void create(storage& s, Args&&... args) { 142| 17.5k| s.ptr_ = new T(std::forward(args)...); 143| 17.5k| } _ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterINS2_15HttpContextDataILb0EE10RouterDataEEEEE12handler_baseINS9_13large_handlerIZNS2_11HttpContextILb0EE6onHttpENSt3__112basic_stringIcNSE_11char_traitsIcEENSE_9allocatorIcEEEESK_ONS_13any_invocableIFvPNS2_12HttpResponseILb0EEEPNS2_11HttpRequestEEEEbEUlPT_E_EEE6handleENS0_6actionEPNS0_7storageES11_: 103| 52.6k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 52.6k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 52.6k] ------------------ 105| 17.5k| case (action::destroy): ------------------ | Branch (105:9): [True: 17.5k, False: 35.0k] ------------------ 106| 17.5k| Derived::destroy(*current); 107| 17.5k| break; 108| 35.0k| case (action::move): ------------------ | Branch (108:9): [True: 35.0k, False: 17.5k] ------------------ 109| 35.0k| Derived::move(*current, *other); 110| 35.0k| break; 111| 52.6k| } 112| 52.6k| } _ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterINS2_15HttpContextDataILb0EE10RouterDataEEEEE13large_handlerIZNS2_11HttpContextILb0EE6onHttpENSt3__112basic_stringIcNSD_11char_traitsIcEENSD_9allocatorIcEEEESJ_ONS_13any_invocableIFvPNS2_12HttpResponseILb0EEEPNS2_11HttpRequestEEEEbEUlPT_E_E7destroyERNS0_7storageE: 145| 17.5k| static void destroy(storage& s) noexcept { delete static_cast(s.ptr_); } _ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterINS2_15HttpContextDataILb0EE10RouterDataEEEEE13large_handlerIZNS2_11HttpContextILb0EE6onHttpENSt3__112basic_stringIcNSD_11char_traitsIcEENSD_9allocatorIcEEEESJ_ONS_13any_invocableIFvPNS2_12HttpResponseILb0EEEPNS2_11HttpRequestEEEEbEUlPT_E_E4moveERNS0_7storageESY_: 147| 35.0k| static void move(storage& dst, storage& src) noexcept { 148| 35.0k| dst.ptr_ = src.ptr_; 149| 35.0k| } _ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterINS2_15HttpContextDataILb0EE10RouterDataEEEEE13large_handlerIZNS2_11HttpContextILb0EE6onHttpENSt3__112basic_stringIcNSD_11char_traitsIcEENSD_9allocatorIcEEEESJ_ONS_13any_invocableIFvPNS2_12HttpResponseILb0EEEPNS2_11HttpRequestEEEEbEUlPT_E_E4callERNS0_7storageES8_: 151| 176k| static R call(storage& s, ArgTypes... args) { 152| 176k| return std::invoke(*static_cast(s.ptr_), 153| 176k| std::forward(args)...); 154| 176k| } _ZN5ofats13any_invocableIFvPN3uWS12HttpResponseILb0EEEPNS1_11HttpRequestEEEclES4_S6_: 345| 176k| R operator()(ArgTypes... args) cv ref noexcept(noex) { \ 346| 176k| return base_type::call(std::forward(args)...); \ 347| 176k| } \ _ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEEE4callES5_S7_: 246| 176k| R call(ArgTypes... args) noexcept(is_noexcept) { 247| 176k| return call_(storage_, std::forward(args)...); 248| 176k| } _ZN5ofats13any_invocableIFvPN3uWS12HttpResponseILb0EEEPNS1_11HttpRequestEEEC2IZNS1_12TemplatedAppILb0EEC1ENS1_20SocketContextOptionsEEUlPT_PT0_E_vEEOSD_: 303| 5.84k| any_invocable(F&& f) { \ 304| 5.84k| base_type::template create>(std::forward(f)); \ 305| 5.84k| } \ _ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEEEC2Ev: 186| 17.5k| any_invocable_impl() noexcept = default; _ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEEE6createIZNS2_12TemplatedAppILb0EEC1ENS2_20SocketContextOptionsEEUlPT_PT0_E_JSH_EEEvDpOT0_: 232| 5.84k| void create(Args&&... args) { 233| 5.84k| using hdl = handler; 234| 5.84k| hdl::create(storage_, std::forward(args)...); 235| 5.84k| handle_ = &hdl::handle; 236| 5.84k| call_ = &hdl::call; 237| 5.84k| } _ZN5ofats10any_detail14handler_traitsIvJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEEE13small_handlerIZNS2_12TemplatedAppILb0EEC1ENS2_20SocketContextOptionsEEUlPT_PT0_E_E6createIJSH_EEEvRNS0_7storageEDpOT_: 118| 17.5k| static void create(storage& s, Args&&... args) { 119| 17.5k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 17.5k| } _ZN5ofats10any_detail14handler_traitsIvJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEEE12handler_baseINS8_13small_handlerIZNS2_12TemplatedAppILb0EEC1ENS2_20SocketContextOptionsEEUlPT_PT0_E_EEE6handleENS0_6actionEPNS0_7storageESN_: 103| 17.5k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 17.5k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 17.5k] ------------------ 105| 5.84k| case (action::destroy): ------------------ | Branch (105:9): [True: 5.84k, False: 11.6k] ------------------ 106| 5.84k| Derived::destroy(*current); 107| 5.84k| break; 108| 11.6k| case (action::move): ------------------ | Branch (108:9): [True: 11.6k, False: 5.84k] ------------------ 109| 11.6k| Derived::move(*current, *other); 110| 11.6k| break; 111| 17.5k| } 112| 17.5k| } _ZN5ofats10any_detail14handler_traitsIvJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEEE13small_handlerIZNS2_12TemplatedAppILb0EEC1ENS2_20SocketContextOptionsEEUlPT_PT0_E_E7destroyERNS0_7storageE: 122| 17.5k| static void destroy(storage& s) noexcept { 123| 17.5k| T& value = *static_cast(static_cast(&s.buf_)); 124| 17.5k| value.~T(); 125| 17.5k| } _ZN5ofats10any_detail14handler_traitsIvJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEEE13small_handlerIZNS2_12TemplatedAppILb0EEC1ENS2_20SocketContextOptionsEEUlPT_PT0_E_E4moveERNS0_7storageESK_: 127| 11.6k| static void move(storage& dst, storage& src) noexcept { 128| 11.6k| create(dst, std::move(*static_cast(static_cast(&src.buf_)))); 129| 11.6k| destroy(src); 130| 11.6k| } _ZN5ofats10any_detail14handler_traitsIvJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEEE13small_handlerIZNS2_12TemplatedAppILb0EEC1ENS2_20SocketContextOptionsEEUlPT_PT0_E_E4callERNS0_7storageES5_S7_: 132| 7.55k| static R call(storage& s, ArgTypes... args) { 133| 7.55k| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 7.55k| std::forward(args)...); 135| 7.55k| } _ZN5ofats13any_invocableIFvvEEaSIDnDnEENSt3__19enable_ifIXaantsr3stdE9is_same_vIT0_S2_Esr3stdE23is_move_constructible_vIS6_EERS2_E4typeEOT_: 335| 171k| operator=(F&& f) { \ 336| 171k| any_invocable{std::forward(f)}.swap(*this); \ 337| 171k| return *this; \ 338| 171k| } \ _ZN5ofats10any_detail18any_invocable_implIvLb0EJEEC2EDn: 187| 171k| any_invocable_impl(std::nullptr_t) noexcept {} _ZN5ofats10any_detail18any_invocable_implIvLb0EJEE4swapERS2_: 208| 171k| void swap(any_invocable_impl& rhs) noexcept { 209| 171k| if (handle_) { ------------------ | Branch (209:9): [True: 0, False: 171k] ------------------ 210| 0| if (rhs.handle_) { ------------------ | Branch (210:11): [True: 0, False: 0] ------------------ 211| 0| storage tmp; 212| 0| handle_(action::move, &tmp, &storage_); 213| 0| rhs.handle_(action::move, &storage_, &rhs.storage_); 214| 0| handle_(action::move, &rhs.storage_, &tmp); 215| 0| std::swap(handle_, rhs.handle_); 216| 0| std::swap(call_, rhs.call_); 217| 0| } else { 218| 0| rhs.swap(*this); 219| 0| } 220| 171k| } else if (rhs.handle_) { ------------------ | Branch (220:16): [True: 0, False: 171k] ------------------ 221| 0| rhs.handle_(action::move, &storage_, &rhs.storage_); 222| 0| handle_ = rhs.handle_; 223| 0| call_ = rhs.call_; 224| 0| rhs.handle_ = nullptr; 225| 0| } 226| 171k| } _ZN5ofats13any_invocableIFbmEEaSIDnDnEENSt3__19enable_ifIXaantsr3stdE9is_same_vIT0_S2_Esr3stdE23is_move_constructible_vIS6_EERS2_E4typeEOT_: 335| 171k| operator=(F&& f) { \ 336| 171k| any_invocable{std::forward(f)}.swap(*this); \ 337| 171k| return *this; \ 338| 171k| } \ _ZN5ofats10any_detail18any_invocable_implIbLb0EJmEEC2EDn: 187| 171k| any_invocable_impl(std::nullptr_t) noexcept {} _ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEEED2Ev: 206| 52.6k| ~any_invocable_impl() { destroy(); } _ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEEE7destroyEv: 239| 52.6k| void destroy() noexcept { 240| 52.6k| if (handle_) { ------------------ | Branch (240:9): [True: 17.5k, False: 35.0k] ------------------ 241| 17.5k| handle_(action::destroy, &storage_, nullptr); 242| 17.5k| handle_ = nullptr; 243| 17.5k| } 244| 52.6k| } _ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS4LoopEEEC2EOS5_: 188| 11.6k| any_invocable_impl(any_invocable_impl&& rhs) noexcept { 189| 11.6k| if (rhs.handle_) { ------------------ | Branch (189:9): [True: 11.6k, False: 0] ------------------ 190| 11.6k| handle_ = rhs.handle_; 191| 11.6k| handle_(action::move, &storage_, &rhs.storage_); 192| 11.6k| call_ = rhs.call_; 193| 11.6k| rhs.handle_ = nullptr; 194| 11.6k| } 195| 11.6k| } EpollEchoServer.cpp:_ZN5ofats13any_invocableIFvPN3uWS4LoopEEEC2IZNS1_12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOS8_NSt3__112basic_stringIcNSC_11char_traitsIcEENSC_9allocatorIcEEEEONS8_17WebSocketBehaviorIT_EEEUlS3_E_vEEOSK_: 303| 5.84k| any_invocable(F&& f) { \ 304| 5.84k| base_type::template create>(std::forward(f)); \ 305| 5.84k| } \ _ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS4LoopEEEC2Ev: 186| 11.6k| any_invocable_impl() noexcept = default; EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS4LoopEEE6createIZNS2_12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOS8_NSt3__112basic_stringIcNSC_11char_traitsIcEENSC_9allocatorIcEEEEONS8_17WebSocketBehaviorIT_EEEUlS4_E_JSN_EEEvDpOT0_: 232| 5.84k| void create(Args&&... args) { 233| 5.84k| using hdl = handler; 234| 5.84k| hdl::create(storage_, std::forward(args)...); 235| 5.84k| handle_ = &hdl::handle; 236| 5.84k| call_ = &hdl::call; 237| 5.84k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS4LoopEEE13small_handlerIZNS2_12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOS8_NSt3__112basic_stringIcNSC_11char_traitsIcEENSC_9allocatorIcEEEEONS8_17WebSocketBehaviorIT_EEEUlS4_E_E6createIJSN_EEEvRNS0_7storageEDpOT_: 118| 11.6k| static void create(storage& s, Args&&... args) { 119| 11.6k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 11.6k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS4LoopEEE12handler_baseINS5_13small_handlerIZNS2_12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOS9_NSt3__112basic_stringIcNSD_11char_traitsIcEENSD_9allocatorIcEEEEONS9_17WebSocketBehaviorIT_EEEUlS4_E_EEE6handleENS0_6actionEPNS0_7storageEST_: 103| 11.6k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 11.6k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 11.6k] ------------------ 105| 5.84k| case (action::destroy): ------------------ | Branch (105:9): [True: 5.84k, False: 5.84k] ------------------ 106| 5.84k| Derived::destroy(*current); 107| 5.84k| break; 108| 5.84k| case (action::move): ------------------ | Branch (108:9): [True: 5.84k, False: 5.84k] ------------------ 109| 5.84k| Derived::move(*current, *other); 110| 5.84k| break; 111| 11.6k| } 112| 11.6k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS4LoopEEE13small_handlerIZNS2_12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOS8_NSt3__112basic_stringIcNSC_11char_traitsIcEENSC_9allocatorIcEEEEONS8_17WebSocketBehaviorIT_EEEUlS4_E_E7destroyERNS0_7storageE: 122| 11.6k| static void destroy(storage& s) noexcept { 123| 11.6k| T& value = *static_cast(static_cast(&s.buf_)); 124| 11.6k| value.~T(); 125| 11.6k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS4LoopEEE13small_handlerIZNS2_12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOS8_NSt3__112basic_stringIcNSC_11char_traitsIcEENSC_9allocatorIcEEEEONS8_17WebSocketBehaviorIT_EEEUlS4_E_E4moveERNS0_7storageESQ_: 127| 5.84k| static void move(storage& dst, storage& src) noexcept { 128| 5.84k| create(dst, std::move(*static_cast(static_cast(&src.buf_)))); 129| 5.84k| destroy(src); 130| 5.84k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS4LoopEEE13small_handlerIZNS2_12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOS8_NSt3__112basic_stringIcNSC_11char_traitsIcEENSC_9allocatorIcEEEEONS8_17WebSocketBehaviorIT_EEEUlS4_E_E4callERNS0_7storageES4_: 132| 2.18M| static R call(storage& s, ArgTypes... args) { 133| 2.18M| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 2.18M| std::forward(args)...); 135| 2.18M| } EpollEchoServer.cpp:_ZN5ofats13any_invocableIFvPN3uWS4LoopEEEC2IZNS1_12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOS8_NSt3__112basic_stringIcNSC_11char_traitsIcEENSC_9allocatorIcEEEEONS8_17WebSocketBehaviorIT_EEEUlS3_E0_vEEOSK_: 303| 5.84k| any_invocable(F&& f) { \ 304| 5.84k| base_type::template create>(std::forward(f)); \ 305| 5.84k| } \ EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS4LoopEEE6createIZNS2_12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOS8_NSt3__112basic_stringIcNSC_11char_traitsIcEENSC_9allocatorIcEEEEONS8_17WebSocketBehaviorIT_EEEUlS4_E0_JSN_EEEvDpOT0_: 232| 5.84k| void create(Args&&... args) { 233| 5.84k| using hdl = handler; 234| 5.84k| hdl::create(storage_, std::forward(args)...); 235| 5.84k| handle_ = &hdl::handle; 236| 5.84k| call_ = &hdl::call; 237| 5.84k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS4LoopEEE13small_handlerIZNS2_12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOS8_NSt3__112basic_stringIcNSC_11char_traitsIcEENSC_9allocatorIcEEEEONS8_17WebSocketBehaviorIT_EEEUlS4_E0_E6createIJSN_EEEvRNS0_7storageEDpOT_: 118| 11.6k| static void create(storage& s, Args&&... args) { 119| 11.6k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 11.6k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS4LoopEEE12handler_baseINS5_13small_handlerIZNS2_12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOS9_NSt3__112basic_stringIcNSD_11char_traitsIcEENSD_9allocatorIcEEEEONS9_17WebSocketBehaviorIT_EEEUlS4_E0_EEE6handleENS0_6actionEPNS0_7storageEST_: 103| 11.6k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 11.6k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 11.6k] ------------------ 105| 5.84k| case (action::destroy): ------------------ | Branch (105:9): [True: 5.84k, False: 5.84k] ------------------ 106| 5.84k| Derived::destroy(*current); 107| 5.84k| break; 108| 5.84k| case (action::move): ------------------ | Branch (108:9): [True: 5.84k, False: 5.84k] ------------------ 109| 5.84k| Derived::move(*current, *other); 110| 5.84k| break; 111| 11.6k| } 112| 11.6k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS4LoopEEE13small_handlerIZNS2_12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOS8_NSt3__112basic_stringIcNSC_11char_traitsIcEENSC_9allocatorIcEEEEONS8_17WebSocketBehaviorIT_EEEUlS4_E0_E7destroyERNS0_7storageE: 122| 11.6k| static void destroy(storage& s) noexcept { 123| 11.6k| T& value = *static_cast(static_cast(&s.buf_)); 124| 11.6k| value.~T(); 125| 11.6k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS4LoopEEE13small_handlerIZNS2_12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOS8_NSt3__112basic_stringIcNSC_11char_traitsIcEENSC_9allocatorIcEEEEONS8_17WebSocketBehaviorIT_EEEUlS4_E0_E4moveERNS0_7storageESQ_: 127| 5.84k| static void move(storage& dst, storage& src) noexcept { 128| 5.84k| create(dst, std::move(*static_cast(static_cast(&src.buf_)))); 129| 5.84k| destroy(src); 130| 5.84k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS4LoopEEE13small_handlerIZNS2_12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOS8_NSt3__112basic_stringIcNSC_11char_traitsIcEENSC_9allocatorIcEEEEONS8_17WebSocketBehaviorIT_EEEUlS4_E0_E4callERNS0_7storageES4_: 132| 2.18M| static R call(storage& s, ArgTypes... args) { 133| 2.18M| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 2.18M| std::forward(args)...); 135| 2.18M| } EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEEC2EDn: 187| 23.3k| any_invocable_impl(std::nullptr_t) noexcept {} EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEEC2EDn: 187| 11.6k| any_invocable_impl(std::nullptr_t) noexcept {} EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEEC2EDn: 187| 23.3k| any_invocable_impl(std::nullptr_t) noexcept {} EpollEchoServer.cpp:_ZNK5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEiiEEcvbEv: 228| 260k| explicit operator bool() const noexcept { return handle_ != nullptr; } EpollEchoServer.cpp:_ZNK5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEEcvbEv: 228| 328k| explicit operator bool() const noexcept { return handle_ != nullptr; } EpollEchoServer.cpp:_ZN5ofats13any_invocableIFvPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS6_11char_traitsIcEEEEEEclES5_iSA_: 345| 328k| R operator()(ArgTypes... args) cv ref noexcept(noex) { \ 346| 328k| return base_type::call(std::forward(args)...); \ 347| 328k| } \ EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE4callES6_iSB_: 246| 328k| R call(ArgTypes... args) noexcept(is_noexcept) { 247| 328k| return call_(storage_, std::forward(args)...); 248| 328k| } EpollEchoServer.cpp:_ZNK5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEEcvbEv: 228| 38.6k| explicit operator bool() const noexcept { return handle_ != nullptr; } EpollEchoServer.cpp:_ZN5ofats13any_invocableIFvPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS6_11char_traitsIcEEEENS1_6OpCodeEEEclES5_SA_SB_: 345| 38.6k| R operator()(ArgTypes... args) cv ref noexcept(noex) { \ 346| 38.6k| return base_type::call(std::forward(args)...); \ 347| 38.6k| } \ EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEE4callES6_SB_SC_: 246| 38.6k| R call(ArgTypes... args) noexcept(is_noexcept) { 247| 38.6k| return call_(storage_, std::forward(args)...); 248| 38.6k| } EpollEchoServer.cpp:_ZNK5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEEcvbEv: 228| 14.9k| explicit operator bool() const noexcept { return handle_ != nullptr; } EpollEchoServer.cpp:_ZN5ofats13any_invocableIFvPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS6_11char_traitsIcEEEEEEclES5_SA_: 345| 14.9k| R operator()(ArgTypes... args) cv ref noexcept(noex) { \ 346| 14.9k| return base_type::call(std::forward(args)...); \ 347| 14.9k| } \ EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE4callES6_SB_: 246| 14.9k| R call(ArgTypes... args) noexcept(is_noexcept) { 247| 14.9k| return call_(storage_, std::forward(args)...); 248| 14.9k| } EpollEchoServer.cpp:_ZNK5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEEcvbEv: 228| 189k| explicit operator bool() const noexcept { return handle_ != nullptr; } EpollEchoServer.cpp:_ZN5ofats13any_invocableIFvPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEEclES5_: 345| 189k| R operator()(ArgTypes... args) cv ref noexcept(noex) { \ 346| 189k| return base_type::call(std::forward(args)...); \ 347| 189k| } \ EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEE4callES6_: 246| 189k| R call(ArgTypes... args) noexcept(is_noexcept) { 247| 189k| return call_(storage_, std::forward(args)...); 248| 189k| } _ZN5ofats10any_detail18any_invocable_implIvLb0EJEEC2EOS2_: 188| 32.7k| any_invocable_impl(any_invocable_impl&& rhs) noexcept { 189| 32.7k| if (rhs.handle_) { ------------------ | Branch (189:9): [True: 32.7k, False: 0] ------------------ 190| 32.7k| handle_ = rhs.handle_; 191| 32.7k| handle_(action::move, &storage_, &rhs.storage_); 192| 32.7k| call_ = rhs.call_; 193| 32.7k| rhs.handle_ = nullptr; 194| 32.7k| } 195| 32.7k| } EpollEchoServer.cpp:_ZN5ofats13any_invocableIFvvEEC2IZN3uWS12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOS6_NSt3__112basic_stringIcNSA_11char_traitsIcEENSA_9allocatorIcEEEEONS6_17WebSocketBehaviorIT_EEEUlvE_vEEOSI_: 303| 11.6k| any_invocable(F&& f) { \ 304| 11.6k| base_type::template create>(std::forward(f)); \ 305| 11.6k| } \ EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJEE6createIZN3uWS12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOS6_NSt3__112basic_stringIcNSA_11char_traitsIcEENSA_9allocatorIcEEEEONS6_17WebSocketBehaviorIT_EEEUlvE_JSL_EEEvDpOT0_: 232| 11.6k| void create(Args&&... args) { 233| 11.6k| using hdl = handler; 234| 11.6k| hdl::create(storage_, std::forward(args)...); 235| 11.6k| handle_ = &hdl::handle; 236| 11.6k| call_ = &hdl::call; 237| 11.6k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJEE13small_handlerIZN3uWS12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOS6_NSt3__112basic_stringIcNSA_11char_traitsIcEENSA_9allocatorIcEEEEONS6_17WebSocketBehaviorIT_EEEUlvE_E6createIJSL_EEEvRNS0_7storageEDpOT_: 118| 29.2k| static void create(storage& s, Args&&... args) { 119| 29.2k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 29.2k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJEE12handler_baseINS2_13small_handlerIZN3uWS12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOS7_NSt3__112basic_stringIcNSB_11char_traitsIcEENSB_9allocatorIcEEEEONS7_17WebSocketBehaviorIT_EEEUlvE_EEE6handleENS0_6actionEPNS0_7storageESR_: 103| 29.2k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 29.2k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 29.2k] ------------------ 105| 11.6k| case (action::destroy): ------------------ | Branch (105:9): [True: 11.6k, False: 17.5k] ------------------ 106| 11.6k| Derived::destroy(*current); 107| 11.6k| break; 108| 17.5k| case (action::move): ------------------ | Branch (108:9): [True: 17.5k, False: 11.6k] ------------------ 109| 17.5k| Derived::move(*current, *other); 110| 17.5k| break; 111| 29.2k| } 112| 29.2k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJEE13small_handlerIZN3uWS12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOS6_NSt3__112basic_stringIcNSA_11char_traitsIcEENSA_9allocatorIcEEEEONS6_17WebSocketBehaviorIT_EEEUlvE_E7destroyERNS0_7storageE: 122| 29.2k| static void destroy(storage& s) noexcept { 123| 29.2k| T& value = *static_cast(static_cast(&s.buf_)); 124| 29.2k| value.~T(); 125| 29.2k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJEE13small_handlerIZN3uWS12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOS6_NSt3__112basic_stringIcNSA_11char_traitsIcEENSA_9allocatorIcEEEEONS6_17WebSocketBehaviorIT_EEEUlvE_E4moveERNS0_7storageESO_: 127| 17.5k| static void move(storage& dst, storage& src) noexcept { 128| 17.5k| create(dst, std::move(*static_cast(static_cast(&src.buf_)))); 129| 17.5k| destroy(src); 130| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJEE13small_handlerIZN3uWS12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOS6_NSt3__112basic_stringIcNSA_11char_traitsIcEENSA_9allocatorIcEEEEONS6_17WebSocketBehaviorIT_EEEUlvE_E4callERNS0_7storageE: 132| 11.6k| static R call(storage& s, ArgTypes... args) { 133| 11.6k| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 11.6k| std::forward(args)...); 135| 11.6k| } EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEEaSEOS7_: 197| 23.3k| any_invocable_impl& operator=(any_invocable_impl&& rhs) noexcept { 198| 23.3k| any_invocable_impl{std::move(rhs)}.swap(*this); 199| 23.3k| return *this; 200| 23.3k| } EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEEC2EOS7_: 188| 70.1k| any_invocable_impl(any_invocable_impl&& rhs) noexcept { 189| 70.1k| if (rhs.handle_) { ------------------ | Branch (189:9): [True: 23.3k, False: 46.7k] ------------------ 190| 23.3k| handle_ = rhs.handle_; 191| 23.3k| handle_(action::move, &storage_, &rhs.storage_); 192| 23.3k| call_ = rhs.call_; 193| 23.3k| rhs.handle_ = nullptr; 194| 23.3k| } 195| 70.1k| } EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEE4swapERS7_: 208| 46.7k| void swap(any_invocable_impl& rhs) noexcept { 209| 46.7k| if (handle_) { ------------------ | Branch (209:9): [True: 23.3k, False: 23.3k] ------------------ 210| 23.3k| if (rhs.handle_) { ------------------ | Branch (210:11): [True: 0, False: 23.3k] ------------------ 211| 0| storage tmp; 212| 0| handle_(action::move, &tmp, &storage_); 213| 0| rhs.handle_(action::move, &storage_, &rhs.storage_); 214| 0| handle_(action::move, &rhs.storage_, &tmp); 215| 0| std::swap(handle_, rhs.handle_); 216| 0| std::swap(call_, rhs.call_); 217| 23.3k| } else { 218| 23.3k| rhs.swap(*this); 219| 23.3k| } 220| 23.3k| } else if (rhs.handle_) { ------------------ | Branch (220:16): [True: 23.3k, False: 0] ------------------ 221| 23.3k| rhs.handle_(action::move, &storage_, &rhs.storage_); 222| 23.3k| handle_ = rhs.handle_; 223| 23.3k| call_ = rhs.call_; 224| 23.3k| rhs.handle_ = nullptr; 225| 23.3k| } 226| 46.7k| } EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEEaSEOSD_: 197| 23.3k| any_invocable_impl& operator=(any_invocable_impl&& rhs) noexcept { 198| 23.3k| any_invocable_impl{std::move(rhs)}.swap(*this); 199| 23.3k| return *this; 200| 23.3k| } EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEEC2EOSD_: 188| 70.1k| any_invocable_impl(any_invocable_impl&& rhs) noexcept { 189| 70.1k| if (rhs.handle_) { ------------------ | Branch (189:9): [True: 11.6k, False: 58.4k] ------------------ 190| 11.6k| handle_ = rhs.handle_; 191| 11.6k| handle_(action::move, &storage_, &rhs.storage_); 192| 11.6k| call_ = rhs.call_; 193| 11.6k| rhs.handle_ = nullptr; 194| 11.6k| } 195| 70.1k| } EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEE4swapERSD_: 208| 35.0k| void swap(any_invocable_impl& rhs) noexcept { 209| 35.0k| if (handle_) { ------------------ | Branch (209:9): [True: 11.6k, False: 23.3k] ------------------ 210| 11.6k| if (rhs.handle_) { ------------------ | Branch (210:11): [True: 0, False: 11.6k] ------------------ 211| 0| storage tmp; 212| 0| handle_(action::move, &tmp, &storage_); 213| 0| rhs.handle_(action::move, &storage_, &rhs.storage_); 214| 0| handle_(action::move, &rhs.storage_, &tmp); 215| 0| std::swap(handle_, rhs.handle_); 216| 0| std::swap(call_, rhs.call_); 217| 11.6k| } else { 218| 11.6k| rhs.swap(*this); 219| 11.6k| } 220| 23.3k| } else if (rhs.handle_) { ------------------ | Branch (220:16): [True: 11.6k, False: 11.6k] ------------------ 221| 11.6k| rhs.handle_(action::move, &storage_, &rhs.storage_); 222| 11.6k| handle_ = rhs.handle_; 223| 11.6k| call_ = rhs.call_; 224| 11.6k| rhs.handle_ = nullptr; 225| 11.6k| } 226| 35.0k| } EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEiiEEaSEOSC_: 197| 11.6k| any_invocable_impl& operator=(any_invocable_impl&& rhs) noexcept { 198| 11.6k| any_invocable_impl{std::move(rhs)}.swap(*this); 199| 11.6k| return *this; 200| 11.6k| } EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEiiEEC2EOSC_: 188| 35.0k| any_invocable_impl(any_invocable_impl&& rhs) noexcept { 189| 35.0k| if (rhs.handle_) { ------------------ | Branch (189:9): [True: 0, False: 35.0k] ------------------ 190| 0| handle_ = rhs.handle_; 191| 0| handle_(action::move, &storage_, &rhs.storage_); 192| 0| call_ = rhs.call_; 193| 0| rhs.handle_ = nullptr; 194| 0| } 195| 35.0k| } EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEiiEE4swapERSC_: 208| 11.6k| void swap(any_invocable_impl& rhs) noexcept { 209| 11.6k| if (handle_) { ------------------ | Branch (209:9): [True: 0, False: 11.6k] ------------------ 210| 0| if (rhs.handle_) { ------------------ | Branch (210:11): [True: 0, False: 0] ------------------ 211| 0| storage tmp; 212| 0| handle_(action::move, &tmp, &storage_); 213| 0| rhs.handle_(action::move, &storage_, &rhs.storage_); 214| 0| handle_(action::move, &rhs.storage_, &tmp); 215| 0| std::swap(handle_, rhs.handle_); 216| 0| std::swap(call_, rhs.call_); 217| 0| } else { 218| 0| rhs.swap(*this); 219| 0| } 220| 11.6k| } else if (rhs.handle_) { ------------------ | Branch (220:16): [True: 0, False: 11.6k] ------------------ 221| 0| rhs.handle_(action::move, &storage_, &rhs.storage_); 222| 0| handle_ = rhs.handle_; 223| 0| call_ = rhs.call_; 224| 0| rhs.handle_ = nullptr; 225| 0| } 226| 11.6k| } EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEEC2EOSC_: 188| 46.7k| any_invocable_impl(any_invocable_impl&& rhs) noexcept { 189| 46.7k| if (rhs.handle_) { ------------------ | Branch (189:9): [True: 23.3k, False: 23.3k] ------------------ 190| 23.3k| handle_ = rhs.handle_; 191| 23.3k| handle_(action::move, &storage_, &rhs.storage_); 192| 23.3k| call_ = rhs.call_; 193| 23.3k| rhs.handle_ = nullptr; 194| 23.3k| } 195| 46.7k| } EpollEchoServer.cpp:_ZN5ofats13any_invocableIFvPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS6_11char_traitsIcEEEEEEaSIZNS1_12TemplatedAppILb0EE2wsIS3_EEOSF_NS6_12basic_stringIcS9_NS6_9allocatorIcEEEEONSF_17WebSocketBehaviorIT_EEEUlS5_iSA_E_SQ_EENS6_9enable_ifIXaantsr3stdE9is_same_vIT0_SC_Esr3stdE23is_move_constructible_vISS_EERSC_E4typeEOSN_: 335| 11.6k| operator=(F&& f) { \ 336| 11.6k| any_invocable{std::forward(f)}.swap(*this); \ 337| 11.6k| return *this; \ 338| 11.6k| } \ EpollEchoServer.cpp:_ZN5ofats13any_invocableIFvPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS6_11char_traitsIcEEEEEEC2IZNS1_12TemplatedAppILb0EE2wsIS3_EEOSF_NS6_12basic_stringIcS9_NS6_9allocatorIcEEEEONSF_17WebSocketBehaviorIT_EEEUlS5_iSA_E_vEEOSN_: 303| 11.6k| any_invocable(F&& f) { \ 304| 11.6k| base_type::template create>(std::forward(f)); \ 305| 11.6k| } \ EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEEC2Ev: 186| 23.3k| any_invocable_impl() noexcept = default; EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE6createIZNS2_12TemplatedAppILb0EE2wsIS4_EEOSF_NS7_12basic_stringIcSA_NS7_9allocatorIcEEEEONSF_17WebSocketBehaviorIT_EEEUlS6_iSB_E_JSQ_EEEvDpOT0_: 232| 11.6k| void create(Args&&... args) { 233| 11.6k| using hdl = handler; 234| 11.6k| hdl::create(storage_, std::forward(args)...); 235| 11.6k| handle_ = &hdl::handle; 236| 11.6k| call_ = &hdl::call; 237| 11.6k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13large_handlerIZNS2_12TemplatedAppILb0EE2wsIS4_EEOSF_NS7_12basic_stringIcSA_NS7_9allocatorIcEEEEONSF_17WebSocketBehaviorIT_EEEUlS6_iSB_E_E6createIJSQ_EEEvRNS0_7storageEDpOT_: 141| 11.6k| static void create(storage& s, Args&&... args) { 142| 11.6k| s.ptr_ = new T(std::forward(args)...); 143| 11.6k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE12handler_baseINSC_13large_handlerIZNS2_12TemplatedAppILb0EE2wsIS4_EEOSG_NS7_12basic_stringIcSA_NS7_9allocatorIcEEEEONSG_17WebSocketBehaviorIT_EEEUlS6_iSB_E_EEE6handleENS0_6actionEPNS0_7storageESW_: 103| 23.3k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 23.3k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 23.3k] ------------------ 105| 11.6k| case (action::destroy): ------------------ | Branch (105:9): [True: 11.6k, False: 11.6k] ------------------ 106| 11.6k| Derived::destroy(*current); 107| 11.6k| break; 108| 11.6k| case (action::move): ------------------ | Branch (108:9): [True: 11.6k, False: 11.6k] ------------------ 109| 11.6k| Derived::move(*current, *other); 110| 11.6k| break; 111| 23.3k| } 112| 23.3k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13large_handlerIZNS2_12TemplatedAppILb0EE2wsIS4_EEOSF_NS7_12basic_stringIcSA_NS7_9allocatorIcEEEEONSF_17WebSocketBehaviorIT_EEEUlS6_iSB_E_E7destroyERNS0_7storageE: 145| 11.6k| static void destroy(storage& s) noexcept { delete static_cast(s.ptr_); } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13large_handlerIZNS2_12TemplatedAppILb0EE2wsIS4_EEOSF_NS7_12basic_stringIcSA_NS7_9allocatorIcEEEEONSF_17WebSocketBehaviorIT_EEEUlS6_iSB_E_E4moveERNS0_7storageEST_: 147| 11.6k| static void move(storage& dst, storage& src) noexcept { 148| 11.6k| dst.ptr_ = src.ptr_; 149| 11.6k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13large_handlerIZNS2_12TemplatedAppILb0EE2wsIS4_EEOSF_NS7_12basic_stringIcSA_NS7_9allocatorIcEEEEONSF_17WebSocketBehaviorIT_EEEUlS6_iSB_E_E4callERNS0_7storageES6_iSB_: 151| 164k| static R call(storage& s, ArgTypes... args) { 152| 164k| return std::invoke(*static_cast(s.ptr_), 153| 164k| std::forward(args)...); 154| 164k| } EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE4swapERSC_: 208| 23.3k| void swap(any_invocable_impl& rhs) noexcept { 209| 23.3k| if (handle_) { ------------------ | Branch (209:9): [True: 11.6k, False: 11.6k] ------------------ 210| 11.6k| if (rhs.handle_) { ------------------ | Branch (210:11): [True: 0, False: 11.6k] ------------------ 211| 0| storage tmp; 212| 0| handle_(action::move, &tmp, &storage_); 213| 0| rhs.handle_(action::move, &storage_, &rhs.storage_); 214| 0| handle_(action::move, &rhs.storage_, &tmp); 215| 0| std::swap(handle_, rhs.handle_); 216| 0| std::swap(call_, rhs.call_); 217| 11.6k| } else { 218| 11.6k| rhs.swap(*this); 219| 11.6k| } 220| 11.6k| } else if (rhs.handle_) { ------------------ | Branch (220:16): [True: 11.6k, False: 0] ------------------ 221| 11.6k| rhs.handle_(action::move, &storage_, &rhs.storage_); 222| 11.6k| handle_ = rhs.handle_; 223| 11.6k| call_ = rhs.call_; 224| 11.6k| rhs.handle_ = nullptr; 225| 11.6k| } 226| 23.3k| } EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEEaSEOSC_: 197| 23.3k| any_invocable_impl& operator=(any_invocable_impl&& rhs) noexcept { 198| 23.3k| any_invocable_impl{std::move(rhs)}.swap(*this); 199| 23.3k| return *this; 200| 23.3k| } EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEEC2EOSC_: 188| 70.1k| any_invocable_impl(any_invocable_impl&& rhs) noexcept { 189| 70.1k| if (rhs.handle_) { ------------------ | Branch (189:9): [True: 23.3k, False: 46.7k] ------------------ 190| 23.3k| handle_ = rhs.handle_; 191| 23.3k| handle_(action::move, &storage_, &rhs.storage_); 192| 23.3k| call_ = rhs.call_; 193| 23.3k| rhs.handle_ = nullptr; 194| 23.3k| } 195| 70.1k| } EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE4swapERSC_: 208| 46.7k| void swap(any_invocable_impl& rhs) noexcept { 209| 46.7k| if (handle_) { ------------------ | Branch (209:9): [True: 23.3k, False: 23.3k] ------------------ 210| 23.3k| if (rhs.handle_) { ------------------ | Branch (210:11): [True: 0, False: 23.3k] ------------------ 211| 0| storage tmp; 212| 0| handle_(action::move, &tmp, &storage_); 213| 0| rhs.handle_(action::move, &storage_, &rhs.storage_); 214| 0| handle_(action::move, &rhs.storage_, &tmp); 215| 0| std::swap(handle_, rhs.handle_); 216| 0| std::swap(call_, rhs.call_); 217| 23.3k| } else { 218| 23.3k| rhs.swap(*this); 219| 23.3k| } 220| 23.3k| } else if (rhs.handle_) { ------------------ | Branch (220:16): [True: 23.3k, False: 0] ------------------ 221| 23.3k| rhs.handle_(action::move, &storage_, &rhs.storage_); 222| 23.3k| handle_ = rhs.handle_; 223| 23.3k| call_ = rhs.call_; 224| 23.3k| rhs.handle_ = nullptr; 225| 23.3k| } 226| 46.7k| } _ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEP19us_socket_context_tEEC2EOSA_: 188| 23.3k| any_invocable_impl(any_invocable_impl&& rhs) noexcept { 189| 23.3k| if (rhs.handle_) { ------------------ | Branch (189:9): [True: 0, False: 23.3k] ------------------ 190| 0| handle_ = rhs.handle_; 191| 0| handle_(action::move, &storage_, &rhs.storage_); 192| 0| call_ = rhs.call_; 193| 0| rhs.handle_ = nullptr; 194| 0| } 195| 23.3k| } EpollEchoServer.cpp:_ZN5ofats13any_invocableIFvPN3uWS12HttpResponseILb0EEEPNS1_11HttpRequestEEEC2IZNS1_12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOSB_NSt3__112basic_stringIcNSF_11char_traitsIcEENSF_9allocatorIcEEEEONSB_17WebSocketBehaviorIT_EEEUlPSN_PT0_E_vEEOSN_: 303| 11.6k| any_invocable(F&& f) { \ 304| 11.6k| base_type::template create>(std::forward(f)); \ 305| 11.6k| } \ EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEEE6createIZNS2_12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOSB_NSt3__112basic_stringIcNSF_11char_traitsIcEENSF_9allocatorIcEEEEONSB_17WebSocketBehaviorIT_EEEUlPSN_PT0_E_JST_EEEvDpOT0_: 232| 11.6k| void create(Args&&... args) { 233| 11.6k| using hdl = handler; 234| 11.6k| hdl::create(storage_, std::forward(args)...); 235| 11.6k| handle_ = &hdl::handle; 236| 11.6k| call_ = &hdl::call; 237| 11.6k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEEE13large_handlerIZNS2_12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOSB_NSt3__112basic_stringIcNSF_11char_traitsIcEENSF_9allocatorIcEEEEONSB_17WebSocketBehaviorIT_EEEUlPSN_PT0_E_E6createIJST_EEEvRNS0_7storageEDpOT_: 141| 11.6k| static void create(storage& s, Args&&... args) { 142| 11.6k| s.ptr_ = new T(std::forward(args)...); 143| 11.6k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEEE12handler_baseINS8_13large_handlerIZNS2_12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOSC_NSt3__112basic_stringIcNSG_11char_traitsIcEENSG_9allocatorIcEEEEONSC_17WebSocketBehaviorIT_EEEUlPSO_PT0_E_EEE6handleENS0_6actionEPNS0_7storageESZ_: 103| 35.0k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 35.0k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 35.0k] ------------------ 105| 11.6k| case (action::destroy): ------------------ | Branch (105:9): [True: 11.6k, False: 23.3k] ------------------ 106| 11.6k| Derived::destroy(*current); 107| 11.6k| break; 108| 23.3k| case (action::move): ------------------ | Branch (108:9): [True: 23.3k, False: 11.6k] ------------------ 109| 23.3k| Derived::move(*current, *other); 110| 23.3k| break; 111| 35.0k| } 112| 35.0k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEEE13large_handlerIZNS2_12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOSB_NSt3__112basic_stringIcNSF_11char_traitsIcEENSF_9allocatorIcEEEEONSB_17WebSocketBehaviorIT_EEEUlPSN_PT0_E_E7destroyERNS0_7storageE: 145| 11.6k| static void destroy(storage& s) noexcept { delete static_cast(s.ptr_); } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEEE13large_handlerIZNS2_12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOSB_NSt3__112basic_stringIcNSF_11char_traitsIcEENSF_9allocatorIcEEEEONSB_17WebSocketBehaviorIT_EEEUlPSN_PT0_E_E4moveERNS0_7storageESW_: 147| 23.3k| static void move(storage& dst, storage& src) noexcept { 148| 23.3k| dst.ptr_ = src.ptr_; 149| 23.3k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEEE13large_handlerIZNS2_12TemplatedAppILb0EE2wsIZ4testvE13PerSocketDataEEOSB_NSt3__112basic_stringIcNSF_11char_traitsIcEENSF_9allocatorIcEEEEONSB_17WebSocketBehaviorIT_EEEUlPSN_PT0_E_E4callERNS0_7storageES5_S7_: 151| 169k| static R call(storage& s, ArgTypes... args) { 152| 169k| return std::invoke(*static_cast(s.ptr_), 153| 169k| std::forward(args)...); 154| 169k| } _ZNK5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb0EEEPNS2_11HttpRequestEP19us_socket_context_tEEcvbEv: 228| 164k| explicit operator bool() const noexcept { return handle_ != nullptr; } EpollEchoServer.cpp:_ZN5ofats13any_invocableIFvPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEEC2IZ4testvE3$_0vEEOT_: 303| 5.84k| any_invocable(F&& f) { \ 304| 5.84k| base_type::template create>(std::forward(f)); \ 305| 5.84k| } \ EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEEC2Ev: 186| 23.3k| any_invocable_impl() noexcept = default; EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEE6createIZ4testvE3$_0JS9_EEEvDpOT0_: 232| 5.84k| void create(Args&&... args) { 233| 5.84k| using hdl = handler; 234| 5.84k| hdl::create(storage_, std::forward(args)...); 235| 5.84k| handle_ = &hdl::handle; 236| 5.84k| call_ = &hdl::call; 237| 5.84k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEE13small_handlerIZ4testvE3$_0E6createIJS9_EEEvRNS0_7storageEDpOT_: 118| 17.5k| static void create(storage& s, Args&&... args) { 119| 17.5k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEE12handler_baseINS7_13small_handlerIZ4testvE3$_0EEE6handleENS0_6actionEPNS0_7storageESF_: 103| 17.5k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 17.5k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 17.5k] ------------------ 105| 5.84k| case (action::destroy): ------------------ | Branch (105:9): [True: 5.84k, False: 11.6k] ------------------ 106| 5.84k| Derived::destroy(*current); 107| 5.84k| break; 108| 11.6k| case (action::move): ------------------ | Branch (108:9): [True: 11.6k, False: 5.84k] ------------------ 109| 11.6k| Derived::move(*current, *other); 110| 11.6k| break; 111| 17.5k| } 112| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEE13small_handlerIZ4testvE3$_0E7destroyERNS0_7storageE: 122| 17.5k| static void destroy(storage& s) noexcept { 123| 17.5k| T& value = *static_cast(static_cast(&s.buf_)); 124| 17.5k| value.~T(); 125| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEE13small_handlerIZ4testvE3$_0E4moveERNS0_7storageESC_: 127| 11.6k| static void move(storage& dst, storage& src) noexcept { 128| 11.6k| create(dst, std::move(*static_cast(static_cast(&src.buf_)))); 129| 11.6k| destroy(src); 130| 11.6k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEE13small_handlerIZ4testvE3$_0E4callERNS0_7storageES6_: 132| 130k| static R call(storage& s, ArgTypes... args) { 133| 130k| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 130k| std::forward(args)...); 135| 130k| } EpollEchoServer.cpp:_ZN5ofats13any_invocableIFvPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS6_11char_traitsIcEEEENS1_6OpCodeEEEC2IZ4testvE3$_1vEEOT_: 303| 5.84k| any_invocable(F&& f) { \ 304| 5.84k| base_type::template create>(std::forward(f)); \ 305| 5.84k| } \ EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEEC2Ev: 186| 11.6k| any_invocable_impl() noexcept = default; EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEE6createIZ4testvE3$_1JSF_EEEvDpOT0_: 232| 5.84k| void create(Args&&... args) { 233| 5.84k| using hdl = handler; 234| 5.84k| hdl::create(storage_, std::forward(args)...); 235| 5.84k| handle_ = &hdl::handle; 236| 5.84k| call_ = &hdl::call; 237| 5.84k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEE13small_handlerIZ4testvE3$_1E6createIJSF_EEEvRNS0_7storageEDpOT_: 118| 17.5k| static void create(storage& s, Args&&... args) { 119| 17.5k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEE12handler_baseINSD_13small_handlerIZ4testvE3$_1EEE6handleENS0_6actionEPNS0_7storageESL_: 103| 17.5k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 17.5k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 17.5k] ------------------ 105| 5.84k| case (action::destroy): ------------------ | Branch (105:9): [True: 5.84k, False: 11.6k] ------------------ 106| 5.84k| Derived::destroy(*current); 107| 5.84k| break; 108| 11.6k| case (action::move): ------------------ | Branch (108:9): [True: 11.6k, False: 5.84k] ------------------ 109| 11.6k| Derived::move(*current, *other); 110| 11.6k| break; 111| 17.5k| } 112| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEE13small_handlerIZ4testvE3$_1E7destroyERNS0_7storageE: 122| 17.5k| static void destroy(storage& s) noexcept { 123| 17.5k| T& value = *static_cast(static_cast(&s.buf_)); 124| 17.5k| value.~T(); 125| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEE13small_handlerIZ4testvE3$_1E4moveERNS0_7storageESI_: 127| 11.6k| static void move(storage& dst, storage& src) noexcept { 128| 11.6k| create(dst, std::move(*static_cast(static_cast(&src.buf_)))); 129| 11.6k| destroy(src); 130| 11.6k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEE13small_handlerIZ4testvE3$_1E4callERNS0_7storageES6_SB_SC_: 132| 29.1k| static R call(storage& s, ArgTypes... args) { 133| 29.1k| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 29.1k| std::forward(args)...); 135| 29.1k| } EpollEchoServer.cpp:_ZN5ofats13any_invocableIFvPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEEC2IZ4testvE3$_2vEEOT_: 303| 5.84k| any_invocable(F&& f) { \ 304| 5.84k| base_type::template create>(std::forward(f)); \ 305| 5.84k| } \ EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEE6createIZ4testvE3$_2JS9_EEEvDpOT0_: 232| 5.84k| void create(Args&&... args) { 233| 5.84k| using hdl = handler; 234| 5.84k| hdl::create(storage_, std::forward(args)...); 235| 5.84k| handle_ = &hdl::handle; 236| 5.84k| call_ = &hdl::call; 237| 5.84k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEE13small_handlerIZ4testvE3$_2E6createIJS9_EEEvRNS0_7storageEDpOT_: 118| 17.5k| static void create(storage& s, Args&&... args) { 119| 17.5k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEE12handler_baseINS7_13small_handlerIZ4testvE3$_2EEE6handleENS0_6actionEPNS0_7storageESF_: 103| 17.5k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 17.5k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 17.5k] ------------------ 105| 5.84k| case (action::destroy): ------------------ | Branch (105:9): [True: 5.84k, False: 11.6k] ------------------ 106| 5.84k| Derived::destroy(*current); 107| 5.84k| break; 108| 11.6k| case (action::move): ------------------ | Branch (108:9): [True: 11.6k, False: 5.84k] ------------------ 109| 11.6k| Derived::move(*current, *other); 110| 11.6k| break; 111| 17.5k| } 112| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEE13small_handlerIZ4testvE3$_2E7destroyERNS0_7storageE: 122| 17.5k| static void destroy(storage& s) noexcept { 123| 17.5k| T& value = *static_cast(static_cast(&s.buf_)); 124| 17.5k| value.~T(); 125| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEE13small_handlerIZ4testvE3$_2E4moveERNS0_7storageESC_: 127| 11.6k| static void move(storage& dst, storage& src) noexcept { 128| 11.6k| create(dst, std::move(*static_cast(static_cast(&src.buf_)))); 129| 11.6k| destroy(src); 130| 11.6k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEE13small_handlerIZ4testvE3$_2E4callERNS0_7storageES6_: 132| 19.4k| static R call(storage& s, ArgTypes... args) { 133| 19.4k| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 19.4k| std::forward(args)...); 135| 19.4k| } EpollEchoServer.cpp:_ZN5ofats13any_invocableIFvPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS6_11char_traitsIcEEEEEEC2IZ4testvE3$_3vEEOT_: 303| 5.84k| any_invocable(F&& f) { \ 304| 5.84k| base_type::template create>(std::forward(f)); \ 305| 5.84k| } \ EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEEC2Ev: 186| 23.3k| any_invocable_impl() noexcept = default; EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE6createIZ4testvE3$_3JSE_EEEvDpOT0_: 232| 5.84k| void create(Args&&... args) { 233| 5.84k| using hdl = handler; 234| 5.84k| hdl::create(storage_, std::forward(args)...); 235| 5.84k| handle_ = &hdl::handle; 236| 5.84k| call_ = &hdl::call; 237| 5.84k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE3$_3E6createIJSE_EEEvRNS0_7storageEDpOT_: 118| 17.5k| static void create(storage& s, Args&&... args) { 119| 17.5k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE12handler_baseINSC_13small_handlerIZ4testvE3$_3EEE6handleENS0_6actionEPNS0_7storageESK_: 103| 17.5k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 17.5k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 17.5k] ------------------ 105| 5.84k| case (action::destroy): ------------------ | Branch (105:9): [True: 5.84k, False: 11.6k] ------------------ 106| 5.84k| Derived::destroy(*current); 107| 5.84k| break; 108| 11.6k| case (action::move): ------------------ | Branch (108:9): [True: 11.6k, False: 5.84k] ------------------ 109| 11.6k| Derived::move(*current, *other); 110| 11.6k| break; 111| 17.5k| } 112| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE3$_3E7destroyERNS0_7storageE: 122| 17.5k| static void destroy(storage& s) noexcept { 123| 17.5k| T& value = *static_cast(static_cast(&s.buf_)); 124| 17.5k| value.~T(); 125| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE3$_3E4moveERNS0_7storageESH_: 127| 11.6k| static void move(storage& dst, storage& src) noexcept { 128| 11.6k| create(dst, std::move(*static_cast(static_cast(&src.buf_)))); 129| 11.6k| destroy(src); 130| 11.6k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE3$_3E4callERNS0_7storageES6_SB_: 132| 3.94k| static R call(storage& s, ArgTypes... args) { 133| 3.94k| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 3.94k| std::forward(args)...); 135| 3.94k| } EpollEchoServer.cpp:_ZN5ofats13any_invocableIFvPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS6_11char_traitsIcEEEEEEC2IZ4testvE3$_4vEEOT_: 303| 5.84k| any_invocable(F&& f) { \ 304| 5.84k| base_type::template create>(std::forward(f)); \ 305| 5.84k| } \ EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE6createIZ4testvE3$_4JSE_EEEvDpOT0_: 232| 5.84k| void create(Args&&... args) { 233| 5.84k| using hdl = handler; 234| 5.84k| hdl::create(storage_, std::forward(args)...); 235| 5.84k| handle_ = &hdl::handle; 236| 5.84k| call_ = &hdl::call; 237| 5.84k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE3$_4E6createIJSE_EEEvRNS0_7storageEDpOT_: 118| 17.5k| static void create(storage& s, Args&&... args) { 119| 17.5k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE12handler_baseINSC_13small_handlerIZ4testvE3$_4EEE6handleENS0_6actionEPNS0_7storageESK_: 103| 17.5k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 17.5k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 17.5k] ------------------ 105| 5.84k| case (action::destroy): ------------------ | Branch (105:9): [True: 5.84k, False: 11.6k] ------------------ 106| 5.84k| Derived::destroy(*current); 107| 5.84k| break; 108| 11.6k| case (action::move): ------------------ | Branch (108:9): [True: 11.6k, False: 5.84k] ------------------ 109| 11.6k| Derived::move(*current, *other); 110| 11.6k| break; 111| 17.5k| } 112| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE3$_4E7destroyERNS0_7storageE: 122| 17.5k| static void destroy(storage& s) noexcept { 123| 17.5k| T& value = *static_cast(static_cast(&s.buf_)); 124| 17.5k| value.~T(); 125| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE3$_4E4moveERNS0_7storageESH_: 127| 11.6k| static void move(storage& dst, storage& src) noexcept { 128| 11.6k| create(dst, std::move(*static_cast(static_cast(&src.buf_)))); 129| 11.6k| destroy(src); 130| 11.6k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE3$_4E4callERNS0_7storageES6_SB_: 132| 1.49k| static R call(storage& s, ArgTypes... args) { 133| 1.49k| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 1.49k| std::forward(args)...); 135| 1.49k| } EpollEchoServer.cpp:_ZN5ofats13any_invocableIFvPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS6_11char_traitsIcEEEEEEC2IZ4testvE3$_5vEEOT_: 303| 5.84k| any_invocable(F&& f) { \ 304| 5.84k| base_type::template create>(std::forward(f)); \ 305| 5.84k| } \ EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE6createIZ4testvE3$_5JSE_EEEvDpOT0_: 232| 5.84k| void create(Args&&... args) { 233| 5.84k| using hdl = handler; 234| 5.84k| hdl::create(storage_, std::forward(args)...); 235| 5.84k| handle_ = &hdl::handle; 236| 5.84k| call_ = &hdl::call; 237| 5.84k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE3$_5E6createIJSE_EEEvRNS0_7storageEDpOT_: 118| 17.5k| static void create(storage& s, Args&&... args) { 119| 17.5k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE12handler_baseINSC_13small_handlerIZ4testvE3$_5EEE6handleENS0_6actionEPNS0_7storageESK_: 103| 17.5k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 17.5k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 17.5k] ------------------ 105| 5.84k| case (action::destroy): ------------------ | Branch (105:9): [True: 5.84k, False: 11.6k] ------------------ 106| 5.84k| Derived::destroy(*current); 107| 5.84k| break; 108| 11.6k| case (action::move): ------------------ | Branch (108:9): [True: 11.6k, False: 5.84k] ------------------ 109| 11.6k| Derived::move(*current, *other); 110| 11.6k| break; 111| 17.5k| } 112| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE3$_5E7destroyERNS0_7storageE: 122| 17.5k| static void destroy(storage& s) noexcept { 123| 17.5k| T& value = *static_cast(static_cast(&s.buf_)); 124| 17.5k| value.~T(); 125| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE3$_5E4moveERNS0_7storageESH_: 127| 11.6k| static void move(storage& dst, storage& src) noexcept { 128| 11.6k| create(dst, std::move(*static_cast(static_cast(&src.buf_)))); 129| 11.6k| destroy(src); 130| 11.6k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE3$_5E4callERNS0_7storageES6_iSB_: 132| 130k| static R call(storage& s, ArgTypes... args) { 133| 130k| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 130k| std::forward(args)...); 135| 130k| } EpollEchoServer.cpp:_ZN5ofats13any_invocableIFvPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEEC2IZ4testvE3$_6vEEOT_: 303| 5.84k| any_invocable(F&& f) { \ 304| 5.84k| base_type::template create>(std::forward(f)); \ 305| 5.84k| } \ EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEE6createIZ4testvE3$_6JS9_EEEvDpOT0_: 232| 5.84k| void create(Args&&... args) { 233| 5.84k| using hdl = handler; 234| 5.84k| hdl::create(storage_, std::forward(args)...); 235| 5.84k| handle_ = &hdl::handle; 236| 5.84k| call_ = &hdl::call; 237| 5.84k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEE13small_handlerIZ4testvE3$_6E6createIJS9_EEEvRNS0_7storageEDpOT_: 118| 17.5k| static void create(storage& s, Args&&... args) { 119| 17.5k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEE12handler_baseINS7_13small_handlerIZ4testvE3$_6EEE6handleENS0_6actionEPNS0_7storageESF_: 103| 17.5k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 17.5k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 17.5k] ------------------ 105| 5.84k| case (action::destroy): ------------------ | Branch (105:9): [True: 5.84k, False: 11.6k] ------------------ 106| 5.84k| Derived::destroy(*current); 107| 5.84k| break; 108| 11.6k| case (action::move): ------------------ | Branch (108:9): [True: 11.6k, False: 5.84k] ------------------ 109| 11.6k| Derived::move(*current, *other); 110| 11.6k| break; 111| 17.5k| } 112| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEE13small_handlerIZ4testvE3$_6E7destroyERNS0_7storageE: 122| 17.5k| static void destroy(storage& s) noexcept { 123| 17.5k| T& value = *static_cast(static_cast(&s.buf_)); 124| 17.5k| value.~T(); 125| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEE13small_handlerIZ4testvE3$_6E4moveERNS0_7storageESC_: 127| 11.6k| static void move(storage& dst, storage& src) noexcept { 128| 11.6k| create(dst, std::move(*static_cast(static_cast(&src.buf_)))); 129| 11.6k| destroy(src); 130| 11.6k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEE13small_handlerIZ4testvE3$_6E4callERNS0_7storageES6_: 132| 33.8k| static R call(storage& s, ArgTypes... args) { 133| 33.8k| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 33.8k| std::forward(args)...); 135| 33.8k| } EpollEchoServer.cpp:_ZN5ofats13any_invocableIFvPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS6_11char_traitsIcEEEENS1_6OpCodeEEEC2IZ4testvE3$_7vEEOT_: 303| 5.84k| any_invocable(F&& f) { \ 304| 5.84k| base_type::template create>(std::forward(f)); \ 305| 5.84k| } \ EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEE6createIZ4testvE3$_7JSF_EEEvDpOT0_: 232| 5.84k| void create(Args&&... args) { 233| 5.84k| using hdl = handler; 234| 5.84k| hdl::create(storage_, std::forward(args)...); 235| 5.84k| handle_ = &hdl::handle; 236| 5.84k| call_ = &hdl::call; 237| 5.84k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEE13small_handlerIZ4testvE3$_7E6createIJSF_EEEvRNS0_7storageEDpOT_: 118| 17.5k| static void create(storage& s, Args&&... args) { 119| 17.5k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEE12handler_baseINSD_13small_handlerIZ4testvE3$_7EEE6handleENS0_6actionEPNS0_7storageESL_: 103| 17.5k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 17.5k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 17.5k] ------------------ 105| 5.84k| case (action::destroy): ------------------ | Branch (105:9): [True: 5.84k, False: 11.6k] ------------------ 106| 5.84k| Derived::destroy(*current); 107| 5.84k| break; 108| 11.6k| case (action::move): ------------------ | Branch (108:9): [True: 11.6k, False: 5.84k] ------------------ 109| 11.6k| Derived::move(*current, *other); 110| 11.6k| break; 111| 17.5k| } 112| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEE13small_handlerIZ4testvE3$_7E7destroyERNS0_7storageE: 122| 17.5k| static void destroy(storage& s) noexcept { 123| 17.5k| T& value = *static_cast(static_cast(&s.buf_)); 124| 17.5k| value.~T(); 125| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEE13small_handlerIZ4testvE3$_7E4moveERNS0_7storageESI_: 127| 11.6k| static void move(storage& dst, storage& src) noexcept { 128| 11.6k| create(dst, std::move(*static_cast(static_cast(&src.buf_)))); 129| 11.6k| destroy(src); 130| 11.6k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEE13small_handlerIZ4testvE3$_7E4callERNS0_7storageES6_SB_SC_: 132| 9.49k| static R call(storage& s, ArgTypes... args) { 133| 9.49k| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 9.49k| std::forward(args)...); 135| 9.49k| } EpollEchoServer.cpp:_ZN5ofats13any_invocableIFvPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEEC2IZ4testvE3$_8vEEOT_: 303| 5.84k| any_invocable(F&& f) { \ 304| 5.84k| base_type::template create>(std::forward(f)); \ 305| 5.84k| } \ EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEE6createIZ4testvE3$_8JS9_EEEvDpOT0_: 232| 5.84k| void create(Args&&... args) { 233| 5.84k| using hdl = handler; 234| 5.84k| hdl::create(storage_, std::forward(args)...); 235| 5.84k| handle_ = &hdl::handle; 236| 5.84k| call_ = &hdl::call; 237| 5.84k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEE13small_handlerIZ4testvE3$_8E6createIJS9_EEEvRNS0_7storageEDpOT_: 118| 17.5k| static void create(storage& s, Args&&... args) { 119| 17.5k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEE12handler_baseINS7_13small_handlerIZ4testvE3$_8EEE6handleENS0_6actionEPNS0_7storageESF_: 103| 17.5k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 17.5k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 17.5k] ------------------ 105| 5.84k| case (action::destroy): ------------------ | Branch (105:9): [True: 5.84k, False: 11.6k] ------------------ 106| 5.84k| Derived::destroy(*current); 107| 5.84k| break; 108| 11.6k| case (action::move): ------------------ | Branch (108:9): [True: 11.6k, False: 5.84k] ------------------ 109| 11.6k| Derived::move(*current, *other); 110| 11.6k| break; 111| 17.5k| } 112| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEE13small_handlerIZ4testvE3$_8E7destroyERNS0_7storageE: 122| 17.5k| static void destroy(storage& s) noexcept { 123| 17.5k| T& value = *static_cast(static_cast(&s.buf_)); 124| 17.5k| value.~T(); 125| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEE13small_handlerIZ4testvE3$_8E4moveERNS0_7storageESC_: 127| 11.6k| static void move(storage& dst, storage& src) noexcept { 128| 11.6k| create(dst, std::move(*static_cast(static_cast(&src.buf_)))); 129| 11.6k| destroy(src); 130| 11.6k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEE13small_handlerIZ4testvE3$_8E4callERNS0_7storageES6_: 132| 5.43k| static R call(storage& s, ArgTypes... args) { 133| 5.43k| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 5.43k| std::forward(args)...); 135| 5.43k| } EpollEchoServer.cpp:_ZN5ofats13any_invocableIFvPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS6_11char_traitsIcEEEEEEC2IZ4testvE3$_9vEEOT_: 303| 5.84k| any_invocable(F&& f) { \ 304| 5.84k| base_type::template create>(std::forward(f)); \ 305| 5.84k| } \ EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE6createIZ4testvE3$_9JSE_EEEvDpOT0_: 232| 5.84k| void create(Args&&... args) { 233| 5.84k| using hdl = handler; 234| 5.84k| hdl::create(storage_, std::forward(args)...); 235| 5.84k| handle_ = &hdl::handle; 236| 5.84k| call_ = &hdl::call; 237| 5.84k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE3$_9E6createIJSE_EEEvRNS0_7storageEDpOT_: 118| 17.5k| static void create(storage& s, Args&&... args) { 119| 17.5k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE12handler_baseINSC_13small_handlerIZ4testvE3$_9EEE6handleENS0_6actionEPNS0_7storageESK_: 103| 17.5k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 17.5k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 17.5k] ------------------ 105| 5.84k| case (action::destroy): ------------------ | Branch (105:9): [True: 5.84k, False: 11.6k] ------------------ 106| 5.84k| Derived::destroy(*current); 107| 5.84k| break; 108| 11.6k| case (action::move): ------------------ | Branch (108:9): [True: 11.6k, False: 5.84k] ------------------ 109| 11.6k| Derived::move(*current, *other); 110| 11.6k| break; 111| 17.5k| } 112| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE3$_9E7destroyERNS0_7storageE: 122| 17.5k| static void destroy(storage& s) noexcept { 123| 17.5k| T& value = *static_cast(static_cast(&s.buf_)); 124| 17.5k| value.~T(); 125| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE3$_9E4moveERNS0_7storageESH_: 127| 11.6k| static void move(storage& dst, storage& src) noexcept { 128| 11.6k| create(dst, std::move(*static_cast(static_cast(&src.buf_)))); 129| 11.6k| destroy(src); 130| 11.6k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE3$_9E4callERNS0_7storageES6_SB_: 132| 7.41k| static R call(storage& s, ArgTypes... args) { 133| 7.41k| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 7.41k| std::forward(args)...); 135| 7.41k| } EpollEchoServer.cpp:_ZN5ofats13any_invocableIFvvEEC2IZZ4testvENK3$_9clIN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEEDaPT_NSt3__117basic_string_viewIcNSC_11char_traitsIcEEEEEUlvE_vEEOSA_: 303| 7.41k| any_invocable(F&& f) { \ 304| 7.41k| base_type::template create>(std::forward(f)); \ 305| 7.41k| } \ EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJEE6createIZZ4testvENK3$_9clIN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEEDaPT_NSt3__117basic_string_viewIcNSC_11char_traitsIcEEEEEUlvE_JSH_EEEvDpOT0_: 232| 7.41k| void create(Args&&... args) { 233| 7.41k| using hdl = handler; 234| 7.41k| hdl::create(storage_, std::forward(args)...); 235| 7.41k| handle_ = &hdl::handle; 236| 7.41k| call_ = &hdl::call; 237| 7.41k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJEE13large_handlerIZZ4testvENK3$_9clIN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEEDaPT_NSt3__117basic_string_viewIcNSC_11char_traitsIcEEEEEUlvE_E6createIJSH_EEEvRNS0_7storageEDpOT_: 141| 7.41k| static void create(storage& s, Args&&... args) { 142| 7.41k| s.ptr_ = new T(std::forward(args)...); 143| 7.41k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJEE12handler_baseINS2_13large_handlerIZZ4testvENK3$_9clIN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEEDaPT_NSt3__117basic_string_viewIcNSD_11char_traitsIcEEEEEUlvE_EEE6handleENS0_6actionEPNS0_7storageESN_: 103| 22.6k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 22.6k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 22.6k] ------------------ 105| 7.41k| case (action::destroy): ------------------ | Branch (105:9): [True: 7.41k, False: 15.1k] ------------------ 106| 7.41k| Derived::destroy(*current); 107| 7.41k| break; 108| 15.1k| case (action::move): ------------------ | Branch (108:9): [True: 15.1k, False: 7.41k] ------------------ 109| 15.1k| Derived::move(*current, *other); 110| 15.1k| break; 111| 22.6k| } 112| 22.6k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJEE13large_handlerIZZ4testvENK3$_9clIN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEEDaPT_NSt3__117basic_string_viewIcNSC_11char_traitsIcEEEEEUlvE_E7destroyERNS0_7storageE: 145| 7.41k| static void destroy(storage& s) noexcept { delete static_cast(s.ptr_); } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJEE13large_handlerIZZ4testvENK3$_9clIN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEEDaPT_NSt3__117basic_string_viewIcNSC_11char_traitsIcEEEEEUlvE_E4moveERNS0_7storageESK_: 147| 15.1k| static void move(storage& dst, storage& src) noexcept { 148| 15.1k| dst.ptr_ = src.ptr_; 149| 15.1k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJEE13large_handlerIZZ4testvENK3$_9clIN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEEDaPT_NSt3__117basic_string_viewIcNSC_11char_traitsIcEEEEEUlvE_E4callERNS0_7storageE: 151| 3.78k| static R call(storage& s, ArgTypes... args) { 152| 3.78k| return std::invoke(*static_cast(s.ptr_), 153| 3.78k| std::forward(args)...); 154| 3.78k| } EpollEchoServer.cpp:_ZN5ofats13any_invocableIFvPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS6_11char_traitsIcEEEEEEC2IZ4testvE4$_10vEEOT_: 303| 5.84k| any_invocable(F&& f) { \ 304| 5.84k| base_type::template create>(std::forward(f)); \ 305| 5.84k| } \ EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE6createIZ4testvE4$_10JSE_EEEvDpOT0_: 232| 5.84k| void create(Args&&... args) { 233| 5.84k| using hdl = handler; 234| 5.84k| hdl::create(storage_, std::forward(args)...); 235| 5.84k| handle_ = &hdl::handle; 236| 5.84k| call_ = &hdl::call; 237| 5.84k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE4$_10E6createIJSE_EEEvRNS0_7storageEDpOT_: 118| 17.5k| static void create(storage& s, Args&&... args) { 119| 17.5k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE12handler_baseINSC_13small_handlerIZ4testvE4$_10EEE6handleENS0_6actionEPNS0_7storageESK_: 103| 17.5k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 17.5k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 17.5k] ------------------ 105| 5.84k| case (action::destroy): ------------------ | Branch (105:9): [True: 5.84k, False: 11.6k] ------------------ 106| 5.84k| Derived::destroy(*current); 107| 5.84k| break; 108| 11.6k| case (action::move): ------------------ | Branch (108:9): [True: 11.6k, False: 5.84k] ------------------ 109| 11.6k| Derived::move(*current, *other); 110| 11.6k| break; 111| 17.5k| } 112| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE4$_10E7destroyERNS0_7storageE: 122| 17.5k| static void destroy(storage& s) noexcept { 123| 17.5k| T& value = *static_cast(static_cast(&s.buf_)); 124| 17.5k| value.~T(); 125| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE4$_10E4moveERNS0_7storageESH_: 127| 11.6k| static void move(storage& dst, storage& src) noexcept { 128| 11.6k| create(dst, std::move(*static_cast(static_cast(&src.buf_)))); 129| 11.6k| destroy(src); 130| 11.6k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE4$_10E4callERNS0_7storageES6_SB_: 132| 2.06k| static R call(storage& s, ArgTypes... args) { 133| 2.06k| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 2.06k| std::forward(args)...); 135| 2.06k| } EpollEchoServer.cpp:_ZN5ofats13any_invocableIFvPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS6_11char_traitsIcEEEEEEC2IZ4testvE4$_11vEEOT_: 303| 5.84k| any_invocable(F&& f) { \ 304| 5.84k| base_type::template create>(std::forward(f)); \ 305| 5.84k| } \ EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE6createIZ4testvE4$_11JSE_EEEvDpOT0_: 232| 5.84k| void create(Args&&... args) { 233| 5.84k| using hdl = handler; 234| 5.84k| hdl::create(storage_, std::forward(args)...); 235| 5.84k| handle_ = &hdl::handle; 236| 5.84k| call_ = &hdl::call; 237| 5.84k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE4$_11E6createIJSE_EEEvRNS0_7storageEDpOT_: 118| 17.5k| static void create(storage& s, Args&&... args) { 119| 17.5k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE12handler_baseINSC_13small_handlerIZ4testvE4$_11EEE6handleENS0_6actionEPNS0_7storageESK_: 103| 17.5k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 17.5k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 17.5k] ------------------ 105| 5.84k| case (action::destroy): ------------------ | Branch (105:9): [True: 5.84k, False: 11.6k] ------------------ 106| 5.84k| Derived::destroy(*current); 107| 5.84k| break; 108| 11.6k| case (action::move): ------------------ | Branch (108:9): [True: 11.6k, False: 5.84k] ------------------ 109| 11.6k| Derived::move(*current, *other); 110| 11.6k| break; 111| 17.5k| } 112| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE4$_11E7destroyERNS0_7storageE: 122| 17.5k| static void destroy(storage& s) noexcept { 123| 17.5k| T& value = *static_cast(static_cast(&s.buf_)); 124| 17.5k| value.~T(); 125| 17.5k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE4$_11E4moveERNS0_7storageESH_: 127| 11.6k| static void move(storage& dst, storage& src) noexcept { 128| 11.6k| create(dst, std::move(*static_cast(static_cast(&src.buf_)))); 129| 11.6k| destroy(src); 130| 11.6k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE4$_11E4callERNS0_7storageES6_iSB_: 132| 33.8k| static R call(storage& s, ArgTypes... args) { 133| 33.8k| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 33.8k| std::forward(args)...); 135| 33.8k| } _ZN5ofats13any_invocableIFvP18us_listen_socket_tEEclES2_: 345| 5.84k| R operator()(ArgTypes... args) cv ref noexcept(noex) { \ 346| 5.84k| return base_type::call(std::forward(args)...); \ 347| 5.84k| } \ _ZN5ofats10any_detail18any_invocable_implIvLb0EJP18us_listen_socket_tEE4callES3_: 246| 5.84k| R call(ArgTypes... args) noexcept(is_noexcept) { 247| 5.84k| return call_(storage_, std::forward(args)...); 248| 5.84k| } EpollEchoServer.cpp:_ZN5ofats13any_invocableIFvP18us_listen_socket_tEEC2IZ4testvE4$_12vEEOT_: 303| 5.84k| any_invocable(F&& f) { \ 304| 5.84k| base_type::template create>(std::forward(f)); \ 305| 5.84k| } \ _ZN5ofats10any_detail18any_invocable_implIvLb0EJP18us_listen_socket_tEEC2Ev: 186| 5.84k| any_invocable_impl() noexcept = default; EpollEchoServer.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJP18us_listen_socket_tEE6createIZ4testvE4$_12JS6_EEEvDpOT0_: 232| 5.84k| void create(Args&&... args) { 233| 5.84k| using hdl = handler; 234| 5.84k| hdl::create(storage_, std::forward(args)...); 235| 5.84k| handle_ = &hdl::handle; 236| 5.84k| call_ = &hdl::call; 237| 5.84k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJP18us_listen_socket_tEE13small_handlerIZ4testvE4$_12E6createIJS6_EEEvRNS0_7storageEDpOT_: 118| 5.84k| static void create(storage& s, Args&&... args) { 119| 5.84k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 5.84k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJP18us_listen_socket_tEE12handler_baseINS4_13small_handlerIZ4testvE4$_12EEE6handleENS0_6actionEPNS0_7storageESC_: 103| 5.84k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 5.84k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 5.84k] ------------------ 105| 5.84k| case (action::destroy): ------------------ | Branch (105:9): [True: 5.84k, False: 0] ------------------ 106| 5.84k| Derived::destroy(*current); 107| 5.84k| break; 108| 0| case (action::move): ------------------ | Branch (108:9): [True: 0, False: 5.84k] ------------------ 109| 0| Derived::move(*current, *other); 110| 0| break; 111| 5.84k| } 112| 5.84k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJP18us_listen_socket_tEE13small_handlerIZ4testvE4$_12E7destroyERNS0_7storageE: 122| 5.84k| static void destroy(storage& s) noexcept { 123| 5.84k| T& value = *static_cast(static_cast(&s.buf_)); 124| 5.84k| value.~T(); 125| 5.84k| } EpollEchoServer.cpp:_ZN5ofats10any_detail14handler_traitsIvJP18us_listen_socket_tEE13small_handlerIZ4testvE4$_12E4callERNS0_7storageES3_: 132| 5.84k| static R call(storage& s, ArgTypes... args) { 133| 5.84k| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 5.84k| std::forward(args)...); 135| 5.84k| } _ZN3uWS15DeflationStream7deflateEPNS_11ZlibContextENSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEb: 90| 3.34k| std::string_view deflate(ZlibContext * /*zlibContext*/, std::string_view raw, bool /*reset*/) { 91| 3.34k| return raw; 92| 3.34k| } _ZN3uWS15InflationStream7inflateEPNS_11ZlibContextENSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEmb: 83| 1.84k| std::optional inflate(ZlibContext * /*zlibContext*/, std::string_view compressed, size_t maxPayloadLength, bool /*reset*/) { 84| 1.84k| return compressed.substr(0, std::min(maxPayloadLength, compressed.length())); 85| 1.84k| } _ZN3uWS15InflationStreamC2ENS_15CompressOptionsE: 86| 5.56k| InflationStream(CompressOptions /*compressOptions*/) { 87| 5.56k| } _ZN3uWS15DeflationStreamC2ENS_15CompressOptionsE: 93| 7.77k| DeflationStream(CompressOptions /*compressOptions*/) { 94| 7.77k| } _ZN3uWS9TopicTreeINS_16TopicTreeMessageENS_19TopicTreeBigMessageEE5drainEPNS_10SubscriberE: 249| 39.4k| void drain(Subscriber *s) { 250| | /* The list is undefined and cannot be touched unless needsDrainage(). */ 251| 39.4k| if (s->needsDrainage()) { ------------------ | Branch (251:13): [True: 2.39k, False: 37.0k] ------------------ 252| | /* This function differs from drainImpl by properly unlinking 253| | * the subscriber from drainableSubscribers. drainImpl does not. */ 254| 2.39k| unlinkDrainableSubscriber(s); 255| | 256| | /* This one always resets needsDrainage before it calls any cb's. 257| | * Otherwise we would stackoverflow when sending after publish but before drain. */ 258| 2.39k| drainImpl(s); 259| | 260| | /* If we drained last subscriber, also clear outgoingMessages */ 261| 2.39k| if (!drainableSubscribers) { ------------------ | Branch (261:17): [True: 620, False: 1.77k] ------------------ 262| 620| outgoingMessages.clear(); 263| 620| } 264| 2.39k| } 265| 39.4k| } _ZN3uWS10Subscriber13needsDrainageEv: 73| 169k| bool needsDrainage() { 74| 169k| return numMessageIndices; 75| 169k| } _ZN3uWS9TopicTreeINS_16TopicTreeMessageENS_19TopicTreeBigMessageEE25unlinkDrainableSubscriberEPNS_10SubscriberE: 132| 6.58k| void unlinkDrainableSubscriber(Subscriber *s) { 133| 6.58k| if (s->prev) { ------------------ | Branch (133:13): [True: 2.96k, False: 3.62k] ------------------ 134| 2.96k| s->prev->next = s->next; 135| 2.96k| } 136| 6.58k| if (s->next) { ------------------ | Branch (136:13): [True: 2.44k, False: 4.14k] ------------------ 137| 2.44k| s->next->prev = s->prev; 138| 2.44k| } 139| | /* If we are the head, then we also need to reset the head */ 140| 6.58k| if (drainableSubscribers == s) { ------------------ | Branch (140:13): [True: 3.62k, False: 2.96k] ------------------ 141| 3.62k| drainableSubscribers = s->next; 142| 3.62k| } 143| 6.58k| } _ZN3uWS9TopicTreeINS_16TopicTreeMessageENS_19TopicTreeBigMessageEE9drainImplEPNS_10SubscriberE: 113| 4.99k| void drainImpl(Subscriber *s) { 114| | /* Before we call cb we need to make sure this subscriber will not report needsDrainage() 115| | * since WebSocket::send will call drain from within the cb in that case.*/ 116| 4.99k| int numMessageIndices = s->numMessageIndices; 117| 4.99k| s->numMessageIndices = 0; 118| | 119| | /* Then we emit cb */ 120| 39.2k| for (int i = 0; i < numMessageIndices; i++) { ------------------ | Branch (120:25): [True: 34.2k, False: 4.99k] ------------------ 121| 34.2k| T &outgoingMessage = outgoingMessages[s->messageIndices[i]]; 122| | 123| 34.2k| int flags = (i == numMessageIndices - 1) ? LAST : 0; ------------------ | Branch (123:25): [True: 4.99k, False: 29.2k] ------------------ 124| | 125| | /* Returning true will stop drainage short (such as when backpressure is too high) */ 126| 34.2k| if (cb(s, outgoingMessage, (IteratorFlags)(flags | (i == 0 ? FIRST : 0)))) { ------------------ | Branch (126:17): [True: 0, False: 34.2k] | Branch (126:65): [True: 4.99k, False: 29.2k] ------------------ 127| 0| break; 128| 0| } 129| 34.2k| } 130| 4.99k| } _ZN3uWS9TopicTreeINS_16TopicTreeMessageENS_19TopicTreeBigMessageEEC2ENSt3__18functionIFbPNS_10SubscriberERS1_NS3_13IteratorFlagsEEEE: 147| 5.84k| TopicTree(std::function cb) : cb(cb) { 148| | 149| 5.84k| } _ZN3uWS9TopicTreeINS_16TopicTreeMessageENS_19TopicTreeBigMessageEE5drainEv: 268| 4.36M| void drain() { 269| 4.36M| if (drainableSubscribers) { ------------------ | Branch (269:13): [True: 1.09k, False: 4.36M] ------------------ 270| | /* Drain one socket a time */ 271| 3.69k| for (Subscriber *s = drainableSubscribers; s; s = s->next) { ------------------ | Branch (271:56): [True: 2.59k, False: 1.09k] ------------------ 272| | /* Instead of unlinking every single subscriber, we just leave the list undefined 273| | * and reset drainableSubscribers ptr below. */ 274| 2.59k| drainImpl(s); 275| 2.59k| } 276| | /* Drain always clears drainableSubscribers and outgoingMessages */ 277| 1.09k| drainableSubscribers = nullptr; 278| 1.09k| outgoingMessages.clear(); 279| 1.09k| } 280| 4.36M| } _ZN3uWS9TopicTreeINS_16TopicTreeMessageENS_19TopicTreeBigMessageEE14freeSubscriberEPNS_10SubscriberE: 222| 164k| void freeSubscriber(Subscriber *s) { 223| | 224| | /* I guess we call this one even if we are not subscribers */ 225| 164k| if (!s) { ------------------ | Branch (225:13): [True: 33.8k, False: 130k] ------------------ 226| 33.8k| return; 227| 33.8k| } 228| | 229| | /* For all topics, unsubscribe */ 230| 130k| for (Topic *topicPtr : s->topics) { ------------------ | Branch (230:30): [True: 130k, False: 130k] ------------------ 231| | /* If we are the last subscriber, simply remove the whole topic */ 232| 130k| if (topicPtr->size() == 1) { ------------------ | Branch (232:17): [True: 27.1k, False: 103k] ------------------ 233| 27.1k| topics.erase(topicPtr->name); 234| 103k| } else { 235| | /* Otherwise just remove us */ 236| 103k| topicPtr->erase(s); 237| 103k| } 238| 130k| } 239| | 240| | /* We also need to unlink us */ 241| 130k| if (s->needsDrainage()) { ------------------ | Branch (241:13): [True: 4.19k, False: 126k] ------------------ 242| 4.19k| unlinkDrainableSubscriber(s); 243| 4.19k| } 244| | 245| 130k| delete s; 246| 130k| } _ZN3uWS9TopicTreeINS_16TopicTreeMessageENS_19TopicTreeBigMessageEE16createSubscriberEv: 217| 130k| Subscriber *createSubscriber() { 218| 130k| return new Subscriber(); 219| 130k| } _ZN3uWS10SubscriberC2Ev: 53| 130k| Subscriber() = default; _ZN3uWS9TopicTreeINS_16TopicTreeMessageENS_19TopicTreeBigMessageEE9subscribeEPNS_10SubscriberENSt3__117basic_string_viewIcNS6_11char_traitsIcEEEE: 161| 130k| Topic *subscribe(Subscriber *s, std::string_view topic) { 162| | /* Notify user that they are doing something wrong here */ 163| 130k| checkIteratingSubscriber(s); 164| | 165| | /* Lookup or create new topic */ 166| 130k| Topic *topicPtr = lookupTopic(topic); 167| 130k| if (!topicPtr) { ------------------ | Branch (167:13): [True: 27.1k, False: 103k] ------------------ 168| 27.1k| Topic *newTopic = new Topic(topic); 169| 27.1k| topics.insert({std::string_view(newTopic->name.data(), newTopic->name.length()), std::unique_ptr(newTopic)}); 170| 27.1k| topicPtr = newTopic; 171| 27.1k| } 172| | 173| | /* Insert us in topic, insert topic in us */ 174| 130k| auto [it, inserted] = s->topics.insert(topicPtr); 175| 130k| if (!inserted) { ------------------ | Branch (175:13): [True: 0, False: 130k] ------------------ 176| 0| return nullptr; 177| 0| } 178| 130k| topicPtr->insert(s); 179| | 180| | /* Success */ 181| 130k| return topicPtr; 182| 130k| } _ZN3uWS9TopicTreeINS_16TopicTreeMessageENS_19TopicTreeBigMessageEE24checkIteratingSubscriberEPNS_10SubscriberE: 104| 131k| void checkIteratingSubscriber(Subscriber *s) { 105| | /* Notify user that they are doing something wrong here */ 106| 131k| if (iteratingSubscriber == s) { ------------------ | Branch (106:13): [True: 0, False: 131k] ------------------ 107| 0| std::cerr << "Error: WebSocket must not subscribe or unsubscribe to topics while iterating its topics!" << std::endl; 108| 0| std::terminate(); 109| 0| } 110| 131k| } _ZN3uWS9TopicTreeINS_16TopicTreeMessageENS_19TopicTreeBigMessageEE11lookupTopicENSt3__117basic_string_viewIcNS4_11char_traitsIcEEEE: 152| 131k| Topic *lookupTopic(std::string_view topic) { 153| 131k| auto it = topics.find(topic); 154| 131k| if (it == topics.end()) { ------------------ | Branch (154:13): [True: 28.1k, False: 103k] ------------------ 155| 28.1k| return nullptr; 156| 28.1k| } 157| 103k| return it->second.get(); 158| 131k| } _ZN3uWS5TopicC2ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE: 40| 27.1k| Topic(std::string_view topic) : name(topic) { 41| | 42| 27.1k| } _ZN3uWS9TopicTreeINS_16TopicTreeMessageENS_19TopicTreeBigMessageEE7publishEPNS_10SubscriberENSt3__117basic_string_viewIcNS6_11char_traitsIcEEEEOS1_: 304| 28.6k| bool publish(Subscriber *sender, std::string_view topic, T &&message) { 305| | /* Do we even have this topic? */ 306| 28.6k| auto it = topics.find(topic); 307| 28.6k| if (it == topics.end()) { ------------------ | Branch (307:13): [True: 12.0k, False: 16.5k] ------------------ 308| 12.0k| return false; 309| 12.0k| } 310| | 311| | /* If we have more than 65k messages we need to drain every socket. */ 312| 16.5k| if (outgoingMessages.size() == UINT16_MAX) { ------------------ | Branch (312:13): [True: 0, False: 16.5k] ------------------ 313| | /* If there is a socket that is currently corked, this will be ugly as all sockets will drain 314| | * to their own backpressure */ 315| 0| drain(); 316| 0| } 317| | 318| | /* If nobody references this message, don't buffer it */ 319| 16.5k| bool referencedMessage = false; 320| | 321| | /* For all subscribers in topic */ 322| 65.0k| for (Subscriber *s : *it->second) { ------------------ | Branch (322:28): [True: 65.0k, False: 16.5k] ------------------ 323| | 324| | /* If we are sender then ignore us */ 325| 65.0k| if (sender != s) { ------------------ | Branch (325:17): [True: 48.5k, False: 16.5k] ------------------ 326| | 327| | /* At least one subscriber wants this message */ 328| 48.5k| referencedMessage = true; 329| | 330| | /* If we already have too many outgoing messages on this subscriber, drain it now */ 331| 48.5k| if (s->numMessageIndices == 32) { ------------------ | Branch (331:21): [True: 705, False: 47.8k] ------------------ 332| | /* This one does not need to check needsDrainage here but still does. */ 333| 705| drain(s); 334| 705| } 335| | 336| | /* Finally we can continue */ 337| 48.5k| s->messageIndices[s->numMessageIndices++] = (uint16_t)outgoingMessages.size(); 338| | /* First message adds subscriber to list of drainable subscribers */ 339| 48.5k| if (s->numMessageIndices == 1) { ------------------ | Branch (339:21): [True: 9.18k, False: 39.3k] ------------------ 340| | /* Insert us in the head of drainable subscribers */ 341| 9.18k| s->next = drainableSubscribers; 342| 9.18k| s->prev = nullptr; 343| 9.18k| if (s->next) { ------------------ | Branch (343:25): [True: 5.40k, False: 3.78k] ------------------ 344| 5.40k| s->next->prev = s; 345| 5.40k| } 346| 9.18k| drainableSubscribers = s; 347| 9.18k| } 348| 48.5k| } 349| 65.0k| } 350| | 351| | /* Push this message and return with success */ 352| 16.5k| if (referencedMessage) { ------------------ | Branch (352:13): [True: 15.9k, False: 629] ------------------ 353| 15.9k| outgoingMessages.emplace_back(message); 354| 15.9k| } 355| | 356| | /* Success if someone wants it */ 357| 16.5k| return referencedMessage; 358| 28.6k| } _ZN3uWS9TopicTreeINS_16TopicTreeMessageENS_19TopicTreeBigMessageEE11unsubscribeEPNS_10SubscriberENSt3__117basic_string_viewIcNS6_11char_traitsIcEEEE: 185| 1.01k| std::tuple unsubscribe(Subscriber *s, std::string_view topic) { 186| | /* Notify user that they are doing something wrong here */ 187| 1.01k| checkIteratingSubscriber(s); 188| | 189| | /* Lookup topic */ 190| 1.01k| Topic *topicPtr = lookupTopic(topic); 191| 1.01k| if (!topicPtr) { ------------------ | Branch (191:13): [True: 1.01k, False: 0] ------------------ 192| | /* If the topic doesn't exist we are assumed to still be subscribers of something */ 193| 1.01k| return {false, false, -1}; 194| 1.01k| } 195| | 196| | /* Erase from our list first */ 197| 0| if (s->topics.erase(topicPtr) == 0) { ------------------ | Branch (197:13): [True: 0, False: 0] ------------------ 198| 0| return {false, false, -1}; 199| 0| } 200| | 201| | /* Remove us from topic */ 202| 0| topicPtr->erase(s); 203| | 204| 0| int newCount = topicPtr->size(); 205| | 206| | /* If there is no subscriber to this topic, remove it */ 207| 0| if (!topicPtr->size()) { ------------------ | Branch (207:13): [True: 0, False: 0] ------------------ 208| | /* Unique_ptr deletes the topic */ 209| 0| topics.erase(topic); 210| 0| } 211| | 212| | /* If we don't hold any topics we are to be freed altogether */ 213| 0| return {true, s->topics.size() == 0, newCount}; 214| 0| } _ZN3uWS5utils6u64toaEmPc: 46| 7.55k|inline int u64toa(uint64_t value, char *dst) { 47| 7.55k| char temp[20]; 48| 7.55k| char *p = temp; 49| 15.1k| do { 50| 15.1k| *p++ = (char) ((value % 10) + '0'); 51| 15.1k| value /= 10; 52| 15.1k| } while (value > 0); ------------------ | Branch (52:14): [True: 7.55k, False: 7.55k] ------------------ 53| | 54| 7.55k| int ret = (int) (p - temp); 55| | 56| 15.1k| do { 57| 15.1k| *dst++ = *--p; 58| 15.1k| } while (p != temp); ------------------ | Branch (58:14): [True: 7.55k, False: 7.55k] ------------------ 59| | 60| 7.55k| return ret; 61| 7.55k|} _ZN3uWS9WebSocketILb0ELb1EiE4sendENSt3__117basic_string_viewIcNS2_11char_traitsIcEEEENS_6OpCodeEbb: 92| 34.2k| SendStatus send(std::string_view message, OpCode opCode = OpCode::BINARY, bool compress = false, bool fin = true) { 93| 34.2k| WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, 94| 34.2k| (us_socket_context_t *) us_socket_context(SSL, (us_socket_t *) this) 95| 34.2k| ); 96| | 97| | /* Skip sending and report success if we are over the limit of maxBackpressure */ 98| 34.2k| if (webSocketContextData->maxBackpressure && webSocketContextData->maxBackpressure < getBufferedAmount()) { ------------------ | Branch (98:13): [True: 34.2k, False: 0] | Branch (98:54): [True: 0, False: 34.2k] ------------------ 99| | /* Also defer a close if we should */ 100| 0| if (webSocketContextData->closeOnBackpressureLimit) { ------------------ | Branch (100:17): [True: 0, False: 0] ------------------ 101| 0| us_socket_shutdown_read(SSL, (us_socket_t *) this); 102| 0| } 103| | 104| | /* It is okay to call send again from within this callback since we immediately return with DROPPED afterwards */ 105| 0| if (webSocketContextData->droppedHandler) { ------------------ | Branch (105:17): [True: 0, False: 0] ------------------ 106| 0| webSocketContextData->droppedHandler(this, message, opCode); 107| 0| } 108| | 109| 0| return DROPPED; 110| 0| } 111| | 112| | /* If we are subscribers and have messages to drain we need to drain them here to stay synced */ 113| 34.2k| WebSocketData *webSocketData = (WebSocketData *) Super::getAsyncSocketData(); 114| | 115| | /* Special path for long sends of non-compressed, non-SSL messages */ 116| 34.2k| if (message.length() >= 16 * 1024 && !compress && !SSL && !webSocketData->subscriber && getBufferedAmount() == 0 && Super::getLoopData()->corkOffset == 0) { ------------------ | Branch (116:13): [True: 0, False: 34.2k] | Branch (116:46): [True: 0, False: 0] | Branch (116:59): [Folded - Ignored] | Branch (116:67): [True: 0, False: 0] | Branch (116:97): [True: 0, False: 0] | Branch (116:125): [True: 0, False: 0] ------------------ 117| 0| char header[10]; 118| 0| int header_length = (int) protocol::formatMessage(header, nullptr, 0, opCode, message.length(), compress, fin); 119| 0| int written = us_socket_write2(0, (struct us_socket_t *)this, header, header_length, message.data(), (int) message.length()); 120| | 121| 0| if (written != header_length + (int) message.length()) { ------------------ | Branch (121:17): [True: 0, False: 0] ------------------ 122| | /* Buffer up backpressure */ 123| 0| if (written > header_length) { ------------------ | Branch (123:21): [True: 0, False: 0] ------------------ 124| 0| webSocketData->buffer.append(message.data() + written - header_length, message.length() - (size_t) (written - header_length)); 125| 0| } else { 126| 0| webSocketData->buffer.append(header + written, (size_t) header_length - (size_t) written); 127| 0| webSocketData->buffer.append(message.data(), message.length()); 128| 0| } 129| | /* We cannot still be corked if we have backpressure. 130| | * We also cannot uncork normally since it will re-write the already buffered 131| | * up backpressure again. */ 132| 0| Super::uncorkWithoutSending(); 133| 0| return BACKPRESSURE; 134| 0| } 135| 34.2k| } else { 136| | 137| 34.2k| if (webSocketData->subscriber) { ------------------ | Branch (137:17): [True: 34.2k, False: 0] ------------------ 138| | /* This will call back into us, send. */ 139| 34.2k| webSocketContextData->topicTree->drain(webSocketData->subscriber); 140| 34.2k| } 141| | 142| | /* Transform the message to compressed domain if requested */ 143| 34.2k| if (compress) { ------------------ | Branch (143:17): [True: 34.2k, False: 0] ------------------ 144| 34.2k| WebSocketData *webSocketData = (WebSocketData *) Super::getAsyncSocketData(); 145| | 146| | /* Check and correct the compress hint. It is never valid to compress 0 bytes */ 147| 34.2k| if (message.length() && opCode < 3 && webSocketData->compressionStatus == WebSocketData::ENABLED) { ------------------ | Branch (147:21): [True: 34.2k, False: 0] | Branch (147:41): [True: 34.2k, False: 0] | Branch (147:55): [True: 289, False: 33.9k] ------------------ 148| 289| LoopData *loopData = Super::getLoopData(); 149| | /* Compress using either shared or dedicated deflationStream */ 150| 289| if (webSocketData->deflationStream) { ------------------ | Branch (150:25): [True: 101, False: 188] ------------------ 151| 101| message = webSocketData->deflationStream->deflate(loopData->zlibContext, message, false); 152| 188| } else { 153| 188| message = loopData->deflationStream->deflate(loopData->zlibContext, message, true); 154| 188| } 155| 33.9k| } else { 156| 33.9k| compress = false; 157| 33.9k| } 158| 34.2k| } 159| | 160| | /* Get size, allocate size, write if needed */ 161| 34.2k| size_t messageFrameSize = protocol::messageFrameSize(message.length()); 162| 34.2k| auto [sendBuffer, sendBufferAttribute] = Super::getSendBuffer(messageFrameSize); 163| 34.2k| protocol::formatMessage(sendBuffer, message.data(), message.length(), opCode, message.length(), compress, fin); 164| | 165| | /* Depending on size of message we have different paths */ 166| 34.2k| if (sendBufferAttribute == SendBufferAttribute::NEEDS_DRAIN) { ------------------ | Branch (166:17): [True: 31.8k, False: 2.41k] ------------------ 167| | /* This is a drain */ 168| 31.8k| auto[written, failed] = Super::write(nullptr, 0); 169| 31.8k| if (failed) { ------------------ | Branch (169:21): [True: 30.5k, False: 1.33k] ------------------ 170| | /* Return false for failure, skipping to reset the timeout below */ 171| 30.5k| return BACKPRESSURE; 172| 30.5k| } 173| 31.8k| } else if (sendBufferAttribute == SendBufferAttribute::NEEDS_UNCORK) { ------------------ | Branch (173:24): [True: 0, False: 2.41k] ------------------ 174| | /* Uncork if we came here uncorked */ 175| 0| auto [written, failed] = Super::uncork(); 176| 0| if (failed) { ------------------ | Branch (176:21): [True: 0, False: 0] ------------------ 177| 0| return BACKPRESSURE; 178| 0| } 179| 0| } 180| | 181| 34.2k| } 182| | 183| | /* Every successful send resets the timeout */ 184| 3.74k| if (webSocketContextData->resetIdleTimeoutOnSend) { ------------------ | Branch (184:13): [True: 0, False: 3.74k] ------------------ 185| 0| Super::timeout(webSocketContextData->idleTimeoutComponents.first); 186| 0| WebSocketData *webSocketData = (WebSocketData *) Super::getAsyncSocketData(); 187| 0| webSocketData->hasTimedOut = false; 188| 0| } 189| | 190| | /* Return success */ 191| 3.74k| return SUCCESS; 192| 34.2k| } EpollEchoServer.cpp:_ZN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataE3endEiNSt3__117basic_string_viewIcNS3_11char_traitsIcEEEE: 196| 6.58k| void end(int code = 0, std::string_view message = {}) { 197| | /* Check if we already called this one */ 198| 6.58k| WebSocketData *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) this); 199| 6.58k| if (webSocketData->isShuttingDown) { ------------------ | Branch (199:13): [True: 0, False: 6.58k] ------------------ 200| 0| return; 201| 0| } 202| | 203| | /* We postpone any FIN sending to either drainage or uncorking */ 204| 6.58k| webSocketData->isShuttingDown = true; 205| | 206| | /* Format and send the close frame */ 207| 6.58k| static const int MAX_CLOSE_PAYLOAD = 123; 208| 6.58k| size_t length = std::min(MAX_CLOSE_PAYLOAD, message.length()); 209| 6.58k| char closePayload[MAX_CLOSE_PAYLOAD + 2]; 210| 6.58k| size_t closePayloadLength = protocol::formatClosePayload(closePayload, (uint16_t) code, message.data(), length); 211| 6.58k| bool ok = send(std::string_view(closePayload, closePayloadLength), OpCode::CLOSE); 212| | 213| | /* FIN if we are ok and not corked */ 214| 6.58k| if (!this->isCorked()) { ------------------ | Branch (214:13): [True: 1.78k, False: 4.79k] ------------------ 215| 1.78k| if (ok) { ------------------ | Branch (215:17): [True: 1.00k, False: 786] ------------------ 216| | /* If we are not corked, and we just sent off everything, we need to FIN right here. 217| | * In all other cases, we need to fin either if uncork was successful, or when drainage is complete. */ 218| 1.00k| this->shutdown(); 219| 1.00k| } 220| 1.78k| } 221| | 222| 6.58k| WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, 223| 6.58k| (us_socket_context_t *) us_socket_context(SSL, (us_socket_t *) this) 224| 6.58k| ); 225| | 226| | /* Set shorter timeout (use ping-timeout) to avoid long hanging sockets after end() on broken connections */ 227| 6.58k| Super::timeout(webSocketContextData->idleTimeoutComponents.second); 228| | 229| | /* At this point we iterate all currently held subscriptions and emit an event for all of them */ 230| 6.58k| if (webSocketData->subscriber && webSocketContextData->subscriptionHandler) { ------------------ | Branch (230:13): [True: 480, False: 6.10k] | Branch (230:42): [True: 0, False: 480] ------------------ 231| 0| for (Topic *t : webSocketData->subscriber->topics) { ------------------ | Branch (231:27): [True: 0, False: 0] ------------------ 232| 0| webSocketContextData->subscriptionHandler(this, t->name, (int) t->size() - 1, (int) t->size()); 233| 0| } 234| 0| } 235| | 236| | /* Make sure to unsubscribe from any pub/sub node at exit */ 237| 6.58k| webSocketContextData->topicTree->freeSubscriber(webSocketData->subscriber); 238| 6.58k| webSocketData->subscriber = nullptr; 239| | 240| | /* Emit close event */ 241| 6.58k| if (webSocketContextData->closeHandler) { ------------------ | Branch (241:13): [True: 6.58k, False: 0] ------------------ 242| 6.58k| webSocketContextData->closeHandler(this, code, message); 243| 6.58k| } 244| 6.58k| } EpollEchoServer.cpp:_ZN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataE4sendENSt3__117basic_string_viewIcNS3_11char_traitsIcEEEENS_6OpCodeEbb: 92| 28.2k| SendStatus send(std::string_view message, OpCode opCode = OpCode::BINARY, bool compress = false, bool fin = true) { 93| 28.2k| WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, 94| 28.2k| (us_socket_context_t *) us_socket_context(SSL, (us_socket_t *) this) 95| 28.2k| ); 96| | 97| | /* Skip sending and report success if we are over the limit of maxBackpressure */ 98| 28.2k| if (webSocketContextData->maxBackpressure && webSocketContextData->maxBackpressure < getBufferedAmount()) { ------------------ | Branch (98:13): [True: 28.2k, False: 0] | Branch (98:54): [True: 0, False: 28.2k] ------------------ 99| | /* Also defer a close if we should */ 100| 0| if (webSocketContextData->closeOnBackpressureLimit) { ------------------ | Branch (100:17): [True: 0, False: 0] ------------------ 101| 0| us_socket_shutdown_read(SSL, (us_socket_t *) this); 102| 0| } 103| | 104| | /* It is okay to call send again from within this callback since we immediately return with DROPPED afterwards */ 105| 0| if (webSocketContextData->droppedHandler) { ------------------ | Branch (105:17): [True: 0, False: 0] ------------------ 106| 0| webSocketContextData->droppedHandler(this, message, opCode); 107| 0| } 108| | 109| 0| return DROPPED; 110| 0| } 111| | 112| | /* If we are subscribers and have messages to drain we need to drain them here to stay synced */ 113| 28.2k| WebSocketData *webSocketData = (WebSocketData *) Super::getAsyncSocketData(); 114| | 115| | /* Special path for long sends of non-compressed, non-SSL messages */ 116| 28.2k| if (message.length() >= 16 * 1024 && !compress && !SSL && !webSocketData->subscriber && getBufferedAmount() == 0 && Super::getLoopData()->corkOffset == 0) { ------------------ | Branch (116:13): [True: 0, False: 28.2k] | Branch (116:46): [True: 0, False: 0] | Branch (116:59): [Folded - Ignored] | Branch (116:67): [True: 0, False: 0] | Branch (116:97): [True: 0, False: 0] | Branch (116:125): [True: 0, False: 0] ------------------ 117| 0| char header[10]; 118| 0| int header_length = (int) protocol::formatMessage(header, nullptr, 0, opCode, message.length(), compress, fin); 119| 0| int written = us_socket_write2(0, (struct us_socket_t *)this, header, header_length, message.data(), (int) message.length()); 120| | 121| 0| if (written != header_length + (int) message.length()) { ------------------ | Branch (121:17): [True: 0, False: 0] ------------------ 122| | /* Buffer up backpressure */ 123| 0| if (written > header_length) { ------------------ | Branch (123:21): [True: 0, False: 0] ------------------ 124| 0| webSocketData->buffer.append(message.data() + written - header_length, message.length() - (size_t) (written - header_length)); 125| 0| } else { 126| 0| webSocketData->buffer.append(header + written, (size_t) header_length - (size_t) written); 127| 0| webSocketData->buffer.append(message.data(), message.length()); 128| 0| } 129| | /* We cannot still be corked if we have backpressure. 130| | * We also cannot uncork normally since it will re-write the already buffered 131| | * up backpressure again. */ 132| 0| Super::uncorkWithoutSending(); 133| 0| return BACKPRESSURE; 134| 0| } 135| 28.2k| } else { 136| | 137| 28.2k| if (webSocketData->subscriber) { ------------------ | Branch (137:17): [True: 4.42k, False: 23.8k] ------------------ 138| | /* This will call back into us, send. */ 139| 4.42k| webSocketContextData->topicTree->drain(webSocketData->subscriber); 140| 4.42k| } 141| | 142| | /* Transform the message to compressed domain if requested */ 143| 28.2k| if (compress) { ------------------ | Branch (143:17): [True: 8.81k, False: 19.4k] ------------------ 144| 8.81k| WebSocketData *webSocketData = (WebSocketData *) Super::getAsyncSocketData(); 145| | 146| | /* Check and correct the compress hint. It is never valid to compress 0 bytes */ 147| 8.81k| if (message.length() && opCode < 3 && webSocketData->compressionStatus == WebSocketData::ENABLED) { ------------------ | Branch (147:21): [True: 6.74k, False: 2.06k] | Branch (147:41): [True: 6.74k, False: 0] | Branch (147:55): [True: 3.05k, False: 3.69k] ------------------ 148| 3.05k| LoopData *loopData = Super::getLoopData(); 149| | /* Compress using either shared or dedicated deflationStream */ 150| 3.05k| if (webSocketData->deflationStream) { ------------------ | Branch (150:25): [True: 1.34k, False: 1.71k] ------------------ 151| 1.34k| message = webSocketData->deflationStream->deflate(loopData->zlibContext, message, false); 152| 1.71k| } else { 153| 1.71k| message = loopData->deflationStream->deflate(loopData->zlibContext, message, true); 154| 1.71k| } 155| 5.75k| } else { 156| 5.75k| compress = false; 157| 5.75k| } 158| 8.81k| } 159| | 160| | /* Get size, allocate size, write if needed */ 161| 28.2k| size_t messageFrameSize = protocol::messageFrameSize(message.length()); 162| 28.2k| auto [sendBuffer, sendBufferAttribute] = Super::getSendBuffer(messageFrameSize); 163| 28.2k| protocol::formatMessage(sendBuffer, message.data(), message.length(), opCode, message.length(), compress, fin); 164| | 165| | /* Depending on size of message we have different paths */ 166| 28.2k| if (sendBufferAttribute == SendBufferAttribute::NEEDS_DRAIN) { ------------------ | Branch (166:17): [True: 19.5k, False: 8.71k] ------------------ 167| | /* This is a drain */ 168| 19.5k| auto[written, failed] = Super::write(nullptr, 0); 169| 19.5k| if (failed) { ------------------ | Branch (169:21): [True: 17.4k, False: 2.13k] ------------------ 170| | /* Return false for failure, skipping to reset the timeout below */ 171| 17.4k| return BACKPRESSURE; 172| 17.4k| } 173| 19.5k| } else if (sendBufferAttribute == SendBufferAttribute::NEEDS_UNCORK) { ------------------ | Branch (173:24): [True: 1.80k, False: 6.91k] ------------------ 174| | /* Uncork if we came here uncorked */ 175| 1.80k| auto [written, failed] = Super::uncork(); 176| 1.80k| if (failed) { ------------------ | Branch (176:21): [True: 893, False: 910] ------------------ 177| 893| return BACKPRESSURE; 178| 893| } 179| 1.80k| } 180| | 181| 28.2k| } 182| | 183| | /* Every successful send resets the timeout */ 184| 9.96k| if (webSocketContextData->resetIdleTimeoutOnSend) { ------------------ | Branch (184:13): [True: 0, False: 9.96k] ------------------ 185| 0| Super::timeout(webSocketContextData->idleTimeoutComponents.first); 186| 0| WebSocketData *webSocketData = (WebSocketData *) Super::getAsyncSocketData(); 187| 0| webSocketData->hasTimedOut = false; 188| 0| } 189| | 190| | /* Return success */ 191| 9.96k| return SUCCESS; 192| 28.2k| } EpollEchoServer.cpp:_ZN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataE11getUserDataEv: 44| 403k| USERDATA *getUserData() { 45| 403k| WebSocketData *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) this); 46| | /* We just have it overallocated by sizeof type */ 47| 403k| return (USERDATA *) (webSocketData + 1); 48| 403k| } EpollEchoServer.cpp:_ZN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataE4initEbNS_15CompressOptionsEONS_12BackPressureE: 37| 164k| void *init(bool perMessageDeflate, CompressOptions compressOptions, BackPressure &&backpressure) { 38| 164k| new (us_socket_ext(SSL, (us_socket_t *) this)) WebSocketData(perMessageDeflate, compressOptions, std::move(backpressure)); 39| 164k| return this; 40| 164k| } EpollEchoServer.cpp:_ZN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataE9subscribeENSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEb: 264| 130k| bool subscribe(std::string_view topic, bool = false) { 265| 130k| WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, 266| 130k| (us_socket_context_t *) us_socket_context(SSL, (us_socket_t *) this) 267| 130k| ); 268| | 269| | /* Make us a subscriber if we aren't yet */ 270| 130k| WebSocketData *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) this); 271| 130k| if (!webSocketData->subscriber) { ------------------ | Branch (271:13): [True: 130k, False: 0] ------------------ 272| 130k| webSocketData->subscriber = webSocketContextData->topicTree->createSubscriber(); 273| 130k| webSocketData->subscriber->user = this; 274| 130k| } 275| | 276| | /* Cannot return numSubscribers as this is only for this particular websocket context */ 277| 130k| Topic *topicOrNull = webSocketContextData->topicTree->subscribe(webSocketData->subscriber, topic); 278| 130k| if (topicOrNull && webSocketContextData->subscriptionHandler) { ------------------ | Branch (278:13): [True: 130k, False: 0] | Branch (278:28): [True: 0, False: 130k] ------------------ 279| | /* Emit this socket, the topic, new count, old count */ 280| 0| webSocketContextData->subscriptionHandler(this, topic, (int) topicOrNull->size(), (int) topicOrNull->size() - 1); 281| 0| } 282| | 283| | /* Subscribe always succeeds */ 284| 130k| return true; 285| 130k| } EpollEchoServer.cpp:_ZN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataE5closeEv: 58| 131k| us_socket_t *close() { 59| 131k| if (us_socket_is_closed(SSL, (us_socket_t *) this)) { ------------------ | Branch (59:13): [True: 129k, False: 1.03k] ------------------ 60| 129k| return nullptr; 61| 129k| } 62| 1.03k| WebSocketData *webSocketData = (WebSocketData *) Super::getAsyncSocketData(); 63| 1.03k| if (webSocketData->isShuttingDown) { ------------------ | Branch (63:13): [True: 480, False: 553] ------------------ 64| 480| return nullptr; 65| 480| } 66| | 67| 553| return us_socket_close(SSL, (us_socket_t *) this, 0, nullptr); 68| 1.03k| } EpollEchoServer.cpp:_ZN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataE7publishENSt3__117basic_string_viewIcNS3_11char_traitsIcEEEES7_NS_6OpCodeEb: 354| 28.6k| bool publish(std::string_view topic, std::string_view message, OpCode opCode = OpCode::TEXT, bool compress = false) { 355| 28.6k| WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, 356| 28.6k| (us_socket_context_t *) us_socket_context(SSL, (us_socket_t *) this) 357| 28.6k| ); 358| | 359| | /* We cannot be a subscriber of this topic if we are not a subscriber of anything */ 360| 28.6k| WebSocketData *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) this); 361| 28.6k| if (!webSocketData->subscriber) { ------------------ | Branch (361:13): [True: 0, False: 28.6k] ------------------ 362| | /* Failure, but still do return the number of subscribers */ 363| 0| return false; 364| 0| } 365| | 366| | /* Publish as sender, does not receive its own messages even if subscribed to relevant topics */ 367| 28.6k| if (message.length() >= LoopData::CORK_BUFFER_SIZE) { ------------------ | Branch (367:13): [True: 0, False: 28.6k] ------------------ 368| 0| return webSocketContextData->topicTree->publishBig(webSocketData->subscriber, topic, {message, opCode, compress}, [](Subscriber *s, TopicTreeBigMessage &message) { 369| 0| auto *ws = (WebSocket *) s->user; 370| | 371| 0| ws->send(message.message, (OpCode)message.opCode, message.compress); 372| 0| }); 373| 28.6k| } else { 374| 28.6k| return webSocketContextData->topicTree->publish(webSocketData->subscriber, topic, {std::string(message), opCode, compress}); 375| 28.6k| } 376| 28.6k| } EpollEchoServer.cpp:_ZN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataE11unsubscribeENSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEb: 288| 1.01k| bool unsubscribe(std::string_view topic, bool = false) { 289| 1.01k| WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, 290| 1.01k| (us_socket_context_t *) us_socket_context(SSL, (us_socket_t *) this) 291| 1.01k| ); 292| | 293| 1.01k| WebSocketData *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) this); 294| | 295| 1.01k| if (!webSocketData->subscriber) { return false; } ------------------ | Branch (295:13): [True: 0, False: 1.01k] ------------------ 296| | 297| | /* Cannot return numSubscribers as this is only for this particular websocket context */ 298| 1.01k| auto [ok, last, newCount] = webSocketContextData->topicTree->unsubscribe(webSocketData->subscriber, topic); 299| | /* Emit subscription event if last */ 300| 1.01k| if (ok && webSocketContextData->subscriptionHandler) { ------------------ | Branch (300:13): [True: 0, False: 1.01k] | Branch (300:19): [True: 0, False: 0] ------------------ 301| 0| webSocketContextData->subscriptionHandler(this, topic, newCount, newCount + 1); 302| 0| } 303| | 304| | /* Leave us as subscribers even if we subscribe to nothing (last unsubscribed topic might miss its message otherwise) */ 305| | 306| 1.01k| return ok; 307| 1.01k| } EpollEchoServer.cpp:_ZN3uWS16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataE6createEPNS_4LoopEP19us_socket_context_tPNS_9TopicTreeINS_16TopicTreeMessageENS_19TopicTreeBigMessageEEE: 420| 11.6k| static WebSocketContext *create(Loop */*loop*/, us_socket_context_t *parentSocketContext, TopicTree *topicTree) { 421| 11.6k| WebSocketContext *webSocketContext = (WebSocketContext *) us_create_child_socket_context(SSL, parentSocketContext, sizeof(WebSocketContextData)); 422| 11.6k| if (!webSocketContext) { ------------------ | Branch (422:13): [True: 0, False: 11.6k] ------------------ 423| 0| return nullptr; 424| 0| } 425| | 426| | /* Init socket context data */ 427| 11.6k| new ((WebSocketContextData *) us_socket_context_ext(SSL, (us_socket_context_t *)webSocketContext)) WebSocketContextData(topicTree); 428| 11.6k| return webSocketContext->init(); 429| 11.6k| } EpollEchoServer.cpp:_ZN3uWS16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataE4initEv: 248| 11.6k| WebSocketContext *init() { 249| | /* Adopting a socket does not trigger open event. 250| | * We arreive as WebSocket with timeout set and 251| | * any backpressure from HTTP state kept. */ 252| | 253| | /* Handle socket disconnections */ 254| 11.6k| us_socket_context_on_close(SSL, getSocketContext(), [](auto *s, int code, void *reason) { 255| | /* For whatever reason, if we already have emitted close event, do not emit it again */ 256| 11.6k| WebSocketData *webSocketData = (WebSocketData *) (us_socket_ext(SSL, s)); 257| 11.6k| if (!webSocketData->isShuttingDown) { 258| | /* Emit close event */ 259| 11.6k| auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); 260| | 261| | /* At this point we iterate all currently held subscriptions and emit an event for all of them */ 262| 11.6k| if (webSocketData->subscriber && webSocketContextData->subscriptionHandler) { 263| 11.6k| for (Topic *t : webSocketData->subscriber->topics) { 264| 11.6k| webSocketContextData->subscriptionHandler((WebSocket *) s, t->name, (int) t->size() - 1, (int) t->size()); 265| 11.6k| } 266| 11.6k| } 267| | 268| | /* Make sure to unsubscribe from any pub/sub node at exit */ 269| 11.6k| webSocketContextData->topicTree->freeSubscriber(webSocketData->subscriber); 270| 11.6k| webSocketData->subscriber = nullptr; 271| | 272| 11.6k| if (webSocketContextData->closeHandler) { 273| 11.6k| webSocketContextData->closeHandler((WebSocket *) s, 1006, {(char *) reason, (size_t) code}); 274| 11.6k| } 275| 11.6k| } 276| | 277| | /* Destruct in-placed data struct */ 278| 11.6k| webSocketData->~WebSocketData(); 279| | 280| 11.6k| return s; 281| 11.6k| }); 282| | 283| | /* Handle WebSocket data streams */ 284| 11.6k| us_socket_context_on_data(SSL, getSocketContext(), [](auto *s, char *data, int length) { 285| | 286| | /* We need the websocket data */ 287| 11.6k| WebSocketData *webSocketData = (WebSocketData *) (us_socket_ext(SSL, s)); 288| | 289| | /* When in websocket shutdown mode, we do not care for ANY message, whether responding close frame or not. 290| | * We only care for the TCP FIN really, not emitting any message after closing is key */ 291| 11.6k| if (webSocketData->isShuttingDown) { 292| 11.6k| return s; 293| 11.6k| } 294| | 295| 11.6k| auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); 296| 11.6k| auto *asyncSocket = (AsyncSocket *) s; 297| | 298| | /* Every time we get data and not in shutdown state we simply reset the timeout */ 299| 11.6k| asyncSocket->timeout(webSocketContextData->idleTimeoutComponents.first); 300| 11.6k| webSocketData->hasTimedOut = false; 301| | 302| | /* We always cork on data */ 303| 11.6k| asyncSocket->cork(); 304| | 305| | /* This parser has virtually no overhead */ 306| 11.6k| WebSocketProtocol>::consume(data, (unsigned int) length, (WebSocketState *) webSocketData, s); 307| | 308| | /* Uncorking a closed socekt is fine, in fact it is needed */ 309| 11.6k| asyncSocket->uncork(); 310| | 311| | /* If uncorking was successful and we are in shutdown state then send TCP FIN */ 312| 11.6k| if (asyncSocket->getBufferedAmount() == 0) { 313| | /* We can now be in shutdown state */ 314| 11.6k| if (webSocketData->isShuttingDown) { 315| | /* Shutting down a closed socket is handled by uSockets and just fine */ 316| 11.6k| asyncSocket->shutdown(); 317| 11.6k| } 318| 11.6k| } 319| | 320| 11.6k| return s; 321| 11.6k| }); 322| | 323| | /* Handle HTTP write out (note: SSL_read may trigger this spuriously, the app need to handle spurious calls) */ 324| 11.6k| us_socket_context_on_writable(SSL, getSocketContext(), [](auto *s) { 325| | 326| | /* NOTE: Are we called here corked? If so, the below write code is broken, since 327| | * we will have 0 as getBufferedAmount due to writing to cork buffer, then sending TCP FIN before 328| | * we actually uncorked and sent off things */ 329| | 330| | /* It makes sense to check for us_is_shut_down here and return if so, to avoid shutting down twice */ 331| 11.6k| if (us_socket_is_shut_down(SSL, (us_socket_t *) s)) { 332| 11.6k| return s; 333| 11.6k| } 334| | 335| 11.6k| AsyncSocket *asyncSocket = (AsyncSocket *) s; 336| 11.6k| WebSocketData *webSocketData = (WebSocketData *)(us_socket_ext(SSL, s)); 337| | 338| | /* We store old backpressure since it is unclear whether write drained anything, 339| | * however, in case of coming here with 0 backpressure we still need to emit drain event */ 340| 11.6k| unsigned int backpressure = asyncSocket->getBufferedAmount(); 341| | 342| | /* Drain as much as possible */ 343| 11.6k| asyncSocket->write(nullptr, 0); 344| | 345| | /* Behavior: if we actively drain backpressure, always reset timeout (even if we are in shutdown) */ 346| | /* Also reset timeout if we came here with 0 backpressure */ 347| 11.6k| if (!backpressure || backpressure > asyncSocket->getBufferedAmount()) { 348| 11.6k| auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); 349| 11.6k| asyncSocket->timeout(webSocketContextData->idleTimeoutComponents.first); 350| 11.6k| webSocketData->hasTimedOut = false; 351| 11.6k| } 352| | 353| | /* Are we in (WebSocket) shutdown mode? */ 354| 11.6k| if (webSocketData->isShuttingDown) { 355| | /* Check if we just now drained completely */ 356| 11.6k| if (asyncSocket->getBufferedAmount() == 0) { 357| | /* Now perform the actual TCP/TLS shutdown which was postponed due to backpressure */ 358| 11.6k| asyncSocket->shutdown(); 359| 11.6k| } 360| 11.6k| } else if (!backpressure || backpressure > asyncSocket->getBufferedAmount()) { 361| | /* Only call drain if we actually drained backpressure or if we came here with 0 backpressure */ 362| 11.6k| auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); 363| 11.6k| if (webSocketContextData->drainHandler) { 364| 11.6k| webSocketContextData->drainHandler((WebSocket *) s); 365| 11.6k| } 366| | /* No need to check for closed here as we leave the handler immediately*/ 367| 11.6k| } 368| | 369| 11.6k| return s; 370| 11.6k| }); 371| | 372| | /* Handle FIN, HTTP does not support half-closed sockets, so simply close */ 373| 11.6k| us_socket_context_on_end(SSL, getSocketContext(), [](auto *s) { 374| | 375| | /* If we get a fin, we just close I guess */ 376| 11.6k| us_socket_close(SSL, (us_socket_t *) s, 0, nullptr); 377| | 378| 11.6k| return s; 379| 11.6k| }); 380| | 381| 11.6k| us_socket_context_on_long_timeout(SSL, getSocketContext(), [](auto *s) { 382| 11.6k| ((WebSocket *) s)->end(1000, "please reconnect"); 383| | 384| 11.6k| return s; 385| 11.6k| }); 386| | 387| | /* Handle socket timeouts, simply close them so to not confuse client with FIN */ 388| 11.6k| us_socket_context_on_timeout(SSL, getSocketContext(), [](auto *s) { 389| | 390| 11.6k| auto *webSocketData = (WebSocketData *)(us_socket_ext(SSL, s)); 391| 11.6k| auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); 392| | 393| 11.6k| if (webSocketContextData->sendPingsAutomatically && !webSocketData->isShuttingDown && !webSocketData->hasTimedOut) { 394| 11.6k| webSocketData->hasTimedOut = true; 395| 11.6k| us_socket_timeout(SSL, s, webSocketContextData->idleTimeoutComponents.second); 396| | /* Send ping without being corked */ 397| 11.6k| ((AsyncSocket *) s)->write("\x89\x00", 2); 398| 11.6k| return s; 399| 11.6k| } 400| | 401| | /* Timeout is very simple; we just close it */ 402| | /* Warning: we happen to know forceClose will not use first parameter so pass nullptr here */ 403| 11.6k| forceClose(nullptr, s, ERR_WEBSOCKET_TIMEOUT); 404| | 405| 11.6k| return s; 406| 11.6k| }); 407| | 408| 11.6k| return this; 409| 11.6k| } EpollEchoServer.cpp:_ZZN3uWS16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataE4initEvENKUlPT_iPvE_clI11us_socket_tEEDaS4_iS5_: 254| 164k| us_socket_context_on_close(SSL, getSocketContext(), [](auto *s, int code, void *reason) { 255| | /* For whatever reason, if we already have emitted close event, do not emit it again */ 256| 164k| WebSocketData *webSocketData = (WebSocketData *) (us_socket_ext(SSL, s)); 257| 164k| if (!webSocketData->isShuttingDown) { ------------------ | Branch (257:17): [True: 157k, False: 6.58k] ------------------ 258| | /* Emit close event */ 259| 157k| auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); 260| | 261| | /* At this point we iterate all currently held subscriptions and emit an event for all of them */ 262| 157k| if (webSocketData->subscriber && webSocketContextData->subscriptionHandler) { ------------------ | Branch (262:21): [True: 129k, False: 27.7k] | Branch (262:50): [True: 0, False: 129k] ------------------ 263| 0| for (Topic *t : webSocketData->subscriber->topics) { ------------------ | Branch (263:35): [True: 0, False: 0] ------------------ 264| 0| webSocketContextData->subscriptionHandler((WebSocket *) s, t->name, (int) t->size() - 1, (int) t->size()); 265| 0| } 266| 0| } 267| | 268| | /* Make sure to unsubscribe from any pub/sub node at exit */ 269| 157k| webSocketContextData->topicTree->freeSubscriber(webSocketData->subscriber); 270| 157k| webSocketData->subscriber = nullptr; 271| | 272| 157k| if (webSocketContextData->closeHandler) { ------------------ | Branch (272:21): [True: 157k, False: 0] ------------------ 273| 157k| webSocketContextData->closeHandler((WebSocket *) s, 1006, {(char *) reason, (size_t) code}); 274| 157k| } 275| 157k| } 276| | 277| | /* Destruct in-placed data struct */ 278| 164k| webSocketData->~WebSocketData(); 279| | 280| 164k| return s; 281| 164k| }); EpollEchoServer.cpp:_ZZN3uWS16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataE4initEvENKUlPT_PciE_clI11us_socket_tEEDaS4_S5_i: 284| 45.7k| us_socket_context_on_data(SSL, getSocketContext(), [](auto *s, char *data, int length) { 285| | 286| | /* We need the websocket data */ 287| 45.7k| WebSocketData *webSocketData = (WebSocketData *) (us_socket_ext(SSL, s)); 288| | 289| | /* When in websocket shutdown mode, we do not care for ANY message, whether responding close frame or not. 290| | * We only care for the TCP FIN really, not emitting any message after closing is key */ 291| 45.7k| if (webSocketData->isShuttingDown) { ------------------ | Branch (291:17): [True: 382, False: 45.3k] ------------------ 292| 382| return s; 293| 382| } 294| | 295| 45.3k| auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); 296| 45.3k| auto *asyncSocket = (AsyncSocket *) s; 297| | 298| | /* Every time we get data and not in shutdown state we simply reset the timeout */ 299| 45.3k| asyncSocket->timeout(webSocketContextData->idleTimeoutComponents.first); 300| 45.3k| webSocketData->hasTimedOut = false; 301| | 302| | /* We always cork on data */ 303| 45.3k| asyncSocket->cork(); 304| | 305| | /* This parser has virtually no overhead */ 306| 45.3k| WebSocketProtocol>::consume(data, (unsigned int) length, (WebSocketState *) webSocketData, s); 307| | 308| | /* Uncorking a closed socekt is fine, in fact it is needed */ 309| 45.3k| asyncSocket->uncork(); 310| | 311| | /* If uncorking was successful and we are in shutdown state then send TCP FIN */ 312| 45.3k| if (asyncSocket->getBufferedAmount() == 0) { ------------------ | Branch (312:17): [True: 9.24k, False: 36.1k] ------------------ 313| | /* We can now be in shutdown state */ 314| 9.24k| if (webSocketData->isShuttingDown) { ------------------ | Branch (314:21): [True: 1.04k, False: 8.20k] ------------------ 315| | /* Shutting down a closed socket is handled by uSockets and just fine */ 316| 1.04k| asyncSocket->shutdown(); 317| 1.04k| } 318| 9.24k| } 319| | 320| 45.3k| return s; 321| 45.7k| }); EpollEchoServer.cpp:_ZN3uWS16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataE13setCompressedEPNS_14WebSocketStateILb1EEEPv: 44| 9.76k| static bool setCompressed(WebSocketState */*wState*/, void *s) { 45| 9.76k| WebSocketData *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) s); 46| | 47| 9.76k| if (webSocketData->compressionStatus == WebSocketData::CompressionStatus::ENABLED) { ------------------ | Branch (47:13): [True: 2.07k, False: 7.68k] ------------------ 48| 2.07k| webSocketData->compressionStatus = WebSocketData::CompressionStatus::COMPRESSED_FRAME; 49| 2.07k| return true; 50| 7.68k| } else { 51| 7.68k| return false; 52| 7.68k| } 53| 9.76k| } EpollEchoServer.cpp:_ZN3uWS16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataE10forceCloseEPNS_14WebSocketStateILb1EEEPvNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEE: 55| 28.1k| static void forceClose(WebSocketState */*wState*/, void *s, std::string_view reason = {}) { 56| 28.1k| us_socket_close(SSL, (us_socket_t *) s, (int) reason.length(), (void *) reason.data()); 57| 28.1k| } EpollEchoServer.cpp:_ZN3uWS16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataE19refusePayloadLengthEmPNS_14WebSocketStateILb1EEEPv: 241| 96.8k| static bool refusePayloadLength(uint64_t length, WebSocketState */*wState*/, void *s) { 242| 96.8k| auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); 243| | 244| | /* Return true for refuse, false for accept */ 245| 96.8k| return webSocketContextData->maxPayloadLength < length; 246| 96.8k| } EpollEchoServer.cpp:_ZN3uWS16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataE14handleFragmentEPcmjibPNS_14WebSocketStateILb1EEEPv: 60| 83.2k| static bool handleFragment(char *data, size_t length, unsigned int remainingBytes, int opCode, bool fin, WebSocketState *webSocketState, void *s) { 61| | /* WebSocketData and WebSocketContextData */ 62| 83.2k| WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); 63| 83.2k| WebSocketData *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) s); 64| | 65| | /* Is this a non-control frame? */ 66| 83.2k| if (opCode < 3) { ------------------ | Branch (66:13): [True: 59.6k, False: 23.6k] ------------------ 67| | /* Did we get everything in one go? */ 68| 59.6k| if (!remainingBytes && fin && !webSocketData->fragmentBuffer.length()) { ------------------ | Branch (68:17): [True: 51.7k, False: 7.85k] | Branch (68:36): [True: 41.7k, False: 10.0k] | Branch (68:43): [True: 37.9k, False: 3.82k] ------------------ 69| | 70| | /* Handle compressed frame */ 71| 37.9k| if (webSocketData->compressionStatus == WebSocketData::CompressionStatus::COMPRESSED_FRAME) { ------------------ | Branch (71:21): [True: 658, False: 37.2k] ------------------ 72| 658| webSocketData->compressionStatus = WebSocketData::CompressionStatus::ENABLED; 73| | 74| 658| LoopData *loopData = (LoopData *) us_loop_ext(us_socket_context_loop(SSL, us_socket_context(SSL, (us_socket_t *) s))); 75| | /* Decompress using shared or dedicated decompressor */ 76| 658| std::optional inflatedFrame; 77| 658| if (webSocketData->inflationStream) { ------------------ | Branch (77:29): [True: 0, False: 658] ------------------ 78| 0| inflatedFrame = webSocketData->inflationStream->inflate(loopData->zlibContext, {data, length}, webSocketContextData->maxPayloadLength, false); 79| 658| } else { 80| 658| inflatedFrame = loopData->inflationStream->inflate(loopData->zlibContext, {data, length}, webSocketContextData->maxPayloadLength, true); 81| 658| } 82| | 83| 658| if (!inflatedFrame.has_value()) { ------------------ | Branch (83:29): [True: 0, False: 658] ------------------ 84| 0| forceClose(webSocketState, s, ERR_TOO_BIG_MESSAGE_INFLATION); 85| 0| return true; 86| 658| } else { 87| 658| data = (char *) inflatedFrame->data(); 88| 658| length = inflatedFrame->length(); 89| 658| } 90| 658| } 91| | 92| | /* Check text messages for Utf-8 validity */ 93| 37.9k| if (opCode == 1 && !protocol::isValidUtf8((unsigned char *) data, length)) { ------------------ | Branch (93:21): [True: 31.7k, False: 6.19k] | Branch (93:36): [True: 2.76k, False: 28.9k] ------------------ 94| 2.76k| forceClose(webSocketState, s, ERR_INVALID_TEXT); 95| 2.76k| return true; 96| 2.76k| } 97| | 98| | /* Emit message event & break if we are closed or shut down when returning */ 99| 35.1k| if (webSocketContextData->messageHandler) { ------------------ | Branch (99:21): [True: 35.1k, False: 0] ------------------ 100| 35.1k| webSocketContextData->messageHandler((WebSocket *) s, std::string_view(data, length), (OpCode) opCode); 101| 35.1k| if (us_socket_is_closed(SSL, (us_socket_t *) s) || webSocketData->isShuttingDown) { ------------------ | Branch (101:25): [True: 358, False: 34.7k] | Branch (101:72): [True: 397, False: 34.3k] ------------------ 102| 755| return true; 103| 755| } 104| 35.1k| } 105| 35.1k| } else { 106| | /* Allocate fragment buffer up front first time */ 107| 21.7k| if (!webSocketData->fragmentBuffer.length()) { ------------------ | Branch (107:21): [True: 12.3k, False: 9.30k] ------------------ 108| 12.3k| webSocketData->fragmentBuffer.reserve(length + remainingBytes); 109| 12.3k| } 110| | /* Fragments forming a big message are not caught until appending them */ 111| 21.7k| if (refusePayloadLength(length + webSocketData->fragmentBuffer.length(), webSocketState, s)) { ------------------ | Branch (111:21): [True: 364, False: 21.3k] ------------------ 112| 364| forceClose(webSocketState, s, ERR_TOO_BIG_MESSAGE); 113| 364| return true; 114| 364| } 115| 21.3k| webSocketData->fragmentBuffer.append(data, length); 116| | 117| | /* Are we done now? */ 118| | // todo: what if we don't have any remaining bytes yet we are not fin? forceclose! 119| 21.3k| if (!remainingBytes && fin) { ------------------ | Branch (119:21): [True: 13.8k, False: 7.52k] | Branch (119:40): [True: 3.82k, False: 9.99k] ------------------ 120| | 121| | /* Handle compression */ 122| 3.82k| if (webSocketData->compressionStatus == WebSocketData::CompressionStatus::COMPRESSED_FRAME) { ------------------ | Branch (122:25): [True: 1.19k, False: 2.62k] ------------------ 123| 1.19k| webSocketData->compressionStatus = WebSocketData::CompressionStatus::ENABLED; 124| | 125| | /* 9 bytes of padding for libdeflate, 4 for zlib */ 126| 1.19k| webSocketData->fragmentBuffer.append("123456789"); 127| | 128| 1.19k| LoopData *loopData = (LoopData *) us_loop_ext( 129| 1.19k| us_socket_context_loop(SSL, 130| 1.19k| us_socket_context(SSL, (us_socket_t *) s) 131| 1.19k| ) 132| 1.19k| ); 133| | 134| | /* Decompress using shared or dedicated decompressor */ 135| 1.19k| std::optional inflatedFrame; 136| 1.19k| if (webSocketData->inflationStream) { ------------------ | Branch (136:33): [True: 0, False: 1.19k] ------------------ 137| 0| inflatedFrame = webSocketData->inflationStream->inflate(loopData->zlibContext, {webSocketData->fragmentBuffer.data(), webSocketData->fragmentBuffer.length() - 9}, webSocketContextData->maxPayloadLength, false); 138| 1.19k| } else { 139| 1.19k| inflatedFrame = loopData->inflationStream->inflate(loopData->zlibContext, {webSocketData->fragmentBuffer.data(), webSocketData->fragmentBuffer.length() - 9}, webSocketContextData->maxPayloadLength, true); 140| 1.19k| } 141| | 142| 1.19k| if (!inflatedFrame.has_value()) { ------------------ | Branch (142:33): [True: 0, False: 1.19k] ------------------ 143| 0| forceClose(webSocketState, s, ERR_TOO_BIG_MESSAGE_INFLATION); 144| 0| return true; 145| 1.19k| } else { 146| 1.19k| data = (char *) inflatedFrame->data(); 147| 1.19k| length = inflatedFrame->length(); 148| 1.19k| } 149| | 150| | 151| 2.62k| } else { 152| | // reset length and data ptrs 153| 2.62k| length = webSocketData->fragmentBuffer.length(); 154| 2.62k| data = webSocketData->fragmentBuffer.data(); 155| 2.62k| } 156| | 157| | /* Check text messages for Utf-8 validity */ 158| 3.82k| if (opCode == 1 && !protocol::isValidUtf8((unsigned char *) data, length)) { ------------------ | Branch (158:25): [True: 1.44k, False: 2.37k] | Branch (158:40): [True: 336, False: 1.11k] ------------------ 159| 336| forceClose(webSocketState, s, ERR_INVALID_TEXT); 160| 336| return true; 161| 336| } 162| | 163| | /* Emit message and check for shutdown or close */ 164| 3.48k| if (webSocketContextData->messageHandler) { ------------------ | Branch (164:25): [True: 3.48k, False: 0] ------------------ 165| 3.48k| webSocketContextData->messageHandler((WebSocket *) s, std::string_view(data, length), (OpCode) opCode); 166| 3.48k| if (us_socket_is_closed(SSL, (us_socket_t *) s) || webSocketData->isShuttingDown) { ------------------ | Branch (166:29): [True: 195, False: 3.28k] | Branch (166:76): [True: 196, False: 3.09k] ------------------ 167| 391| return true; 168| 391| } 169| 3.48k| } 170| | 171| | /* If we shutdown or closed, this will be taken care of elsewhere */ 172| 3.09k| webSocketData->fragmentBuffer.clear(); 173| 3.09k| } 174| 21.3k| } 175| 59.6k| } else { 176| | /* Control frames need the websocket to send pings, pongs and close */ 177| 23.6k| WebSocket *webSocket = (WebSocket *) s; 178| | 179| 23.6k| if (!remainingBytes && fin && !webSocketData->controlTipLength) { ------------------ | Branch (179:17): [True: 19.4k, False: 4.24k] | Branch (179:36): [True: 19.4k, False: 0] | Branch (179:43): [True: 15.6k, False: 3.77k] ------------------ 180| 15.6k| if (opCode == CLOSE) { ------------------ | Branch (180:21): [True: 2.84k, False: 12.7k] ------------------ 181| 2.84k| auto closeFrame = protocol::parseClosePayload(data, length); 182| 2.84k| webSocket->end(closeFrame.code, std::string_view(closeFrame.message, closeFrame.length)); 183| 2.84k| return true; 184| 12.7k| } else { 185| 12.7k| if (opCode == PING) { ------------------ | Branch (185:25): [True: 11.1k, False: 1.67k] ------------------ 186| 11.1k| webSocket->send(std::string_view(data, length), (OpCode) OpCode::PONG); 187| 11.1k| if (webSocketContextData->pingHandler) { ------------------ | Branch (187:29): [True: 11.1k, False: 0] ------------------ 188| 11.1k| webSocketContextData->pingHandler(webSocket, {data, length}); 189| 11.1k| if (us_socket_is_closed(SSL, (us_socket_t *) s) || webSocketData->isShuttingDown) { ------------------ | Branch (189:33): [True: 0, False: 11.1k] | Branch (189:80): [True: 0, False: 11.1k] ------------------ 190| 0| return true; 191| 0| } 192| 11.1k| } 193| 11.1k| } else if (opCode == PONG) { ------------------ | Branch (193:32): [True: 1.67k, False: 0] ------------------ 194| 1.67k| if (webSocketContextData->pongHandler) { ------------------ | Branch (194:29): [True: 1.67k, False: 0] ------------------ 195| 1.67k| webSocketContextData->pongHandler(webSocket, {data, length}); 196| 1.67k| if (us_socket_is_closed(SSL, (us_socket_t *) s) || webSocketData->isShuttingDown) { ------------------ | Branch (196:33): [True: 0, False: 1.67k] | Branch (196:80): [True: 0, False: 1.67k] ------------------ 197| 0| return true; 198| 0| } 199| 1.67k| } 200| 1.67k| } 201| 12.7k| } 202| 15.6k| } else { 203| | /* Here we never mind any size optimizations as we are in the worst possible path */ 204| 8.01k| webSocketData->fragmentBuffer.append(data, length); 205| 8.01k| webSocketData->controlTipLength += (unsigned int) length; 206| | 207| 8.01k| if (!remainingBytes && fin) { ------------------ | Branch (207:21): [True: 3.77k, False: 4.24k] | Branch (207:40): [True: 3.77k, False: 0] ------------------ 208| 3.77k| char *controlBuffer = (char *) webSocketData->fragmentBuffer.data() + webSocketData->fragmentBuffer.length() - webSocketData->controlTipLength; 209| 3.77k| if (opCode == CLOSE) { ------------------ | Branch (209:25): [True: 1.63k, False: 2.13k] ------------------ 210| 1.63k| protocol::CloseFrame closeFrame = protocol::parseClosePayload(controlBuffer, webSocketData->controlTipLength); 211| 1.63k| webSocket->end(closeFrame.code, std::string_view(closeFrame.message, closeFrame.length)); 212| 1.63k| return true; 213| 2.13k| } else { 214| 2.13k| if (opCode == PING) { ------------------ | Branch (214:29): [True: 245, False: 1.89k] ------------------ 215| 245| webSocket->send(std::string_view(controlBuffer, webSocketData->controlTipLength), (OpCode) OpCode::PONG); 216| 245| if (webSocketContextData->pingHandler) { ------------------ | Branch (216:33): [True: 245, False: 0] ------------------ 217| 245| webSocketContextData->pingHandler(webSocket, std::string_view(controlBuffer, webSocketData->controlTipLength)); 218| 245| if (us_socket_is_closed(SSL, (us_socket_t *) s) || webSocketData->isShuttingDown) { ------------------ | Branch (218:37): [True: 0, False: 245] | Branch (218:84): [True: 0, False: 245] ------------------ 219| 0| return true; 220| 0| } 221| 245| } 222| 1.89k| } else if (opCode == PONG) { ------------------ | Branch (222:36): [True: 1.89k, False: 0] ------------------ 223| 1.89k| if (webSocketContextData->pongHandler) { ------------------ | Branch (223:33): [True: 1.89k, False: 0] ------------------ 224| 1.89k| webSocketContextData->pongHandler(webSocket, std::string_view(controlBuffer, webSocketData->controlTipLength)); 225| 1.89k| if (us_socket_is_closed(SSL, (us_socket_t *) s) || webSocketData->isShuttingDown) { ------------------ | Branch (225:37): [True: 0, False: 1.89k] | Branch (225:84): [True: 0, False: 1.89k] ------------------ 226| 0| return true; 227| 0| } 228| 1.89k| } 229| 1.89k| } 230| 2.13k| } 231| | 232| | /* Same here, we do not care for any particular smart allocation scheme */ 233| 2.13k| webSocketData->fragmentBuffer.resize((unsigned int) webSocketData->fragmentBuffer.length() - webSocketData->controlTipLength); 234| 2.13k| webSocketData->controlTipLength = 0; 235| 2.13k| } 236| 8.01k| } 237| 23.6k| } 238| 74.1k| return false; 239| 83.2k| } EpollEchoServer.cpp:_ZZN3uWS16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataE4initEvENKUlPT_E_clI11us_socket_tEEDaS4_: 324| 31.5k| us_socket_context_on_writable(SSL, getSocketContext(), [](auto *s) { 325| | 326| | /* NOTE: Are we called here corked? If so, the below write code is broken, since 327| | * we will have 0 as getBufferedAmount due to writing to cork buffer, then sending TCP FIN before 328| | * we actually uncorked and sent off things */ 329| | 330| | /* It makes sense to check for us_is_shut_down here and return if so, to avoid shutting down twice */ 331| 31.5k| if (us_socket_is_shut_down(SSL, (us_socket_t *) s)) { ------------------ | Branch (331:17): [True: 0, False: 31.5k] ------------------ 332| 0| return s; 333| 0| } 334| | 335| 31.5k| AsyncSocket *asyncSocket = (AsyncSocket *) s; 336| 31.5k| WebSocketData *webSocketData = (WebSocketData *)(us_socket_ext(SSL, s)); 337| | 338| | /* We store old backpressure since it is unclear whether write drained anything, 339| | * however, in case of coming here with 0 backpressure we still need to emit drain event */ 340| 31.5k| unsigned int backpressure = asyncSocket->getBufferedAmount(); 341| | 342| | /* Drain as much as possible */ 343| 31.5k| asyncSocket->write(nullptr, 0); 344| | 345| | /* Behavior: if we actively drain backpressure, always reset timeout (even if we are in shutdown) */ 346| | /* Also reset timeout if we came here with 0 backpressure */ 347| 31.5k| if (!backpressure || backpressure > asyncSocket->getBufferedAmount()) { ------------------ | Branch (347:17): [True: 242, False: 31.2k] | Branch (347:34): [True: 25.0k, False: 6.22k] ------------------ 348| 25.2k| auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); 349| 25.2k| asyncSocket->timeout(webSocketContextData->idleTimeoutComponents.first); 350| 25.2k| webSocketData->hasTimedOut = false; 351| 25.2k| } 352| | 353| | /* Are we in (WebSocket) shutdown mode? */ 354| 31.5k| if (webSocketData->isShuttingDown) { ------------------ | Branch (354:17): [True: 977, False: 30.5k] ------------------ 355| | /* Check if we just now drained completely */ 356| 977| if (asyncSocket->getBufferedAmount() == 0) { ------------------ | Branch (356:21): [True: 201, False: 776] ------------------ 357| | /* Now perform the actual TCP/TLS shutdown which was postponed due to backpressure */ 358| 201| asyncSocket->shutdown(); 359| 201| } 360| 30.5k| } else if (!backpressure || backpressure > asyncSocket->getBufferedAmount()) { ------------------ | Branch (360:24): [True: 242, False: 30.2k] | Branch (360:41): [True: 24.5k, False: 5.70k] ------------------ 361| | /* Only call drain if we actually drained backpressure or if we came here with 0 backpressure */ 362| 24.8k| auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); 363| 24.8k| if (webSocketContextData->drainHandler) { ------------------ | Branch (363:21): [True: 24.8k, False: 0] ------------------ 364| 24.8k| webSocketContextData->drainHandler((WebSocket *) s); 365| 24.8k| } 366| | /* No need to check for closed here as we leave the handler immediately*/ 367| 24.8k| } 368| | 369| 31.5k| return s; 370| 31.5k| }); EpollEchoServer.cpp:_ZZN3uWS16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataE4initEvENKUlPT_E0_clI11us_socket_tEEDaS4_: 373| 2.63k| us_socket_context_on_end(SSL, getSocketContext(), [](auto *s) { 374| | 375| | /* If we get a fin, we just close I guess */ 376| 2.63k| us_socket_close(SSL, (us_socket_t *) s, 0, nullptr); 377| | 378| 2.63k| return s; 379| 2.63k| }); EpollEchoServer.cpp:_ZZN3uWS16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataE4initEvENKUlPT_E2_clI11us_socket_tEEDaS4_: 388| 22.8k| us_socket_context_on_timeout(SSL, getSocketContext(), [](auto *s) { 389| | 390| 22.8k| auto *webSocketData = (WebSocketData *)(us_socket_ext(SSL, s)); 391| 22.8k| auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); 392| | 393| 22.8k| if (webSocketContextData->sendPingsAutomatically && !webSocketData->isShuttingDown && !webSocketData->hasTimedOut) { ------------------ | Branch (393:17): [True: 22.8k, False: 0] | Branch (393:65): [True: 18.7k, False: 4.12k] | Branch (393:99): [True: 15.9k, False: 2.82k] ------------------ 394| 15.9k| webSocketData->hasTimedOut = true; 395| 15.9k| us_socket_timeout(SSL, s, webSocketContextData->idleTimeoutComponents.second); 396| | /* Send ping without being corked */ 397| 15.9k| ((AsyncSocket *) s)->write("\x89\x00", 2); 398| 15.9k| return s; 399| 15.9k| } 400| | 401| | /* Timeout is very simple; we just close it */ 402| | /* Warning: we happen to know forceClose will not use first parameter so pass nullptr here */ 403| 6.94k| forceClose(nullptr, s, ERR_WEBSOCKET_TIMEOUT); 404| | 405| 6.94k| return s; 406| 22.8k| }); EpollEchoServer.cpp:_ZN3uWS16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataE4freeEv: 411| 11.6k| void free() { 412| 11.6k| WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, (us_socket_context_t *) this); 413| 11.6k| webSocketContextData->~WebSocketContextData(); 414| | 415| 11.6k| us_socket_context_free(SSL, (us_socket_context_t *) this); 416| 11.6k| } EpollEchoServer.cpp:_ZN3uWS16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataE16getSocketContextEv: 35| 81.2k| us_socket_context_t *getSocketContext() { 36| 81.2k| return (us_socket_context_t *) this; 37| 81.2k| } EpollEchoServer.cpp:_ZN3uWS16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataE6getExtEv: 39| 187k| WebSocketContextData *getExt() { 40| 187k| return (WebSocketContextData *) us_socket_context_ext(SSL, (us_socket_context_t *) this); 41| 187k| } EpollEchoServer.cpp:_ZN3uWS20WebSocketContextDataILb0EZ4testvE13PerSocketDataEC2EPNS_9TopicTreeINS_16TopicTreeMessageENS_19TopicTreeBigMessageEEE: 102| 11.6k| WebSocketContextData(TopicTree *topicTree) : topicTree(topicTree) { 103| | 104| 11.6k| } EpollEchoServer.cpp:_ZN3uWS20WebSocketContextDataILb0EZ4testvE13PerSocketDataED2Ev: 98| 11.6k| ~WebSocketContextData() { 99| | 100| 11.6k| } EpollEchoServer.cpp:_ZN3uWS20WebSocketContextDataILb0EZ4testvE13PerSocketDataE29calculateIdleTimeoutCompnentsEt: 86| 11.6k| void calculateIdleTimeoutCompnents(unsigned short idleTimeout) { 87| 11.6k| unsigned short margin = 4; 88| | /* 4, 8 or 16 seconds margin based on idleTimeout */ 89| 11.6k| while ((int) idleTimeout - margin * 2 >= margin * 2 && margin < 16) { ------------------ | Branch (89:16): [True: 0, False: 11.6k] | Branch (89:64): [True: 0, False: 0] ------------------ 90| 0| margin = (unsigned short) (margin << 1); 91| 0| } 92| 11.6k| idleTimeoutComponents = { 93| 11.6k| idleTimeout - (sendPingsAutomatically ? margin : 0), /* reduce normal idleTimeout if it is extended by ping-timeout */ ------------------ | Branch (93:28): [True: 11.6k, False: 0] ------------------ 94| 11.6k| margin /* ping-timeout - also used for end() timeout */ 95| 11.6k| }; 96| 11.6k| } _ZN3uWS13WebSocketDataD2Ev: 69| 164k| ~WebSocketData() { 70| 164k| if (deflationStream) { ------------------ | Branch (70:13): [True: 2.21k, False: 162k] ------------------ 71| 2.21k| delete deflationStream; 72| 2.21k| } 73| | 74| 164k| if (inflationStream) { ------------------ | Branch (74:13): [True: 0, False: 164k] ------------------ 75| 0| delete inflationStream; 76| 0| } 77| | 78| 164k| if (subscriber) { ------------------ | Branch (78:13): [True: 0, False: 164k] ------------------ 79| 0| delete subscriber; 80| 0| } 81| 164k| } _ZN3uWS13WebSocketDataC2EbNS_15CompressOptionsEONS_12BackPressureE: 55| 164k| WebSocketData(bool perMessageDeflate, CompressOptions compressOptions, BackPressure &&backpressure) : AsyncSocketData(std::move(backpressure)), WebSocketState() { 56| 164k| compressionStatus = perMessageDeflate ? ENABLED : DISABLED; ------------------ | Branch (56:29): [True: 3.71k, False: 160k] ------------------ 57| | 58| | /* Initialize the dedicated sliding window(s) */ 59| 164k| if (perMessageDeflate) { ------------------ | Branch (59:13): [True: 3.71k, False: 160k] ------------------ 60| 3.71k| if ((compressOptions & CompressOptions::_COMPRESSOR_MASK) != CompressOptions::SHARED_COMPRESSOR) { ------------------ | Branch (60:17): [True: 2.21k, False: 1.50k] ------------------ 61| 2.21k| deflationStream = new DeflationStream(compressOptions); 62| 2.21k| } 63| 3.71k| if ((compressOptions & CompressOptions::_DECOMPRESSOR_MASK) != CompressOptions::SHARED_DECOMPRESSOR) { ------------------ | Branch (63:17): [True: 0, False: 3.71k] ------------------ 64| 0| inflationStream = new InflationStream(compressOptions); 65| 0| } 66| 3.71k| } 67| 164k| } EpollEchoServer.cpp:_ZN3uWSL20negotiateCompressionEbiiNSt3__117basic_string_viewIcNS0_11char_traitsIcEEEE: 144| 8.07k|static inline std::tuple negotiateCompression(bool wantCompression, int wantedCompressionWindow, int wantedInflationWindow, std::string_view offer) { 145| | 146| | /* If we don't want compression then we are done here */ 147| 8.07k| if (!wantCompression) { ------------------ | Branch (147:9): [True: 0, False: 8.07k] ------------------ 148| 0| return {false, 0, 0, ""}; 149| 0| } 150| | 151| 8.07k| ExtensionsParser ep(offer.data(), offer.length()); 152| | 153| 8.07k| static thread_local std::string response; 154| 8.07k| response = ""; 155| | 156| 8.07k| int compressionWindow = wantedCompressionWindow; 157| 8.07k| int inflationWindow = wantedInflationWindow; 158| 8.07k| bool compression = false; 159| | 160| 8.07k| if (ep.xWebKitDeflateFrame) { ------------------ | Branch (160:9): [True: 1.54k, False: 6.53k] ------------------ 161| | /* We now have compression */ 162| 1.54k| compression = true; 163| 1.54k| response = "x-webkit-deflate-frame"; 164| | 165| | /* If the other peer has DEMANDED us no sliding window, 166| | * we cannot compress with anything other than shared compressor */ 167| 1.54k| if (ep.noContextTakeover) { ------------------ | Branch (167:13): [True: 388, False: 1.15k] ------------------ 168| | /* We must fail here right now (fix pub/sub) */ 169| 388|#ifndef UWS_ALLOW_SHARED_AND_DEDICATED_COMPRESSOR_MIX 170| 388| if (wantedCompressionWindow != 0) { ------------------ | Branch (170:17): [True: 194, False: 194] ------------------ 171| 194| return {false, 0, 0, ""}; 172| 194| } 173| 194|#endif 174| | 175| 194| compressionWindow = 0; 176| 194| } 177| | 178| | /* If the other peer has DEMANDED us to use a limited sliding window, 179| | * we have to limit out compression sliding window */ 180| 1.34k| if (ep.maxWindowBits && ep.maxWindowBits < compressionWindow) { ------------------ | Branch (180:13): [True: 678, False: 671] | Branch (180:33): [True: 448, False: 230] ------------------ 181| 448| compressionWindow = ep.maxWindowBits; 182| 448|#ifndef UWS_ALLOW_8_WINDOW_BITS 183| | /* We cannot really deny this, so we have to disable compression in this case */ 184| 448| if (compressionWindow == 8) { ------------------ | Branch (184:17): [True: 241, False: 207] ------------------ 185| 241| return {false, 0, 0, ""}; 186| 241| } 187| 448|#endif 188| 448| } 189| | 190| | /* We decide our own inflation sliding window (and their compression sliding window) */ 191| 1.10k| if (wantedInflationWindow < 15) { ------------------ | Branch (191:13): [True: 1.10k, False: 0] ------------------ 192| 1.10k| if (!wantedInflationWindow) { ------------------ | Branch (192:17): [True: 1.10k, False: 0] ------------------ 193| 1.10k| response += "; no_context_takeover"; 194| 1.10k| } else { 195| 0| response += "; max_window_bits=" + std::to_string(wantedInflationWindow); 196| 0| } 197| 1.10k| } 198| 6.53k| } else if (ep.perMessageDeflate) { ------------------ | Branch (198:16): [True: 2.84k, False: 3.68k] ------------------ 199| | /* We now have compression */ 200| 2.84k| compression = true; 201| 2.84k| response = "permessage-deflate"; 202| | 203| 2.84k| if (ep.clientNoContextTakeover) { ------------------ | Branch (203:13): [True: 194, False: 2.65k] ------------------ 204| 194| inflationWindow = 0; 205| 2.65k| } else if (ep.clientMaxWindowBits && ep.clientMaxWindowBits != 1) { ------------------ | Branch (205:20): [True: 560, False: 2.09k] | Branch (205:46): [True: 224, False: 336] ------------------ 206| 224| inflationWindow = std::min(ep.clientMaxWindowBits, inflationWindow); 207| 224| } 208| | 209| | /* Whatever we have now, write */ 210| 2.84k| if (inflationWindow < 15) { ------------------ | Branch (210:13): [True: 2.84k, False: 0] ------------------ 211| 2.84k| if (!inflationWindow || !ep.clientMaxWindowBits) { ------------------ | Branch (211:17): [True: 2.84k, False: 0] | Branch (211:37): [True: 0, False: 0] ------------------ 212| 2.84k| response += "; client_no_context_takeover"; 213| 2.84k| inflationWindow = 0; 214| 2.84k| } else { 215| 0| response += "; client_max_window_bits=" + std::to_string(inflationWindow); 216| 0| } 217| 2.84k| } 218| | 219| | /* This block basically lets the client lower it */ 220| 2.84k| if (ep.serverNoContextTakeover) { ------------------ | Branch (220:13): [True: 341, False: 2.50k] ------------------ 221| | /* This is an important (temporary) fix since we haven't allowed 222| | * these two modes to mix, and pub/sub will not handle this case (yet) */ 223| |#ifdef UWS_ALLOW_SHARED_AND_DEDICATED_COMPRESSOR_MIX 224| | compressionWindow = 0; 225| |#endif 226| 2.50k| } else if (ep.serverMaxWindowBits) { ------------------ | Branch (226:20): [True: 443, False: 2.06k] ------------------ 227| 443| compressionWindow = std::min(ep.serverMaxWindowBits, compressionWindow); 228| 443|#ifndef UWS_ALLOW_8_WINDOW_BITS 229| | /* Zlib cannot do windowBits=8, memLevel=1 so we raise it up to 9 minimum */ 230| 443| if (compressionWindow == 8) { ------------------ | Branch (230:17): [True: 194, False: 249] ------------------ 231| 194| compressionWindow = 9; 232| 194| } 233| 443|#endif 234| 443| } 235| | 236| | /* Whatever we have now, write */ 237| 2.84k| if (compressionWindow < 15) { ------------------ | Branch (237:13): [True: 2.25k, False: 590] ------------------ 238| 2.25k| if (!compressionWindow) { ------------------ | Branch (238:17): [True: 1.06k, False: 1.18k] ------------------ 239| 1.06k| response += "; server_no_context_takeover"; 240| 1.18k| } else { 241| 1.18k| response += "; server_max_window_bits=" + std::to_string(compressionWindow); 242| 1.18k| } 243| 2.25k| } 244| 2.84k| } 245| | 246| | /* A final sanity check (this check does not actually catch too high values!) */ 247| 7.64k| if ((compressionWindow && compressionWindow < 8) || compressionWindow > 15 || (inflationWindow && inflationWindow < 8) || inflationWindow > 15) { ------------------ | Branch (247:10): [True: 5.33k, False: 2.30k] | Branch (247:31): [True: 238, False: 5.09k] | Branch (247:57): [True: 0, False: 7.40k] | Branch (247:84): [True: 0, False: 7.40k] | Branch (247:103): [True: 0, False: 0] | Branch (247:127): [True: 0, False: 7.40k] ------------------ 248| 238| return {false, 0, 0, ""}; 249| 238| } 250| | 251| 7.40k| return {compression, compressionWindow, inflationWindow, response}; 252| 7.64k|} _ZN3uWS16ExtensionsParserC2EPKcm: 93| 8.07k| ExtensionsParser(const char *data, size_t length) { 94| 8.07k| const char *stop = data + length; 95| 8.07k| int token = 1; 96| | 97| | /* Ignore anything before permessage-deflate or x-webkit-deflate-frame */ 98| 21.0k| for (; token && token != TOK_PERMESSAGE_DEFLATE && token != TOK_X_WEBKIT_DEFLATE_FRAME; token = getToken(data, stop)); ------------------ | Branch (98:16): [True: 17.3k, False: 3.68k] | Branch (98:25): [True: 14.5k, False: 2.84k] | Branch (98:60): [True: 13.0k, False: 1.54k] ------------------ 99| | 100| | /* What protocol are we going to use? */ 101| 8.07k| perMessageDeflate = (token == TOK_PERMESSAGE_DEFLATE); 102| 8.07k| xWebKitDeflateFrame = (token == TOK_X_WEBKIT_DEFLATE_FRAME); 103| | 104| 24.5k| while ((token = getToken(data, stop))) { ------------------ | Branch (104:16): [True: 17.1k, False: 7.47k] ------------------ 105| 17.1k| switch (token) { 106| 392| case TOK_X_WEBKIT_DEFLATE_FRAME: ------------------ | Branch (106:13): [True: 392, False: 16.7k] ------------------ 107| | /* Duplicates not allowed/supported */ 108| 392| return; 109| 582| case TOK_NO_CONTEXT_TAKEOVER: ------------------ | Branch (109:13): [True: 582, False: 16.5k] ------------------ 110| 582| noContextTakeover = true; 111| 582| break; 112| 901| case TOK_MAX_WINDOW_BITS: ------------------ | Branch (112:13): [True: 901, False: 16.2k] ------------------ 113| 901| maxWindowBits = 1; 114| 901| lastInteger = &maxWindowBits; 115| 901| break; 116| 207| case TOK_PERMESSAGE_DEFLATE: ------------------ | Branch (116:13): [True: 207, False: 16.9k] ------------------ 117| | /* Duplicates not allowed/supported */ 118| 207| return; 119| 525| case TOK_SERVER_NO_CONTEXT_TAKEOVER: ------------------ | Branch (119:13): [True: 525, False: 16.5k] ------------------ 120| 525| serverNoContextTakeover = true; 121| 525| break; 122| 397| case TOK_CLIENT_NO_CONTEXT_TAKEOVER: ------------------ | Branch (122:13): [True: 397, False: 16.7k] ------------------ 123| 397| clientNoContextTakeover = true; 124| 397| break; 125| 642| case TOK_SERVER_MAX_WINDOW_BITS: ------------------ | Branch (125:13): [True: 642, False: 16.4k] ------------------ 126| 642| serverMaxWindowBits = 1; 127| 642| lastInteger = &serverMaxWindowBits; 128| 642| break; 129| 2.37k| case TOK_CLIENT_MAX_WINDOW_BITS: ------------------ | Branch (129:13): [True: 2.37k, False: 14.7k] ------------------ 130| 2.37k| clientMaxWindowBits = 1; 131| 2.37k| lastInteger = &clientMaxWindowBits; 132| 2.37k| break; 133| 11.0k| default: ------------------ | Branch (133:13): [True: 11.0k, False: 6.02k] ------------------ 134| 11.0k| if (token < 0 && lastInteger) { ------------------ | Branch (134:21): [True: 3.01k, False: 8.07k] | Branch (134:34): [True: 2.57k, False: 431] ------------------ 135| 2.57k| *lastInteger = -token; 136| 2.57k| } 137| 11.0k| break; 138| 17.1k| } 139| 17.1k| } 140| 8.07k| } _ZN3uWS16ExtensionsParser8getTokenERPKcS2_: 69| 37.5k| int getToken(const char *&in, const char *stop) { 70| 85.2k| while (in != stop && !isalnum(*in)) { ------------------ | Branch (70:16): [True: 75.0k, False: 10.1k] | Branch (70:30): [True: 47.6k, False: 27.4k] ------------------ 71| 47.6k| in++; 72| 47.6k| } 73| | 74| | /* Don't care more than this for now */ 75| 37.5k| static_assert(SHRT_MIN > INT_MIN, "Integer overflow fix is invalid for this platform, report this as a bug!"); 76| | 77| 37.5k| int hashedToken = 0; 78| 279k| while (in != stop && (isalnum(*in) || *in == '-' || *in == '_')) { ------------------ | Branch (78:16): [True: 266k, False: 13.4k] | Branch (78:31): [True: 227k, False: 38.8k] | Branch (78:47): [True: 14.2k, False: 24.5k] | Branch (78:61): [True: 388, False: 24.1k] ------------------ 79| 242k| if (isdigit(*in)) { ------------------ | Branch (79:17): [True: 16.6k, False: 225k] ------------------ 80| | /* This check is a quick and incorrect fix for integer overflow 81| | * in oss-fuzz but we don't care as it doesn't matter either way */ 82| 16.6k| if (hashedToken > SHRT_MIN && hashedToken < SHRT_MAX) { ------------------ | Branch (82:21): [True: 15.1k, False: 1.47k] | Branch (82:47): [True: 14.4k, False: 713] ------------------ 83| 14.4k| hashedToken = hashedToken * 10 - (*in - '0'); 84| 14.4k| } 85| 225k| } else { 86| 225k| hashedToken += *in; 87| 225k| } 88| 242k| in++; 89| 242k| } 90| 37.5k| return hashedToken; 91| 37.5k| } _ZN3uWS18WebSocketHandshake8generateEPKcPc: 116| 164k| static inline void generate(const char input[24], char output[28]) { 117| 164k| uint32_t b_output[5] = { 118| 164k| 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 119| 164k| }; 120| 164k| uint32_t b_input[16] = { 121| 164k| 0, 0, 0, 0, 0, 0, 0x32353845, 0x41464135, 0x2d453931, 0x342d3437, 0x44412d39, 122| 164k| 0x3543412d, 0x43354142, 0x30444338, 0x35423131, 0x80000000 123| 164k| }; 124| | 125| 1.14M| for (int i = 0; i < 6; i++) { ------------------ | Branch (125:25): [True: 985k, False: 164k] ------------------ 126| 985k| b_input[i] = (uint32_t) ((input[4 * i + 3] & 0xff) | (input[4 * i + 2] & 0xff) << 8 | (input[4 * i + 1] & 0xff) << 16 | (input[4 * i + 0] & 0xff) << 24); 127| 985k| } 128| 164k| sha1(b_output, b_input); 129| 164k| uint32_t last_b[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 480}; 130| 164k| sha1(b_output, last_b); 131| 985k| for (int i = 0; i < 5; i++) { ------------------ | Branch (131:25): [True: 821k, False: 164k] ------------------ 132| 821k| uint32_t tmp = b_output[i]; 133| 821k| char *bytes = (char *) &b_output[i]; 134| 821k| bytes[3] = (char) (tmp & 0xff); 135| 821k| bytes[2] = (char) ((tmp >> 8) & 0xff); 136| 821k| bytes[1] = (char) ((tmp >> 16) & 0xff); 137| 821k| bytes[0] = (char) ((tmp >> 24) & 0xff); 138| 821k| } 139| 164k| base64((unsigned char *) b_output, output); 140| 164k| } _ZN3uWS18WebSocketHandshake4sha1EPjS1_: 91| 328k| static inline void sha1(uint32_t hash[5], uint32_t b[16]) { 92| 328k| uint32_t a[5] = {hash[4], hash[3], hash[2], hash[1], hash[0]}; 93| 328k| static_for<16, Sha1Loop1>()(a, b); 94| 328k| static_for<4, Sha1Loop2>()(a, b); 95| 328k| static_for<20, Sha1Loop3>()(a, b); 96| 328k| static_for<20, Sha1Loop4>()(a, b); 97| 328k| static_for<20, Sha1Loop5>()(a, b); 98| 328k| static_for<5, Sha1Loop6>()(a, hash); 99| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi16ENS0_9Sha1Loop1EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi15ENS0_9Sha1Loop1EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi14ENS0_9Sha1Loop1EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi13ENS0_9Sha1Loop1EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi12ENS0_9Sha1Loop1EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi11ENS0_9Sha1Loop1EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi10ENS0_9Sha1Loop1EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi9ENS0_9Sha1Loop1EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi8ENS0_9Sha1Loop1EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi7ENS0_9Sha1Loop1EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi6ENS0_9Sha1Loop1EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi5ENS0_9Sha1Loop1EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi4ENS0_9Sha1Loop1EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi3ENS0_9Sha1Loop1EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi2ENS0_9Sha1Loop1EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi1ENS0_9Sha1Loop1EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi0ENS0_9Sha1Loop1EEclEPjS4_: 37| 328k| void operator()(uint32_t */*a*/, uint32_t */*hash*/) {} _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi0EEEvPjS3_: 47| 328k| static inline void f(uint32_t *a, uint32_t *b) { 48| 328k| a[i % 5] += ((a[(3 + i) % 5] & (a[(2 + i) % 5] ^ a[(1 + i) % 5])) ^ a[(1 + i) % 5]) + b[i] + 0x5a827999 + rol(a[(4 + i) % 5], 5); 49| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 328k| } _ZN3uWS18WebSocketHandshake3rolEjm: 40| 73.5M| static inline uint32_t rol(uint32_t value, size_t bits) {return (value << bits) | (value >> (32 - bits));} _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi1EEEvPjS3_: 47| 328k| static inline void f(uint32_t *a, uint32_t *b) { 48| 328k| a[i % 5] += ((a[(3 + i) % 5] & (a[(2 + i) % 5] ^ a[(1 + i) % 5])) ^ a[(1 + i) % 5]) + b[i] + 0x5a827999 + rol(a[(4 + i) % 5], 5); 49| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi2EEEvPjS3_: 47| 328k| static inline void f(uint32_t *a, uint32_t *b) { 48| 328k| a[i % 5] += ((a[(3 + i) % 5] & (a[(2 + i) % 5] ^ a[(1 + i) % 5])) ^ a[(1 + i) % 5]) + b[i] + 0x5a827999 + rol(a[(4 + i) % 5], 5); 49| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi3EEEvPjS3_: 47| 328k| static inline void f(uint32_t *a, uint32_t *b) { 48| 328k| a[i % 5] += ((a[(3 + i) % 5] & (a[(2 + i) % 5] ^ a[(1 + i) % 5])) ^ a[(1 + i) % 5]) + b[i] + 0x5a827999 + rol(a[(4 + i) % 5], 5); 49| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi4EEEvPjS3_: 47| 328k| static inline void f(uint32_t *a, uint32_t *b) { 48| 328k| a[i % 5] += ((a[(3 + i) % 5] & (a[(2 + i) % 5] ^ a[(1 + i) % 5])) ^ a[(1 + i) % 5]) + b[i] + 0x5a827999 + rol(a[(4 + i) % 5], 5); 49| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi5EEEvPjS3_: 47| 328k| static inline void f(uint32_t *a, uint32_t *b) { 48| 328k| a[i % 5] += ((a[(3 + i) % 5] & (a[(2 + i) % 5] ^ a[(1 + i) % 5])) ^ a[(1 + i) % 5]) + b[i] + 0x5a827999 + rol(a[(4 + i) % 5], 5); 49| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi6EEEvPjS3_: 47| 328k| static inline void f(uint32_t *a, uint32_t *b) { 48| 328k| a[i % 5] += ((a[(3 + i) % 5] & (a[(2 + i) % 5] ^ a[(1 + i) % 5])) ^ a[(1 + i) % 5]) + b[i] + 0x5a827999 + rol(a[(4 + i) % 5], 5); 49| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi7EEEvPjS3_: 47| 328k| static inline void f(uint32_t *a, uint32_t *b) { 48| 328k| a[i % 5] += ((a[(3 + i) % 5] & (a[(2 + i) % 5] ^ a[(1 + i) % 5])) ^ a[(1 + i) % 5]) + b[i] + 0x5a827999 + rol(a[(4 + i) % 5], 5); 49| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi8EEEvPjS3_: 47| 328k| static inline void f(uint32_t *a, uint32_t *b) { 48| 328k| a[i % 5] += ((a[(3 + i) % 5] & (a[(2 + i) % 5] ^ a[(1 + i) % 5])) ^ a[(1 + i) % 5]) + b[i] + 0x5a827999 + rol(a[(4 + i) % 5], 5); 49| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi9EEEvPjS3_: 47| 328k| static inline void f(uint32_t *a, uint32_t *b) { 48| 328k| a[i % 5] += ((a[(3 + i) % 5] & (a[(2 + i) % 5] ^ a[(1 + i) % 5])) ^ a[(1 + i) % 5]) + b[i] + 0x5a827999 + rol(a[(4 + i) % 5], 5); 49| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi10EEEvPjS3_: 47| 328k| static inline void f(uint32_t *a, uint32_t *b) { 48| 328k| a[i % 5] += ((a[(3 + i) % 5] & (a[(2 + i) % 5] ^ a[(1 + i) % 5])) ^ a[(1 + i) % 5]) + b[i] + 0x5a827999 + rol(a[(4 + i) % 5], 5); 49| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi11EEEvPjS3_: 47| 328k| static inline void f(uint32_t *a, uint32_t *b) { 48| 328k| a[i % 5] += ((a[(3 + i) % 5] & (a[(2 + i) % 5] ^ a[(1 + i) % 5])) ^ a[(1 + i) % 5]) + b[i] + 0x5a827999 + rol(a[(4 + i) % 5], 5); 49| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi12EEEvPjS3_: 47| 328k| static inline void f(uint32_t *a, uint32_t *b) { 48| 328k| a[i % 5] += ((a[(3 + i) % 5] & (a[(2 + i) % 5] ^ a[(1 + i) % 5])) ^ a[(1 + i) % 5]) + b[i] + 0x5a827999 + rol(a[(4 + i) % 5], 5); 49| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi13EEEvPjS3_: 47| 328k| static inline void f(uint32_t *a, uint32_t *b) { 48| 328k| a[i % 5] += ((a[(3 + i) % 5] & (a[(2 + i) % 5] ^ a[(1 + i) % 5])) ^ a[(1 + i) % 5]) + b[i] + 0x5a827999 + rol(a[(4 + i) % 5], 5); 49| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi14EEEvPjS3_: 47| 328k| static inline void f(uint32_t *a, uint32_t *b) { 48| 328k| a[i % 5] += ((a[(3 + i) % 5] & (a[(2 + i) % 5] ^ a[(1 + i) % 5])) ^ a[(1 + i) % 5]) + b[i] + 0x5a827999 + rol(a[(4 + i) % 5], 5); 49| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi15EEEvPjS3_: 47| 328k| static inline void f(uint32_t *a, uint32_t *b) { 48| 328k| a[i % 5] += ((a[(3 + i) % 5] & (a[(2 + i) % 5] ^ a[(1 + i) % 5])) ^ a[(1 + i) % 5]) + b[i] + 0x5a827999 + rol(a[(4 + i) % 5], 5); 49| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi4ENS0_9Sha1Loop2EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi3ENS0_9Sha1Loop2EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi2ENS0_9Sha1Loop2EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi1ENS0_9Sha1Loop2EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi0ENS0_9Sha1Loop2EEclEPjS4_: 37| 328k| void operator()(uint32_t */*a*/, uint32_t */*hash*/) {} _ZN3uWS18WebSocketHandshake9Sha1Loop21fILi0EEEvPjS3_: 54| 328k| static inline void f(uint32_t *a, uint32_t *b) { 55| 328k| b[i] = blk(b, i); 56| 328k| a[(1 + i) % 5] += ((a[(4 + i) % 5] & (a[(3 + i) % 5] ^ a[(2 + i) % 5])) ^ a[(2 + i) % 5]) + b[i] + 0x5a827999 + rol(a[(5 + i) % 5], 5); 57| 328k| a[(4 + i) % 5] = rol(a[(4 + i) % 5], 30); 58| 328k| } _ZN3uWS18WebSocketHandshake3blkEPjm: 41| 21.0M| static inline uint32_t blk(uint32_t b[16], size_t i) { 42| 21.0M| return rol(b[(i + 13) & 15] ^ b[(i + 8) & 15] ^ b[(i + 2) & 15] ^ b[i], 1); 43| 21.0M| } _ZN3uWS18WebSocketHandshake9Sha1Loop21fILi1EEEvPjS3_: 54| 328k| static inline void f(uint32_t *a, uint32_t *b) { 55| 328k| b[i] = blk(b, i); 56| 328k| a[(1 + i) % 5] += ((a[(4 + i) % 5] & (a[(3 + i) % 5] ^ a[(2 + i) % 5])) ^ a[(2 + i) % 5]) + b[i] + 0x5a827999 + rol(a[(5 + i) % 5], 5); 57| 328k| a[(4 + i) % 5] = rol(a[(4 + i) % 5], 30); 58| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop21fILi2EEEvPjS3_: 54| 328k| static inline void f(uint32_t *a, uint32_t *b) { 55| 328k| b[i] = blk(b, i); 56| 328k| a[(1 + i) % 5] += ((a[(4 + i) % 5] & (a[(3 + i) % 5] ^ a[(2 + i) % 5])) ^ a[(2 + i) % 5]) + b[i] + 0x5a827999 + rol(a[(5 + i) % 5], 5); 57| 328k| a[(4 + i) % 5] = rol(a[(4 + i) % 5], 30); 58| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop21fILi3EEEvPjS3_: 54| 328k| static inline void f(uint32_t *a, uint32_t *b) { 55| 328k| b[i] = blk(b, i); 56| 328k| a[(1 + i) % 5] += ((a[(4 + i) % 5] & (a[(3 + i) % 5] ^ a[(2 + i) % 5])) ^ a[(2 + i) % 5]) + b[i] + 0x5a827999 + rol(a[(5 + i) % 5], 5); 57| 328k| a[(4 + i) % 5] = rol(a[(4 + i) % 5], 30); 58| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi20ENS0_9Sha1Loop3EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi19ENS0_9Sha1Loop3EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi18ENS0_9Sha1Loop3EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi17ENS0_9Sha1Loop3EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi16ENS0_9Sha1Loop3EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi15ENS0_9Sha1Loop3EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi14ENS0_9Sha1Loop3EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi13ENS0_9Sha1Loop3EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi12ENS0_9Sha1Loop3EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi11ENS0_9Sha1Loop3EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi10ENS0_9Sha1Loop3EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi9ENS0_9Sha1Loop3EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi8ENS0_9Sha1Loop3EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi7ENS0_9Sha1Loop3EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi6ENS0_9Sha1Loop3EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi5ENS0_9Sha1Loop3EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi4ENS0_9Sha1Loop3EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi3ENS0_9Sha1Loop3EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi2ENS0_9Sha1Loop3EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi1ENS0_9Sha1Loop3EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi0ENS0_9Sha1Loop3EEclEPjS4_: 37| 328k| void operator()(uint32_t */*a*/, uint32_t */*hash*/) {} _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi0EEEvPjS3_: 62| 328k| static inline void f(uint32_t *a, uint32_t *b) { 63| 328k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 4) % 16] + 0x6ed9eba1 + rol(a[(4 + i) % 5], 5); 65| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi1EEEvPjS3_: 62| 328k| static inline void f(uint32_t *a, uint32_t *b) { 63| 328k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 4) % 16] + 0x6ed9eba1 + rol(a[(4 + i) % 5], 5); 65| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi2EEEvPjS3_: 62| 328k| static inline void f(uint32_t *a, uint32_t *b) { 63| 328k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 4) % 16] + 0x6ed9eba1 + rol(a[(4 + i) % 5], 5); 65| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi3EEEvPjS3_: 62| 328k| static inline void f(uint32_t *a, uint32_t *b) { 63| 328k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 4) % 16] + 0x6ed9eba1 + rol(a[(4 + i) % 5], 5); 65| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi4EEEvPjS3_: 62| 328k| static inline void f(uint32_t *a, uint32_t *b) { 63| 328k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 4) % 16] + 0x6ed9eba1 + rol(a[(4 + i) % 5], 5); 65| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi5EEEvPjS3_: 62| 328k| static inline void f(uint32_t *a, uint32_t *b) { 63| 328k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 4) % 16] + 0x6ed9eba1 + rol(a[(4 + i) % 5], 5); 65| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi6EEEvPjS3_: 62| 328k| static inline void f(uint32_t *a, uint32_t *b) { 63| 328k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 4) % 16] + 0x6ed9eba1 + rol(a[(4 + i) % 5], 5); 65| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi7EEEvPjS3_: 62| 328k| static inline void f(uint32_t *a, uint32_t *b) { 63| 328k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 4) % 16] + 0x6ed9eba1 + rol(a[(4 + i) % 5], 5); 65| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi8EEEvPjS3_: 62| 328k| static inline void f(uint32_t *a, uint32_t *b) { 63| 328k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 4) % 16] + 0x6ed9eba1 + rol(a[(4 + i) % 5], 5); 65| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi9EEEvPjS3_: 62| 328k| static inline void f(uint32_t *a, uint32_t *b) { 63| 328k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 4) % 16] + 0x6ed9eba1 + rol(a[(4 + i) % 5], 5); 65| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi10EEEvPjS3_: 62| 328k| static inline void f(uint32_t *a, uint32_t *b) { 63| 328k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 4) % 16] + 0x6ed9eba1 + rol(a[(4 + i) % 5], 5); 65| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi11EEEvPjS3_: 62| 328k| static inline void f(uint32_t *a, uint32_t *b) { 63| 328k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 4) % 16] + 0x6ed9eba1 + rol(a[(4 + i) % 5], 5); 65| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi12EEEvPjS3_: 62| 328k| static inline void f(uint32_t *a, uint32_t *b) { 63| 328k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 4) % 16] + 0x6ed9eba1 + rol(a[(4 + i) % 5], 5); 65| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi13EEEvPjS3_: 62| 328k| static inline void f(uint32_t *a, uint32_t *b) { 63| 328k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 4) % 16] + 0x6ed9eba1 + rol(a[(4 + i) % 5], 5); 65| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi14EEEvPjS3_: 62| 328k| static inline void f(uint32_t *a, uint32_t *b) { 63| 328k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 4) % 16] + 0x6ed9eba1 + rol(a[(4 + i) % 5], 5); 65| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi15EEEvPjS3_: 62| 328k| static inline void f(uint32_t *a, uint32_t *b) { 63| 328k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 4) % 16] + 0x6ed9eba1 + rol(a[(4 + i) % 5], 5); 65| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi16EEEvPjS3_: 62| 328k| static inline void f(uint32_t *a, uint32_t *b) { 63| 328k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 4) % 16] + 0x6ed9eba1 + rol(a[(4 + i) % 5], 5); 65| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi17EEEvPjS3_: 62| 328k| static inline void f(uint32_t *a, uint32_t *b) { 63| 328k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 4) % 16] + 0x6ed9eba1 + rol(a[(4 + i) % 5], 5); 65| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi18EEEvPjS3_: 62| 328k| static inline void f(uint32_t *a, uint32_t *b) { 63| 328k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 4) % 16] + 0x6ed9eba1 + rol(a[(4 + i) % 5], 5); 65| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi19EEEvPjS3_: 62| 328k| static inline void f(uint32_t *a, uint32_t *b) { 63| 328k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 4) % 16] + 0x6ed9eba1 + rol(a[(4 + i) % 5], 5); 65| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi20ENS0_9Sha1Loop4EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi19ENS0_9Sha1Loop4EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi18ENS0_9Sha1Loop4EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi17ENS0_9Sha1Loop4EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi16ENS0_9Sha1Loop4EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi15ENS0_9Sha1Loop4EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi14ENS0_9Sha1Loop4EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi13ENS0_9Sha1Loop4EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi12ENS0_9Sha1Loop4EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi11ENS0_9Sha1Loop4EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi10ENS0_9Sha1Loop4EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi9ENS0_9Sha1Loop4EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi8ENS0_9Sha1Loop4EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi7ENS0_9Sha1Loop4EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi6ENS0_9Sha1Loop4EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi5ENS0_9Sha1Loop4EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi4ENS0_9Sha1Loop4EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi3ENS0_9Sha1Loop4EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi2ENS0_9Sha1Loop4EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi1ENS0_9Sha1Loop4EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi0ENS0_9Sha1Loop4EEclEPjS4_: 37| 328k| void operator()(uint32_t */*a*/, uint32_t */*hash*/) {} _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi0EEEvPjS3_: 70| 328k| static inline void f(uint32_t *a, uint32_t *b) { 71| 328k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 328k| a[i % 5] += (((a[(3 + i) % 5] | a[(2 + i) % 5]) & a[(1 + i) % 5]) | (a[(3 + i) % 5] & a[(2 + i) % 5])) + b[(i + 8) % 16] + 0x8f1bbcdc + rol(a[(4 + i) % 5], 5); 73| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi1EEEvPjS3_: 70| 328k| static inline void f(uint32_t *a, uint32_t *b) { 71| 328k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 328k| a[i % 5] += (((a[(3 + i) % 5] | a[(2 + i) % 5]) & a[(1 + i) % 5]) | (a[(3 + i) % 5] & a[(2 + i) % 5])) + b[(i + 8) % 16] + 0x8f1bbcdc + rol(a[(4 + i) % 5], 5); 73| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi2EEEvPjS3_: 70| 328k| static inline void f(uint32_t *a, uint32_t *b) { 71| 328k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 328k| a[i % 5] += (((a[(3 + i) % 5] | a[(2 + i) % 5]) & a[(1 + i) % 5]) | (a[(3 + i) % 5] & a[(2 + i) % 5])) + b[(i + 8) % 16] + 0x8f1bbcdc + rol(a[(4 + i) % 5], 5); 73| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi3EEEvPjS3_: 70| 328k| static inline void f(uint32_t *a, uint32_t *b) { 71| 328k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 328k| a[i % 5] += (((a[(3 + i) % 5] | a[(2 + i) % 5]) & a[(1 + i) % 5]) | (a[(3 + i) % 5] & a[(2 + i) % 5])) + b[(i + 8) % 16] + 0x8f1bbcdc + rol(a[(4 + i) % 5], 5); 73| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi4EEEvPjS3_: 70| 328k| static inline void f(uint32_t *a, uint32_t *b) { 71| 328k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 328k| a[i % 5] += (((a[(3 + i) % 5] | a[(2 + i) % 5]) & a[(1 + i) % 5]) | (a[(3 + i) % 5] & a[(2 + i) % 5])) + b[(i + 8) % 16] + 0x8f1bbcdc + rol(a[(4 + i) % 5], 5); 73| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi5EEEvPjS3_: 70| 328k| static inline void f(uint32_t *a, uint32_t *b) { 71| 328k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 328k| a[i % 5] += (((a[(3 + i) % 5] | a[(2 + i) % 5]) & a[(1 + i) % 5]) | (a[(3 + i) % 5] & a[(2 + i) % 5])) + b[(i + 8) % 16] + 0x8f1bbcdc + rol(a[(4 + i) % 5], 5); 73| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi6EEEvPjS3_: 70| 328k| static inline void f(uint32_t *a, uint32_t *b) { 71| 328k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 328k| a[i % 5] += (((a[(3 + i) % 5] | a[(2 + i) % 5]) & a[(1 + i) % 5]) | (a[(3 + i) % 5] & a[(2 + i) % 5])) + b[(i + 8) % 16] + 0x8f1bbcdc + rol(a[(4 + i) % 5], 5); 73| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi7EEEvPjS3_: 70| 328k| static inline void f(uint32_t *a, uint32_t *b) { 71| 328k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 328k| a[i % 5] += (((a[(3 + i) % 5] | a[(2 + i) % 5]) & a[(1 + i) % 5]) | (a[(3 + i) % 5] & a[(2 + i) % 5])) + b[(i + 8) % 16] + 0x8f1bbcdc + rol(a[(4 + i) % 5], 5); 73| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi8EEEvPjS3_: 70| 328k| static inline void f(uint32_t *a, uint32_t *b) { 71| 328k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 328k| a[i % 5] += (((a[(3 + i) % 5] | a[(2 + i) % 5]) & a[(1 + i) % 5]) | (a[(3 + i) % 5] & a[(2 + i) % 5])) + b[(i + 8) % 16] + 0x8f1bbcdc + rol(a[(4 + i) % 5], 5); 73| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi9EEEvPjS3_: 70| 328k| static inline void f(uint32_t *a, uint32_t *b) { 71| 328k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 328k| a[i % 5] += (((a[(3 + i) % 5] | a[(2 + i) % 5]) & a[(1 + i) % 5]) | (a[(3 + i) % 5] & a[(2 + i) % 5])) + b[(i + 8) % 16] + 0x8f1bbcdc + rol(a[(4 + i) % 5], 5); 73| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi10EEEvPjS3_: 70| 328k| static inline void f(uint32_t *a, uint32_t *b) { 71| 328k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 328k| a[i % 5] += (((a[(3 + i) % 5] | a[(2 + i) % 5]) & a[(1 + i) % 5]) | (a[(3 + i) % 5] & a[(2 + i) % 5])) + b[(i + 8) % 16] + 0x8f1bbcdc + rol(a[(4 + i) % 5], 5); 73| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi11EEEvPjS3_: 70| 328k| static inline void f(uint32_t *a, uint32_t *b) { 71| 328k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 328k| a[i % 5] += (((a[(3 + i) % 5] | a[(2 + i) % 5]) & a[(1 + i) % 5]) | (a[(3 + i) % 5] & a[(2 + i) % 5])) + b[(i + 8) % 16] + 0x8f1bbcdc + rol(a[(4 + i) % 5], 5); 73| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi12EEEvPjS3_: 70| 328k| static inline void f(uint32_t *a, uint32_t *b) { 71| 328k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 328k| a[i % 5] += (((a[(3 + i) % 5] | a[(2 + i) % 5]) & a[(1 + i) % 5]) | (a[(3 + i) % 5] & a[(2 + i) % 5])) + b[(i + 8) % 16] + 0x8f1bbcdc + rol(a[(4 + i) % 5], 5); 73| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi13EEEvPjS3_: 70| 328k| static inline void f(uint32_t *a, uint32_t *b) { 71| 328k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 328k| a[i % 5] += (((a[(3 + i) % 5] | a[(2 + i) % 5]) & a[(1 + i) % 5]) | (a[(3 + i) % 5] & a[(2 + i) % 5])) + b[(i + 8) % 16] + 0x8f1bbcdc + rol(a[(4 + i) % 5], 5); 73| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi14EEEvPjS3_: 70| 328k| static inline void f(uint32_t *a, uint32_t *b) { 71| 328k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 328k| a[i % 5] += (((a[(3 + i) % 5] | a[(2 + i) % 5]) & a[(1 + i) % 5]) | (a[(3 + i) % 5] & a[(2 + i) % 5])) + b[(i + 8) % 16] + 0x8f1bbcdc + rol(a[(4 + i) % 5], 5); 73| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi15EEEvPjS3_: 70| 328k| static inline void f(uint32_t *a, uint32_t *b) { 71| 328k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 328k| a[i % 5] += (((a[(3 + i) % 5] | a[(2 + i) % 5]) & a[(1 + i) % 5]) | (a[(3 + i) % 5] & a[(2 + i) % 5])) + b[(i + 8) % 16] + 0x8f1bbcdc + rol(a[(4 + i) % 5], 5); 73| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi16EEEvPjS3_: 70| 328k| static inline void f(uint32_t *a, uint32_t *b) { 71| 328k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 328k| a[i % 5] += (((a[(3 + i) % 5] | a[(2 + i) % 5]) & a[(1 + i) % 5]) | (a[(3 + i) % 5] & a[(2 + i) % 5])) + b[(i + 8) % 16] + 0x8f1bbcdc + rol(a[(4 + i) % 5], 5); 73| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi17EEEvPjS3_: 70| 328k| static inline void f(uint32_t *a, uint32_t *b) { 71| 328k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 328k| a[i % 5] += (((a[(3 + i) % 5] | a[(2 + i) % 5]) & a[(1 + i) % 5]) | (a[(3 + i) % 5] & a[(2 + i) % 5])) + b[(i + 8) % 16] + 0x8f1bbcdc + rol(a[(4 + i) % 5], 5); 73| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi18EEEvPjS3_: 70| 328k| static inline void f(uint32_t *a, uint32_t *b) { 71| 328k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 328k| a[i % 5] += (((a[(3 + i) % 5] | a[(2 + i) % 5]) & a[(1 + i) % 5]) | (a[(3 + i) % 5] & a[(2 + i) % 5])) + b[(i + 8) % 16] + 0x8f1bbcdc + rol(a[(4 + i) % 5], 5); 73| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi19EEEvPjS3_: 70| 328k| static inline void f(uint32_t *a, uint32_t *b) { 71| 328k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 328k| a[i % 5] += (((a[(3 + i) % 5] | a[(2 + i) % 5]) & a[(1 + i) % 5]) | (a[(3 + i) % 5] & a[(2 + i) % 5])) + b[(i + 8) % 16] + 0x8f1bbcdc + rol(a[(4 + i) % 5], 5); 73| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi20ENS0_9Sha1Loop5EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi19ENS0_9Sha1Loop5EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi18ENS0_9Sha1Loop5EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi17ENS0_9Sha1Loop5EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi16ENS0_9Sha1Loop5EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi15ENS0_9Sha1Loop5EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi14ENS0_9Sha1Loop5EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi13ENS0_9Sha1Loop5EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi12ENS0_9Sha1Loop5EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi11ENS0_9Sha1Loop5EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi10ENS0_9Sha1Loop5EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi9ENS0_9Sha1Loop5EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi8ENS0_9Sha1Loop5EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi7ENS0_9Sha1Loop5EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi6ENS0_9Sha1Loop5EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi5ENS0_9Sha1Loop5EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi4ENS0_9Sha1Loop5EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi3ENS0_9Sha1Loop5EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi2ENS0_9Sha1Loop5EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi1ENS0_9Sha1Loop5EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi0ENS0_9Sha1Loop5EEclEPjS4_: 37| 328k| void operator()(uint32_t */*a*/, uint32_t */*hash*/) {} _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi0EEEvPjS3_: 78| 328k| static inline void f(uint32_t *a, uint32_t *b) { 79| 328k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 12) % 16] + 0xca62c1d6 + rol(a[(4 + i) % 5], 5); 81| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi1EEEvPjS3_: 78| 328k| static inline void f(uint32_t *a, uint32_t *b) { 79| 328k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 12) % 16] + 0xca62c1d6 + rol(a[(4 + i) % 5], 5); 81| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi2EEEvPjS3_: 78| 328k| static inline void f(uint32_t *a, uint32_t *b) { 79| 328k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 12) % 16] + 0xca62c1d6 + rol(a[(4 + i) % 5], 5); 81| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi3EEEvPjS3_: 78| 328k| static inline void f(uint32_t *a, uint32_t *b) { 79| 328k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 12) % 16] + 0xca62c1d6 + rol(a[(4 + i) % 5], 5); 81| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi4EEEvPjS3_: 78| 328k| static inline void f(uint32_t *a, uint32_t *b) { 79| 328k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 12) % 16] + 0xca62c1d6 + rol(a[(4 + i) % 5], 5); 81| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi5EEEvPjS3_: 78| 328k| static inline void f(uint32_t *a, uint32_t *b) { 79| 328k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 12) % 16] + 0xca62c1d6 + rol(a[(4 + i) % 5], 5); 81| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi6EEEvPjS3_: 78| 328k| static inline void f(uint32_t *a, uint32_t *b) { 79| 328k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 12) % 16] + 0xca62c1d6 + rol(a[(4 + i) % 5], 5); 81| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi7EEEvPjS3_: 78| 328k| static inline void f(uint32_t *a, uint32_t *b) { 79| 328k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 12) % 16] + 0xca62c1d6 + rol(a[(4 + i) % 5], 5); 81| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi8EEEvPjS3_: 78| 328k| static inline void f(uint32_t *a, uint32_t *b) { 79| 328k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 12) % 16] + 0xca62c1d6 + rol(a[(4 + i) % 5], 5); 81| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi9EEEvPjS3_: 78| 328k| static inline void f(uint32_t *a, uint32_t *b) { 79| 328k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 12) % 16] + 0xca62c1d6 + rol(a[(4 + i) % 5], 5); 81| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi10EEEvPjS3_: 78| 328k| static inline void f(uint32_t *a, uint32_t *b) { 79| 328k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 12) % 16] + 0xca62c1d6 + rol(a[(4 + i) % 5], 5); 81| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi11EEEvPjS3_: 78| 328k| static inline void f(uint32_t *a, uint32_t *b) { 79| 328k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 12) % 16] + 0xca62c1d6 + rol(a[(4 + i) % 5], 5); 81| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi12EEEvPjS3_: 78| 328k| static inline void f(uint32_t *a, uint32_t *b) { 79| 328k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 12) % 16] + 0xca62c1d6 + rol(a[(4 + i) % 5], 5); 81| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi13EEEvPjS3_: 78| 328k| static inline void f(uint32_t *a, uint32_t *b) { 79| 328k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 12) % 16] + 0xca62c1d6 + rol(a[(4 + i) % 5], 5); 81| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi14EEEvPjS3_: 78| 328k| static inline void f(uint32_t *a, uint32_t *b) { 79| 328k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 12) % 16] + 0xca62c1d6 + rol(a[(4 + i) % 5], 5); 81| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi15EEEvPjS3_: 78| 328k| static inline void f(uint32_t *a, uint32_t *b) { 79| 328k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 12) % 16] + 0xca62c1d6 + rol(a[(4 + i) % 5], 5); 81| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi16EEEvPjS3_: 78| 328k| static inline void f(uint32_t *a, uint32_t *b) { 79| 328k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 12) % 16] + 0xca62c1d6 + rol(a[(4 + i) % 5], 5); 81| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi17EEEvPjS3_: 78| 328k| static inline void f(uint32_t *a, uint32_t *b) { 79| 328k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 12) % 16] + 0xca62c1d6 + rol(a[(4 + i) % 5], 5); 81| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi18EEEvPjS3_: 78| 328k| static inline void f(uint32_t *a, uint32_t *b) { 79| 328k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 12) % 16] + 0xca62c1d6 + rol(a[(4 + i) % 5], 5); 81| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi19EEEvPjS3_: 78| 328k| static inline void f(uint32_t *a, uint32_t *b) { 79| 328k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 328k| a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + b[(i + 12) % 16] + 0xca62c1d6 + rol(a[(4 + i) % 5], 5); 81| 328k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi5ENS0_9Sha1Loop6EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi4ENS0_9Sha1Loop6EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi3ENS0_9Sha1Loop6EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi2ENS0_9Sha1Loop6EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi1ENS0_9Sha1Loop6EEclEPjS4_: 29| 328k| void operator()(uint32_t *a, uint32_t *b) { 30| 328k| static_for()(a, b); 31| 328k| T::template f(a, b); 32| 328k| } _ZN3uWS18WebSocketHandshake10static_forILi0ENS0_9Sha1Loop6EEclEPjS4_: 37| 328k| void operator()(uint32_t */*a*/, uint32_t */*hash*/) {} _ZN3uWS18WebSocketHandshake9Sha1Loop61fILi0EEEvPjS3_: 86| 328k| static inline void f(uint32_t *a, uint32_t *b) { 87| 328k| b[i] += a[4 - i]; 88| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop61fILi1EEEvPjS3_: 86| 328k| static inline void f(uint32_t *a, uint32_t *b) { 87| 328k| b[i] += a[4 - i]; 88| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop61fILi2EEEvPjS3_: 86| 328k| static inline void f(uint32_t *a, uint32_t *b) { 87| 328k| b[i] += a[4 - i]; 88| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop61fILi3EEEvPjS3_: 86| 328k| static inline void f(uint32_t *a, uint32_t *b) { 87| 328k| b[i] += a[4 - i]; 88| 328k| } _ZN3uWS18WebSocketHandshake9Sha1Loop61fILi4EEEvPjS3_: 86| 328k| static inline void f(uint32_t *a, uint32_t *b) { 87| 328k| b[i] += a[4 - i]; 88| 328k| } _ZN3uWS18WebSocketHandshake6base64EPhPc: 101| 164k| static inline void base64(unsigned char *src, char *dst) { 102| 164k| const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 103| 1.14M| for (int i = 0; i < 18; i += 3) { ------------------ | Branch (103:25): [True: 985k, False: 164k] ------------------ 104| 985k| *dst++ = b64[(src[i] >> 2) & 63]; 105| 985k| *dst++ = b64[((src[i] & 3) << 4) | ((src[i + 1] & 240) >> 4)]; 106| 985k| *dst++ = b64[((src[i + 1] & 15) << 2) | ((src[i + 2] & 192) >> 6)]; 107| 985k| *dst++ = b64[src[i + 2] & 63]; 108| 985k| } 109| 164k| *dst++ = b64[(src[18] >> 2) & 63]; 110| 164k| *dst++ = b64[((src[18] & 3) << 4) | ((src[19] & 240) >> 4)]; 111| 164k| *dst++ = b64[((src[19] & 15) << 2)]; 112| 164k| *dst++ = '='; 113| 164k| } EpollEchoServer.cpp:_ZN3uWS8protocolL13formatMessageILb1EEEmPcPKcmNS_6OpCodeEmbb: 209| 62.5k|static inline size_t formatMessage(char *dst, const char *src, size_t length, OpCode opCode, size_t reportedLength, bool compressed, bool fin) { 210| 62.5k| size_t messageLength; 211| 62.5k| size_t headerLength; 212| 62.5k| if (reportedLength < 126) { ------------------ | Branch (212:9): [True: 61.8k, False: 655] ------------------ 213| 61.8k| headerLength = 2; 214| 61.8k| dst[1] = (char) reportedLength; 215| 61.8k| } else if (reportedLength <= UINT16_MAX) { ------------------ | Branch (215:16): [True: 655, False: 0] ------------------ 216| 655| headerLength = 4; 217| 655| dst[1] = 126; 218| 655| uint16_t tmp = cond_byte_swap((uint16_t) reportedLength); 219| 655| memcpy(&dst[2], &tmp, sizeof(uint16_t)); 220| 655| } else { 221| 0| headerLength = 10; 222| 0| dst[1] = 127; 223| 0| uint64_t tmp = cond_byte_swap((uint64_t) reportedLength); 224| 0| memcpy(&dst[2], &tmp, sizeof(uint64_t)); 225| 0| } 226| | 227| 62.5k| dst[0] = (char) ((fin ? 128 : 0) | ((compressed && opCode) ? SND_COMPRESSED : 0) | (char) opCode); ------------------ | Branch (227:23): [True: 62.5k, False: 0] | Branch (227:42): [True: 3.34k, False: 59.1k] | Branch (227:56): [True: 3.34k, False: 0] ------------------ 228| | 229| | //printf("%d\n", (int)dst[0]); 230| | 231| 62.5k| char mask[4]; 232| 62.5k| if (!isServer) { ------------------ | Branch (232:9): [Folded - Ignored] ------------------ 233| 0| dst[1] |= 0x80; 234| 0| uint32_t random = (uint32_t) rand(); 235| 0| memcpy(mask, &random, 4); 236| 0| memcpy(dst + headerLength, &random, 4); 237| 0| headerLength += 4; 238| 0| } 239| | 240| 62.5k| messageLength = headerLength + length; 241| 62.5k| memcpy(dst + headerLength, src, length); 242| | 243| 62.5k| if (!isServer) { ------------------ | Branch (243:9): [Folded - Ignored] ------------------ 244| | 245| | // overwrites up to 3 bytes outside of the given buffer! 246| | //WebSocketProtocol::unmaskInplace(dst + headerLength, dst + headerLength + length, mask); 247| | 248| | // this is not optimal 249| 0| char *start = dst + headerLength; 250| 0| char *stop = start + length; 251| 0| int i = 0; 252| 0| while (start != stop) { ------------------ | Branch (252:16): [True: 0, False: 0] ------------------ 253| 0| (*start++) ^= mask[i++ % 4]; 254| 0| } 255| 0| } 256| 62.5k| return messageLength; 257| 62.5k|} _ZN3uWS8protocol14cond_byte_swapItEET_S2_: 95| 13.0k|T cond_byte_swap(T value) { 96| 13.0k| uint32_t endian_test = 1; 97| 13.0k| if (*((char *)&endian_test)) { ------------------ | Branch (97:9): [True: 13.0k, False: 0] ------------------ 98| 13.0k| union { 99| 13.0k| T i; 100| 13.0k| uint8_t b[sizeof(T)]; 101| 13.0k| } src = { value }, dst; 102| | 103| 39.2k| for (unsigned int i = 0; i < sizeof(value); i++) { ------------------ | Branch (103:34): [True: 26.1k, False: 13.0k] ------------------ 104| 26.1k| dst.b[i] = src.b[sizeof(value) - 1 - i]; 105| 26.1k| } 106| | 107| 13.0k| return dst.i; 108| 13.0k| } 109| 0| return value; 110| 13.0k|} _ZN3uWS8protocol14cond_byte_swapImEET_S2_: 95| 5.85k|T cond_byte_swap(T value) { 96| 5.85k| uint32_t endian_test = 1; 97| 5.85k| if (*((char *)&endian_test)) { ------------------ | Branch (97:9): [True: 5.85k, False: 0] ------------------ 98| 5.85k| union { 99| 5.85k| T i; 100| 5.85k| uint8_t b[sizeof(T)]; 101| 5.85k| } src = { value }, dst; 102| | 103| 52.6k| for (unsigned int i = 0; i < sizeof(value); i++) { ------------------ | Branch (103:34): [True: 46.8k, False: 5.85k] ------------------ 104| 46.8k| dst.b[i] = src.b[sizeof(value) - 1 - i]; 105| 46.8k| } 106| | 107| 5.85k| return dst.i; 108| 5.85k| } 109| 0| return value; 110| 5.85k|} EpollEchoServer.cpp:_ZN3uWS8protocolL16messageFrameSizeEm: 193| 62.5k|static inline size_t messageFrameSize(size_t messageSize) { 194| 62.5k| if (messageSize < 126) { ------------------ | Branch (194:9): [True: 61.8k, False: 655] ------------------ 195| 61.8k| return 2 + messageSize; 196| 61.8k| } else if (messageSize <= UINT16_MAX) { ------------------ | Branch (196:16): [True: 655, False: 0] ------------------ 197| 655| return 4 + messageSize; 198| 655| } 199| 0| return 10 + messageSize; 200| 62.5k|} EpollEchoServer.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataEEE7consumeEPcjPNS_14WebSocketStateILb1EEEPv: 458| 45.3k| static inline void consume(char *src, unsigned int length, WebSocketState *wState, void *user) { 459| 45.3k| if (wState->state.spillLength) { ------------------ | Branch (459:13): [True: 2.13k, False: 43.2k] ------------------ 460| 2.13k| src -= wState->state.spillLength; 461| 2.13k| length += wState->state.spillLength; 462| 2.13k| memcpy(src, wState->state.spill, wState->state.spillLength); 463| 2.13k| } 464| 45.3k| if (wState->state.wantsHead) { ------------------ | Branch (464:13): [True: 36.2k, False: 9.13k] ------------------ 465| 41.2k| parseNext: 466| 98.6k| while (length >= SHORT_MESSAGE_HEADER) { ------------------ | Branch (466:20): [True: 92.7k, False: 5.94k] ------------------ 467| | 468| | // invalid reserved bits / invalid opcodes / invalid control frames / set compressed frame 469| 92.7k| if ((rsv1(src) && !Impl::setCompressed(wState, user)) || rsv23(src) || (getOpCode(src) > 2 && getOpCode(src) < 8) || ------------------ | Branch (469:22): [True: 9.76k, False: 82.9k] | Branch (469:35): [True: 7.68k, False: 2.07k] | Branch (469:74): [True: 4.31k, False: 80.7k] | Branch (469:89): [True: 21.4k, False: 59.3k] | Branch (469:111): [True: 401, False: 21.0k] ------------------ 470| 92.7k| getOpCode(src) > 10 || (getOpCode(src) > 2 && (!isFin(src) || payloadLength(src) > 125))) { ------------------ | Branch (470:21): [True: 540, False: 79.7k] | Branch (470:45): [True: 20.4k, False: 59.3k] | Branch (470:68): [True: 452, False: 20.0k] | Branch (470:83): [True: 286, False: 19.7k] ------------------ 471| 13.6k| Impl::forceClose(wState, user); 472| 13.6k| return; 473| 13.6k| } 474| | 475| 79.0k| if (payloadLength(src) < 126) { ------------------ | Branch (475:21): [True: 66.3k, False: 12.6k] ------------------ 476| 66.3k| if (consumeMessage(payloadLength(src), src, length, wState, user)) { ------------------ | Branch (476:25): [True: 13.6k, False: 52.7k] ------------------ 477| 13.6k| return; 478| 13.6k| } 479| 66.3k| } else if (payloadLength(src) == 126) { ------------------ | Branch (479:28): [True: 6.44k, False: 6.20k] ------------------ 480| 6.44k| if (length < MEDIUM_MESSAGE_HEADER) { ------------------ | Branch (480:25): [True: 509, False: 5.93k] ------------------ 481| 509| break; 482| 5.93k| } else if(consumeMessage(protocol::cond_byte_swap(protocol::bit_cast(src + 2)), src, length, wState, user)) { ------------------ | Branch (482:31): [True: 3.55k, False: 2.38k] ------------------ 483| 3.55k| return; 484| 3.55k| } 485| 6.44k| } else if (length < LONG_MESSAGE_HEADER) { ------------------ | Branch (485:28): [True: 350, False: 5.85k] ------------------ 486| 350| break; 487| 5.85k| } else if (consumeMessage(protocol::cond_byte_swap(protocol::bit_cast(src + 2)), src, length, wState, user)) { ------------------ | Branch (487:28): [True: 3.60k, False: 2.24k] ------------------ 488| 3.60k| return; 489| 3.60k| } 490| 79.0k| } 491| 6.80k| if (length) { ------------------ | Branch (491:17): [True: 4.66k, False: 2.13k] ------------------ 492| 4.66k| memcpy(wState->state.spill, src, length); 493| 4.66k| wState->state.spillLength = length & 0xf; 494| 4.66k| } 495| 9.13k| } else if (consumeContinuation(src, length, wState, user)) { ------------------ | Branch (495:20): [True: 5.04k, False: 4.09k] ------------------ 496| 5.04k| goto parseNext; 497| 5.04k| } 498| 45.3k| } EpollEchoServer.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataEEE4rsv1EPc: 274| 92.7k| static inline bool rsv1(char *frame) {return *((unsigned char *) frame) & 64;} EpollEchoServer.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataEEE5rsv23EPc: 273| 85.0k| static inline bool rsv23(char *frame) {return *((unsigned char *) frame) & 48;} EpollEchoServer.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataEEE9getOpCodeEPc: 271| 413k| static inline unsigned char getOpCode(char *frame) {return *((unsigned char *) frame) & 15;} EpollEchoServer.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataEEE5isFinEPc: 270| 169k| static inline bool isFin(char *frame) {return *((unsigned char *) frame) & 128;} EpollEchoServer.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataEEE13payloadLengthEPc: 272| 178k| static inline unsigned char payloadLength(char *frame) {return ((unsigned char *) frame)[1] & 127;} EpollEchoServer.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataEEE14consumeMessageILj6EhEEbT0_RPcRjPNS_14WebSocketStateILb1EEEPv: 340| 66.3k| static inline bool consumeMessage(T payLength, char *&src, unsigned int &length, WebSocketState *wState, void *user) { 341| 66.3k| if (getOpCode(src)) { ------------------ | Branch (341:13): [True: 61.6k, False: 4.72k] ------------------ 342| 61.6k| if (wState->state.opStack == 1 || (!wState->state.lastFin && getOpCode(src) < 2)) { ------------------ | Branch (342:17): [True: 213, False: 61.4k] | Branch (342:48): [True: 1.94k, False: 59.4k] | Branch (342:74): [True: 218, False: 1.73k] ------------------ 343| 431| Impl::forceClose(wState, user); 344| 431| return true; 345| 431| } 346| 61.2k| wState->state.opCode[++wState->state.opStack] = (OpCode) getOpCode(src); 347| 61.2k| } else if (wState->state.opStack == -1) { ------------------ | Branch (347:20): [True: 1.03k, False: 3.69k] ------------------ 348| 1.03k| Impl::forceClose(wState, user); 349| 1.03k| return true; 350| 1.03k| } 351| 64.9k| wState->state.lastFin = isFin(src); 352| | 353| 64.9k| if (Impl::refusePayloadLength(payLength, wState, user)) { ------------------ | Branch (353:13): [True: 0, False: 64.9k] ------------------ 354| 0| Impl::forceClose(wState, user, ERR_TOO_BIG_MESSAGE); 355| 0| return true; 356| 0| } 357| | 358| 64.9k| if (payLength + MESSAGE_HEADER <= length) { ------------------ | Branch (358:13): [True: 57.8k, False: 7.08k] ------------------ 359| 57.8k| bool fin = isFin(src); 360| 57.8k| if (isServer) { ------------------ | Branch (360:17): [Folded - Ignored] ------------------ 361| | /* This guy can never be assumed to be perfectly aligned since we can get multiple messages in one read */ 362| 57.8k| unmaskImpreciseCopyMask(src + MESSAGE_HEADER, (unsigned int) payLength); 363| 57.8k| if (Impl::handleFragment(src, payLength, 0, wState->state.opCode[wState->state.opStack], fin, wState, user)) { ------------------ | Branch (363:21): [True: 5.08k, False: 52.7k] ------------------ 364| 5.08k| return true; 365| 5.08k| } 366| 57.8k| } else { 367| 0| if (Impl::handleFragment(src + MESSAGE_HEADER, payLength, 0, wState->state.opCode[wState->state.opStack], isFin(src), wState, user)) { ------------------ | Branch (367:21): [True: 0, False: 0] ------------------ 368| 0| return true; 369| 0| } 370| 0| } 371| | 372| 52.7k| if (fin) { ------------------ | Branch (372:17): [True: 45.9k, False: 6.80k] ------------------ 373| 45.9k| wState->state.opStack--; 374| 45.9k| } 375| | 376| 52.7k| src += payLength + MESSAGE_HEADER; 377| 52.7k| length -= (unsigned int) (payLength + MESSAGE_HEADER); 378| 52.7k| wState->state.spillLength = 0; 379| 52.7k| return false; 380| 57.8k| } else { 381| 7.08k| wState->state.spillLength = 0; 382| 7.08k| wState->state.wantsHead = false; 383| 7.08k| wState->remainingBytes = (unsigned int) (payLength - length + MESSAGE_HEADER); 384| 7.08k| bool fin = isFin(src); 385| 7.08k| if constexpr (isServer) { ------------------ | Branch (385:27): [Folded - Ignored] ------------------ 386| 7.08k| memcpy(wState->mask, src + MESSAGE_HEADER - 4, 4); 387| 7.08k| uint64_t mask; 388| 7.08k| memcpy(&mask, src + MESSAGE_HEADER - 4, 4); 389| 7.08k| memcpy(((char *)&mask) + 4, src + MESSAGE_HEADER - 4, 4); 390| 7.08k| unmaskImprecise8<0>(src + MESSAGE_HEADER, mask, length); 391| 7.08k| rotateMask(4 - (length - MESSAGE_HEADER) % 4, wState->mask); 392| 7.08k| } 393| 7.08k| Impl::handleFragment(src + MESSAGE_HEADER, length - MESSAGE_HEADER, wState->remainingBytes, wState->state.opCode[wState->state.opStack], fin, wState, user); 394| 7.08k| return true; 395| 7.08k| } 396| 64.9k| } EpollEchoServer.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataEEE23unmaskImpreciseCopyMaskILi6EEEvPcj: 308| 57.8k| static inline void unmaskImpreciseCopyMask(char *src, unsigned int length) { 309| 57.8k| if constexpr (HEADER_SIZE != 6) { ------------------ | Branch (309:23): [Folded - Ignored] ------------------ 310| 57.8k| char mask[8] = {src[-4], src[-3], src[-2], src[-1], src[-4], src[-3], src[-2], src[-1]}; 311| 57.8k| uint64_t maskInt; 312| 57.8k| memcpy(&maskInt, mask, 8); 313| 57.8k| unmaskImprecise8(src, maskInt, length); 314| 57.8k| } else { 315| 57.8k| char mask[4] = {src[-4], src[-3], src[-2], src[-1]}; 316| 57.8k| uint32_t maskInt; 317| 57.8k| memcpy(&maskInt, mask, 4); 318| 57.8k| unmaskImprecise4(src, maskInt, length); 319| 57.8k| } 320| 57.8k| } EpollEchoServer.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataEEE16unmaskImprecise4ILi6EEEvPcjj: 297| 57.8k| static inline void unmaskImprecise4(char *src, uint32_t mask, unsigned int length) { 298| 190k| for (unsigned int n = (length >> 2) + 1; n; n--) { ------------------ | Branch (298:50): [True: 132k, False: 57.8k] ------------------ 299| 132k| uint32_t loaded; 300| 132k| memcpy(&loaded, src, 4); 301| 132k| loaded ^= mask; 302| 132k| memcpy(src - DESTINATION, &loaded, 4); 303| 132k| src += 4; 304| 132k| } 305| 57.8k| } EpollEchoServer.cpp:_ZN3uWS8protocolL11isValidUtf8EPhm: 117| 35.3k|{ 118| 92.2k| for (unsigned char *e = s + length; s != e; ) { ------------------ | Branch (118:41): [True: 90.8k, False: 1.44k] ------------------ 119| 90.8k| if (s + 4 <= e) { ------------------ | Branch (119:13): [True: 60.2k, False: 30.5k] ------------------ 120| 60.2k| uint32_t tmp; 121| 60.2k| memcpy(&tmp, s, 4); 122| 60.2k| if ((tmp & 0x80808080) == 0) { ------------------ | Branch (122:17): [True: 54.8k, False: 5.36k] ------------------ 123| 54.8k| s += 4; 124| 54.8k| continue; 125| 54.8k| } 126| 60.2k| } 127| | 128| 44.8k| while (!(*s & 0x80)) { ------------------ | Branch (128:16): [True: 38.2k, False: 6.61k] ------------------ 129| 38.2k| if (++s == e) { ------------------ | Branch (129:17): [True: 29.3k, False: 8.86k] ------------------ 130| 29.3k| return true; 131| 29.3k| } 132| 38.2k| } 133| | 134| 6.61k| if ((s[0] & 0x60) == 0x40) { ------------------ | Branch (134:13): [True: 1.06k, False: 5.55k] ------------------ 135| 1.06k| if (s + 1 >= e || (s[1] & 0xc0) != 0x80 || (s[0] & 0xfe) == 0xc0) { ------------------ | Branch (135:17): [True: 223, False: 841] | Branch (135:31): [True: 260, False: 581] | Branch (135:56): [True: 196, False: 385] ------------------ 136| 679| return false; 137| 679| } 138| 385| s += 2; 139| 5.55k| } else if ((s[0] & 0xf0) == 0xe0) { ------------------ | Branch (139:20): [True: 1.70k, False: 3.84k] ------------------ 140| 1.70k| if (s + 2 >= e || (s[1] & 0xc0) != 0x80 || (s[2] & 0xc0) != 0x80 || ------------------ | Branch (140:17): [True: 246, False: 1.46k] | Branch (140:31): [True: 237, False: 1.22k] | Branch (140:56): [True: 209, False: 1.01k] ------------------ 141| 1.70k| (s[0] == 0xe0 && (s[1] & 0xe0) == 0x80) || (s[0] == 0xed && (s[1] & 0xe0) == 0xa0)) { ------------------ | Branch (141:22): [True: 393, False: 624] | Branch (141:38): [True: 196, False: 197] | Branch (141:65): [True: 394, False: 427] | Branch (141:81): [True: 195, False: 199] ------------------ 142| 1.08k| return false; 143| 1.08k| } 144| 626| s += 3; 145| 3.84k| } else if ((s[0] & 0xf8) == 0xf0) { ------------------ | Branch (145:20): [True: 2.48k, False: 1.35k] ------------------ 146| 2.48k| if (s + 3 >= e || (s[1] & 0xc0) != 0x80 || (s[2] & 0xc0) != 0x80 || (s[3] & 0xc0) != 0x80 || ------------------ | Branch (146:17): [True: 237, False: 2.25k] | Branch (146:31): [True: 207, False: 2.04k] | Branch (146:56): [True: 200, False: 1.84k] | Branch (146:81): [True: 199, False: 1.64k] ------------------ 147| 2.48k| (s[0] == 0xf0 && (s[1] & 0xf0) == 0x80) || (s[0] == 0xf4 && s[1] > 0x8f) || s[0] > 0xf4) { ------------------ | Branch (147:22): [True: 819, False: 825] | Branch (147:38): [True: 197, False: 622] | Branch (147:65): [True: 414, False: 1.03k] | Branch (147:81): [True: 217, False: 197] | Branch (147:97): [True: 195, False: 1.03k] ------------------ 148| 1.45k| return false; 149| 1.45k| } 150| 1.03k| s += 4; 151| 1.35k| } else { 152| 1.35k| return false; 153| 1.35k| } 154| 6.61k| } 155| 1.44k| return true; 156| 35.3k|} EpollEchoServer.cpp:_ZN3uWS8protocolL17parseClosePayloadEPcm: 164| 4.48k|static inline CloseFrame parseClosePayload(char *src, size_t length) { 165| | /* If we get no code or message, default to reporting 1005 no status code present */ 166| 4.48k| CloseFrame cf = {1005, nullptr, 0}; 167| 4.48k| if (length >= 2) { ------------------ | Branch (167:9): [True: 4.25k, False: 231] ------------------ 168| 4.25k| memcpy(&cf.code, src, 2); 169| 4.25k| cf = {cond_byte_swap(cf.code), src + 2, length - 2}; 170| 4.25k| if (cf.code < 1000 || cf.code > 4999 || (cf.code > 1011 && cf.code < 4000) || ------------------ | Branch (170:13): [True: 416, False: 3.83k] | Branch (170:31): [True: 692, False: 3.14k] | Branch (170:50): [True: 1.78k, False: 1.35k] | Branch (170:68): [True: 415, False: 1.37k] ------------------ 171| 4.25k| (cf.code >= 1004 && cf.code <= 1006) || !isValidUtf8((unsigned char *) cf.message, cf.length)) { ------------------ | Branch (171:14): [True: 2.28k, False: 441] | Branch (171:33): [True: 520, False: 1.76k] | Branch (171:53): [True: 1.47k, False: 733] ------------------ 172| | /* Even though we got a WebSocket close frame, it in itself is abnormal */ 173| 3.51k| return {1006, nullptr, 0}; 174| 3.51k| } 175| 4.25k| } 176| 964| return cf; 177| 4.48k|} EpollEchoServer.cpp:_ZN3uWS8protocolL18formatClosePayloadEPctPKcm: 179| 6.58k|static inline size_t formatClosePayload(char *dst, uint16_t code, const char *message, size_t length) { 180| | /* We could have more strict checks here, but never append code 0 or 1005 or 1006 */ 181| 6.58k| if (code && code != 1005 && code != 1006) { ------------------ | Branch (181:9): [True: 6.58k, False: 0] | Branch (181:17): [True: 6.35k, False: 231] | Branch (181:33): [True: 2.24k, False: 4.11k] ------------------ 182| 2.24k| code = cond_byte_swap(code); 183| 2.24k| memcpy(dst, &code, 2); 184| | /* It is invalid to pass nullptr to memcpy, even though length is 0 */ 185| 2.24k| if (message) { ------------------ | Branch (185:13): [True: 733, False: 1.50k] ------------------ 186| 733| memcpy(dst + 2, message, length); 187| 733| } 188| 2.24k| return length + 2; 189| 2.24k| } 190| 4.34k| return 0; 191| 6.58k|} EpollEchoServer.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataEEE16unmaskImprecise8ILi0EEEvPcmj: 285| 10.3k| static inline void unmaskImprecise8(char *src, uint64_t mask, unsigned int length) { 286| 55.6k| for (unsigned int n = (length >> 3) + 1; n; n--) { ------------------ | Branch (286:50): [True: 45.2k, False: 10.3k] ------------------ 287| 45.2k| uint64_t loaded; 288| 45.2k| memcpy(&loaded, src, 8); 289| 45.2k| loaded ^= mask; 290| 45.2k| memcpy(src - DESTINATION, &loaded, 8); 291| 45.2k| src += 8; 292| 45.2k| } 293| 10.3k| } EpollEchoServer.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataEEE10rotateMaskEjPc: 322| 11.5k| static inline void rotateMask(unsigned int offset, char *mask) { 323| 11.5k| char originalMask[4] = {mask[0], mask[1], mask[2], mask[3]}; 324| 11.5k| mask[(0 + offset) % 4] = originalMask[0]; 325| 11.5k| mask[(1 + offset) % 4] = originalMask[1]; 326| 11.5k| mask[(2 + offset) % 4] = originalMask[2]; 327| 11.5k| mask[(3 + offset) % 4] = originalMask[3]; 328| 11.5k| } EpollEchoServer.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataEEE14consumeMessageILj8EtEEbT0_RPcRjPNS_14WebSocketStateILb1EEEPv: 340| 5.93k| static inline bool consumeMessage(T payLength, char *&src, unsigned int &length, WebSocketState *wState, void *user) { 341| 5.93k| if (getOpCode(src)) { ------------------ | Branch (341:13): [True: 4.41k, False: 1.52k] ------------------ 342| 4.41k| if (wState->state.opStack == 1 || (!wState->state.lastFin && getOpCode(src) < 2)) { ------------------ | Branch (342:17): [True: 194, False: 4.22k] | Branch (342:48): [True: 738, False: 3.48k] | Branch (342:74): [True: 195, False: 543] ------------------ 343| 389| Impl::forceClose(wState, user); 344| 389| return true; 345| 389| } 346| 4.02k| wState->state.opCode[++wState->state.opStack] = (OpCode) getOpCode(src); 347| 4.02k| } else if (wState->state.opStack == -1) { ------------------ | Branch (347:20): [True: 204, False: 1.31k] ------------------ 348| 204| Impl::forceClose(wState, user); 349| 204| return true; 350| 204| } 351| 5.34k| wState->state.lastFin = isFin(src); 352| | 353| 5.34k| if (Impl::refusePayloadLength(payLength, wState, user)) { ------------------ | Branch (353:13): [True: 223, False: 5.12k] ------------------ 354| 223| Impl::forceClose(wState, user, ERR_TOO_BIG_MESSAGE); 355| 223| return true; 356| 223| } 357| | 358| 5.12k| if (payLength + MESSAGE_HEADER <= length) { ------------------ | Branch (358:13): [True: 3.20k, False: 1.91k] ------------------ 359| 3.20k| bool fin = isFin(src); 360| 3.20k| if (isServer) { ------------------ | Branch (360:17): [Folded - Ignored] ------------------ 361| | /* This guy can never be assumed to be perfectly aligned since we can get multiple messages in one read */ 362| 3.20k| unmaskImpreciseCopyMask(src + MESSAGE_HEADER, (unsigned int) payLength); 363| 3.20k| if (Impl::handleFragment(src, payLength, 0, wState->state.opCode[wState->state.opStack], fin, wState, user)) { ------------------ | Branch (363:21): [True: 824, False: 2.38k] ------------------ 364| 824| return true; 365| 824| } 366| 3.20k| } else { 367| 0| if (Impl::handleFragment(src + MESSAGE_HEADER, payLength, 0, wState->state.opCode[wState->state.opStack], isFin(src), wState, user)) { ------------------ | Branch (367:21): [True: 0, False: 0] ------------------ 368| 0| return true; 369| 0| } 370| 0| } 371| | 372| 2.38k| if (fin) { ------------------ | Branch (372:17): [True: 1.07k, False: 1.31k] ------------------ 373| 1.07k| wState->state.opStack--; 374| 1.07k| } 375| | 376| 2.38k| src += payLength + MESSAGE_HEADER; 377| 2.38k| length -= (unsigned int) (payLength + MESSAGE_HEADER); 378| 2.38k| wState->state.spillLength = 0; 379| 2.38k| return false; 380| 3.20k| } else { 381| 1.91k| wState->state.spillLength = 0; 382| 1.91k| wState->state.wantsHead = false; 383| 1.91k| wState->remainingBytes = (unsigned int) (payLength - length + MESSAGE_HEADER); 384| 1.91k| bool fin = isFin(src); 385| 1.91k| if constexpr (isServer) { ------------------ | Branch (385:27): [Folded - Ignored] ------------------ 386| 1.91k| memcpy(wState->mask, src + MESSAGE_HEADER - 4, 4); 387| 1.91k| uint64_t mask; 388| 1.91k| memcpy(&mask, src + MESSAGE_HEADER - 4, 4); 389| 1.91k| memcpy(((char *)&mask) + 4, src + MESSAGE_HEADER - 4, 4); 390| 1.91k| unmaskImprecise8<0>(src + MESSAGE_HEADER, mask, length); 391| 1.91k| rotateMask(4 - (length - MESSAGE_HEADER) % 4, wState->mask); 392| 1.91k| } 393| 1.91k| Impl::handleFragment(src + MESSAGE_HEADER, length - MESSAGE_HEADER, wState->remainingBytes, wState->state.opCode[wState->state.opStack], fin, wState, user); 394| 1.91k| return true; 395| 1.91k| } 396| 5.12k| } EpollEchoServer.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataEEE23unmaskImpreciseCopyMaskILi8EEEvPcj: 308| 3.20k| static inline void unmaskImpreciseCopyMask(char *src, unsigned int length) { 309| 3.20k| if constexpr (HEADER_SIZE != 6) { ------------------ | Branch (309:23): [Folded - Ignored] ------------------ 310| 3.20k| char mask[8] = {src[-4], src[-3], src[-2], src[-1], src[-4], src[-3], src[-2], src[-1]}; 311| 3.20k| uint64_t maskInt; 312| 3.20k| memcpy(&maskInt, mask, 8); 313| 3.20k| unmaskImprecise8(src, maskInt, length); 314| 3.20k| } else { 315| 3.20k| char mask[4] = {src[-4], src[-3], src[-2], src[-1]}; 316| 3.20k| uint32_t maskInt; 317| 3.20k| memcpy(&maskInt, mask, 4); 318| 3.20k| unmaskImprecise4(src, maskInt, length); 319| 3.20k| } 320| 3.20k| } EpollEchoServer.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataEEE16unmaskImprecise8ILi8EEEvPcmj: 285| 3.20k| static inline void unmaskImprecise8(char *src, uint64_t mask, unsigned int length) { 286| 18.6k| for (unsigned int n = (length >> 3) + 1; n; n--) { ------------------ | Branch (286:50): [True: 15.4k, False: 3.20k] ------------------ 287| 15.4k| uint64_t loaded; 288| 15.4k| memcpy(&loaded, src, 8); 289| 15.4k| loaded ^= mask; 290| 15.4k| memcpy(src - DESTINATION, &loaded, 8); 291| 15.4k| src += 8; 292| 15.4k| } 293| 3.20k| } _ZN3uWS8protocol8bit_castItEET_Pc: 87| 5.93k|T bit_cast(char *c) { 88| 5.93k| T val; 89| 5.93k| memcpy(&val, c, sizeof(T)); 90| 5.93k| return val; 91| 5.93k|} EpollEchoServer.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataEEE14consumeMessageILj14EmEEbT0_RPcRjPNS_14WebSocketStateILb1EEEPv: 340| 5.85k| static inline bool consumeMessage(T payLength, char *&src, unsigned int &length, WebSocketState *wState, void *user) { 341| 5.85k| if (getOpCode(src)) { ------------------ | Branch (341:13): [True: 4.49k, False: 1.35k] ------------------ 342| 4.49k| if (wState->state.opStack == 1 || (!wState->state.lastFin && getOpCode(src) < 2)) { ------------------ | Branch (342:17): [True: 222, False: 4.27k] | Branch (342:48): [True: 1.29k, False: 2.97k] | Branch (342:74): [True: 578, False: 716] ------------------ 343| 800| Impl::forceClose(wState, user); 344| 800| return true; 345| 800| } 346| 3.69k| wState->state.opCode[++wState->state.opStack] = (OpCode) getOpCode(src); 347| 3.69k| } else if (wState->state.opStack == -1) { ------------------ | Branch (347:20): [True: 196, False: 1.16k] ------------------ 348| 196| Impl::forceClose(wState, user); 349| 196| return true; 350| 196| } 351| 4.85k| wState->state.lastFin = isFin(src); 352| | 353| 4.85k| if (Impl::refusePayloadLength(payLength, wState, user)) { ------------------ | Branch (353:13): [True: 764, False: 4.09k] ------------------ 354| 764| Impl::forceClose(wState, user, ERR_TOO_BIG_MESSAGE); 355| 764| return true; 356| 764| } 357| | 358| 4.09k| if (payLength + MESSAGE_HEADER <= length) { ------------------ | Branch (358:13): [True: 2.74k, False: 1.35k] ------------------ 359| 2.74k| bool fin = isFin(src); 360| 2.74k| if (isServer) { ------------------ | Branch (360:17): [Folded - Ignored] ------------------ 361| | /* This guy can never be assumed to be perfectly aligned since we can get multiple messages in one read */ 362| 2.74k| unmaskImpreciseCopyMask(src + MESSAGE_HEADER, (unsigned int) payLength); 363| 2.74k| if (Impl::handleFragment(src, payLength, 0, wState->state.opCode[wState->state.opStack], fin, wState, user)) { ------------------ | Branch (363:21): [True: 497, False: 2.24k] ------------------ 364| 497| return true; 365| 497| } 366| 2.74k| } else { 367| 0| if (Impl::handleFragment(src + MESSAGE_HEADER, payLength, 0, wState->state.opCode[wState->state.opStack], isFin(src), wState, user)) { ------------------ | Branch (367:21): [True: 0, False: 0] ------------------ 368| 0| return true; 369| 0| } 370| 0| } 371| | 372| 2.24k| if (fin) { ------------------ | Branch (372:17): [True: 1.16k, False: 1.07k] ------------------ 373| 1.16k| wState->state.opStack--; 374| 1.16k| } 375| | 376| 2.24k| src += payLength + MESSAGE_HEADER; 377| 2.24k| length -= (unsigned int) (payLength + MESSAGE_HEADER); 378| 2.24k| wState->state.spillLength = 0; 379| 2.24k| return false; 380| 2.74k| } else { 381| 1.35k| wState->state.spillLength = 0; 382| 1.35k| wState->state.wantsHead = false; 383| 1.35k| wState->remainingBytes = (unsigned int) (payLength - length + MESSAGE_HEADER); 384| 1.35k| bool fin = isFin(src); 385| 1.35k| if constexpr (isServer) { ------------------ | Branch (385:27): [Folded - Ignored] ------------------ 386| 1.35k| memcpy(wState->mask, src + MESSAGE_HEADER - 4, 4); 387| 1.35k| uint64_t mask; 388| 1.35k| memcpy(&mask, src + MESSAGE_HEADER - 4, 4); 389| 1.35k| memcpy(((char *)&mask) + 4, src + MESSAGE_HEADER - 4, 4); 390| 1.35k| unmaskImprecise8<0>(src + MESSAGE_HEADER, mask, length); 391| 1.35k| rotateMask(4 - (length - MESSAGE_HEADER) % 4, wState->mask); 392| 1.35k| } 393| 1.35k| Impl::handleFragment(src + MESSAGE_HEADER, length - MESSAGE_HEADER, wState->remainingBytes, wState->state.opCode[wState->state.opStack], fin, wState, user); 394| 1.35k| return true; 395| 1.35k| } 396| 4.09k| } EpollEchoServer.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataEEE23unmaskImpreciseCopyMaskILi14EEEvPcj: 308| 2.74k| static inline void unmaskImpreciseCopyMask(char *src, unsigned int length) { 309| 2.74k| if constexpr (HEADER_SIZE != 6) { ------------------ | Branch (309:23): [Folded - Ignored] ------------------ 310| 2.74k| char mask[8] = {src[-4], src[-3], src[-2], src[-1], src[-4], src[-3], src[-2], src[-1]}; 311| 2.74k| uint64_t maskInt; 312| 2.74k| memcpy(&maskInt, mask, 8); 313| 2.74k| unmaskImprecise8(src, maskInt, length); 314| 2.74k| } else { 315| 2.74k| char mask[4] = {src[-4], src[-3], src[-2], src[-1]}; 316| 2.74k| uint32_t maskInt; 317| 2.74k| memcpy(&maskInt, mask, 4); 318| 2.74k| unmaskImprecise4(src, maskInt, length); 319| 2.74k| } 320| 2.74k| } EpollEchoServer.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataEEE16unmaskImprecise8ILi14EEEvPcmj: 285| 2.74k| static inline void unmaskImprecise8(char *src, uint64_t mask, unsigned int length) { 286| 12.1k| for (unsigned int n = (length >> 3) + 1; n; n--) { ------------------ | Branch (286:50): [True: 9.44k, False: 2.74k] ------------------ 287| 9.44k| uint64_t loaded; 288| 9.44k| memcpy(&loaded, src, 8); 289| 9.44k| loaded ^= mask; 290| 9.44k| memcpy(src - DESTINATION, &loaded, 8); 291| 9.44k| src += 8; 292| 9.44k| } 293| 2.74k| } _ZN3uWS8protocol8bit_castImEET_Pc: 87| 5.85k|T bit_cast(char *c) { 88| 5.85k| T val; 89| 5.85k| memcpy(&val, c, sizeof(T)); 90| 5.85k| return val; 91| 5.85k|} EpollEchoServer.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataEEE19consumeContinuationERPcRjPNS_14WebSocketStateILb1EEEPv: 405| 9.13k| static inline bool consumeContinuation(char *&src, unsigned int &length, WebSocketState *wState, void *user) { 406| 9.13k| if (wState->remainingBytes <= length) { ------------------ | Branch (406:13): [True: 7.38k, False: 1.75k] ------------------ 407| 7.38k| if (isServer) { ------------------ | Branch (407:17): [Folded - Ignored] ------------------ 408| 7.38k| unsigned int n = wState->remainingBytes >> 2; 409| 7.38k| unmaskInplace(src, src + n * 4, wState->mask); 410| 19.3k| for (unsigned int i = 0, s = wState->remainingBytes % 4; i < s; i++) { ------------------ | Branch (410:74): [True: 12.0k, False: 7.38k] ------------------ 411| 12.0k| src[n * 4 + i] ^= wState->mask[i]; 412| 12.0k| } 413| 7.38k| } 414| | 415| 7.38k| if (Impl::handleFragment(src, wState->remainingBytes, 0, wState->state.opCode[wState->state.opStack], wState->state.lastFin, wState, user)) { ------------------ | Branch (415:17): [True: 2.34k, False: 5.04k] ------------------ 416| 2.34k| return false; 417| 2.34k| } 418| | 419| 5.04k| if (wState->state.lastFin) { ------------------ | Branch (419:17): [True: 4.23k, False: 806] ------------------ 420| 4.23k| wState->state.opStack--; 421| 4.23k| } 422| | 423| 5.04k| src += wState->remainingBytes; 424| 5.04k| length -= wState->remainingBytes; 425| 5.04k| wState->state.wantsHead = true; 426| 5.04k| return true; 427| 7.38k| } else { 428| 1.75k| if (isServer) { ------------------ | Branch (428:17): [Folded - Ignored] ------------------ 429| | /* No need to unmask if mask is 0 */ 430| 1.75k| uint32_t nullmask = 0; 431| 1.75k| if (memcmp(wState->mask, &nullmask, sizeof(uint32_t))) { ------------------ | Branch (431:21): [True: 1.43k, False: 320] ------------------ 432| 1.43k| if /*constexpr*/ (LIBUS_RECV_BUFFER_LENGTH == length) { ------------------ | | 22| 1.43k|#define LIBUS_RECV_BUFFER_LENGTH 524288 ------------------ | Branch (432:39): [True: 0, False: 1.43k] ------------------ 433| 0| unmaskAll(src, wState->mask); 434| 1.43k| } else { 435| | // Slow path 436| 1.43k| unmaskInplace(src, src + ((length >> 2) + 1) * 4, wState->mask); 437| 1.43k| } 438| 1.43k| } 439| 1.75k| } 440| | 441| 1.75k| wState->remainingBytes -= length; 442| 1.75k| if (Impl::handleFragment(src, length, wState->remainingBytes, wState->state.opCode[wState->state.opStack], wState->state.lastFin, wState, user)) { ------------------ | Branch (442:17): [True: 322, False: 1.43k] ------------------ 443| 322| return false; 444| 322| } 445| | 446| 1.43k| if (isServer && length % 4) { ------------------ | Branch (446:17): [Folded - Ignored] | Branch (446:29): [True: 1.21k, False: 212] ------------------ 447| 1.21k| rotateMask(4 - (length % 4), wState->mask); 448| 1.21k| } 449| 1.43k| return false; 450| 1.75k| } 451| 9.13k| } EpollEchoServer.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb0ELb1EZ4testvE13PerSocketDataEEE13unmaskInplaceEPcS5_S5_: 330| 8.81k| static inline void unmaskInplace(char *data, char *stop, char *mask) { 331| 58.7k| while (data < stop) { ------------------ | Branch (331:16): [True: 49.9k, False: 8.81k] ------------------ 332| 49.9k| *(data++) ^= mask[0]; 333| 49.9k| *(data++) ^= mask[1]; 334| 49.9k| *(data++) ^= mask[2]; 335| 49.9k| *(data++) ^= mask[3]; 336| 49.9k| } 337| 8.81k| } _ZN3uWS14WebSocketStateILb1EE5StateC2Ev: 70| 164k| State() { 71| 164k| wantsHead = true; 72| 164k| spillLength = 0; 73| 164k| opStack = -1; 74| 164k| lastFin = true; 75| 164k| } apple_no_sigpipe: 269| 1.63M|LIBUS_SOCKET_DESCRIPTOR apple_no_sigpipe(LIBUS_SOCKET_DESCRIPTOR fd) { 270| |#ifdef __APPLE__ 271| | if (fd != LIBUS_SOCKET_ERROR) { 272| | int no_sigpipe = 1; 273| | setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (void *) &no_sigpipe, sizeof(int)); 274| | } 275| |#endif 276| 1.63M| return fd; 277| 1.63M|} bsd_set_nonblocking: 279| 1.63M|LIBUS_SOCKET_DESCRIPTOR bsd_set_nonblocking(LIBUS_SOCKET_DESCRIPTOR fd) { 280| |#ifdef _WIN32 281| | /* Libuv will set windows sockets as non-blocking */ 282| |#else 283| 1.63M| fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); 284| 1.63M|#endif 285| 1.63M| return fd; 286| 1.63M|} bsd_socket_nodelay: 288| 1.63M|void bsd_socket_nodelay(LIBUS_SOCKET_DESCRIPTOR fd, int enabled) { 289| 1.63M| setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void *) &enabled, sizeof(enabled)); 290| 1.63M|} bsd_create_socket: 300| 5.84k|LIBUS_SOCKET_DESCRIPTOR bsd_create_socket(int domain, int type, int protocol) { 301| | // returns INVALID_SOCKET on error 302| 5.84k| int flags = 0; 303| 5.84k|#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) 304| 5.84k| flags = SOCK_CLOEXEC | SOCK_NONBLOCK; 305| 5.84k|#endif 306| | 307| 5.84k| LIBUS_SOCKET_DESCRIPTOR created_fd = socket(domain, type | flags, protocol); ------------------ | | 38| 5.84k|#define LIBUS_SOCKET_DESCRIPTOR int ------------------ 308| | 309| 5.84k| return bsd_set_nonblocking(apple_no_sigpipe(created_fd)); 310| 5.84k|} bsd_close_socket: 312| 1.63M|void bsd_close_socket(LIBUS_SOCKET_DESCRIPTOR fd) { 313| |#ifdef _WIN32 314| | closesocket(fd); 315| |#else 316| 1.63M| close(fd); 317| 1.63M|#endif 318| 1.63M|} bsd_shutdown_socket: 320| 401k|void bsd_shutdown_socket(LIBUS_SOCKET_DESCRIPTOR fd) { 321| |#ifdef _WIN32 322| | shutdown(fd, SD_SEND); 323| |#else 324| 401k| shutdown(fd, SHUT_WR); 325| 401k|#endif 326| 401k|} internal_finalize_bsd_addr: 336| 1.63M|void internal_finalize_bsd_addr(struct bsd_addr_t *addr) { 337| | // parse, so to speak, the address 338| 1.63M| if (addr->mem.ss_family == AF_INET6) { ------------------ | Branch (338:9): [True: 199k, False: 1.43M] ------------------ 339| 199k| addr->ip = (char *) &((struct sockaddr_in6 *) addr)->sin6_addr; 340| 199k| addr->ip_length = sizeof(struct in6_addr); 341| 199k| addr->port = ntohs(((struct sockaddr_in6 *) addr)->sin6_port); 342| 1.43M| } else if (addr->mem.ss_family == AF_INET) { ------------------ | Branch (342:16): [True: 1.43M, False: 0] ------------------ 343| 1.43M| addr->ip = (char *) &((struct sockaddr_in *) addr)->sin_addr; 344| 1.43M| addr->ip_length = sizeof(struct in_addr); 345| 1.43M| addr->port = ntohs(((struct sockaddr_in *) addr)->sin_port); 346| 1.43M| } else { 347| 0| addr->ip_length = 0; 348| 0| addr->port = -1; 349| 0| } 350| 1.63M|} bsd_addr_get_ip: 370| 1.63M|char *bsd_addr_get_ip(struct bsd_addr_t *addr) { 371| 1.63M| return addr->ip; 372| 1.63M|} bsd_addr_get_ip_length: 374| 1.63M|int bsd_addr_get_ip_length(struct bsd_addr_t *addr) { 375| 1.63M| return addr->ip_length; 376| 1.63M|} bsd_accept_socket: 383| 3.19M|LIBUS_SOCKET_DESCRIPTOR bsd_accept_socket(LIBUS_SOCKET_DESCRIPTOR fd, struct bsd_addr_t *addr) { 384| 3.19M| LIBUS_SOCKET_DESCRIPTOR accepted_fd; ------------------ | | 38| 3.19M|#define LIBUS_SOCKET_DESCRIPTOR int ------------------ 385| 3.19M| addr->len = sizeof(addr->mem); 386| | 387| 3.19M|#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) 388| | // Linux, FreeBSD 389| 3.19M| accepted_fd = accept4(fd, (struct sockaddr *) addr, &addr->len, SOCK_CLOEXEC | SOCK_NONBLOCK); 390| |#else 391| | // Windows, OS X 392| | accepted_fd = accept(fd, (struct sockaddr *) addr, &addr->len); 393| | 394| |#endif 395| | 396| | /* We cannot rely on addr since it is not initialized if failed */ 397| 3.19M| if (accepted_fd == LIBUS_SOCKET_ERROR) { ------------------ | | 44| 3.19M|#define LIBUS_SOCKET_ERROR -1 ------------------ | Branch (397:9): [True: 1.56M, False: 1.63M] ------------------ 398| 1.56M| return LIBUS_SOCKET_ERROR; ------------------ | | 44| 1.56M|#define LIBUS_SOCKET_ERROR -1 ------------------ 399| 1.56M| } 400| | 401| 1.63M| internal_finalize_bsd_addr(addr); 402| | 403| 1.63M| return bsd_set_nonblocking(apple_no_sigpipe(accepted_fd)); 404| 3.19M|} bsd_recv: 406| 732k|int bsd_recv(LIBUS_SOCKET_DESCRIPTOR fd, void *buf, int length, int flags) { 407| 732k| return recv(fd, buf, length, flags); 408| 732k|} bsd_send: 436| 696k|int bsd_send(LIBUS_SOCKET_DESCRIPTOR fd, const char *buf, int length, int msg_more) { 437| | 438| | // MSG_MORE (Linux), MSG_PARTIAL (Windows), TCP_NOPUSH (BSD) 439| | 440| |#ifndef MSG_NOSIGNAL 441| |#define MSG_NOSIGNAL 0 442| |#endif 443| | 444| 696k|#ifdef MSG_MORE 445| | 446| | // for Linux we do not want signals 447| 696k| return send(fd, buf, length, ((msg_more != 0) * MSG_MORE) | MSG_NOSIGNAL); 448| | 449| |#else 450| | 451| | // use TCP_NOPUSH 452| | 453| | return send(fd, buf, length, MSG_NOSIGNAL); 454| | 455| |#endif 456| 696k|} bsd_would_block: 458| 8.02k|int bsd_would_block() { 459| |#ifdef _WIN32 460| | return WSAGetLastError() == WSAEWOULDBLOCK; 461| |#else 462| 8.02k| return errno == EWOULDBLOCK;// || errno == EAGAIN; 463| 8.02k|#endif 464| 8.02k|} bsd_create_listen_socket: 468| 5.84k|LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket(const char *host, int port, int options) { 469| 5.84k| struct addrinfo hints, *result; 470| 5.84k| memset(&hints, 0, sizeof(struct addrinfo)); 471| | 472| 5.84k| hints.ai_flags = AI_PASSIVE; 473| 5.84k| hints.ai_family = AF_UNSPEC; 474| 5.84k| hints.ai_socktype = SOCK_STREAM; 475| | 476| 5.84k| char port_string[16]; 477| 5.84k| snprintf(port_string, 16, "%d", port); 478| | 479| 5.84k| if (getaddrinfo(host, port_string, &hints, &result)) { ------------------ | Branch (479:9): [True: 6, False: 5.84k] ------------------ 480| 6| return LIBUS_SOCKET_ERROR; ------------------ | | 44| 6|#define LIBUS_SOCKET_ERROR -1 ------------------ 481| 6| } 482| | 483| 5.84k| LIBUS_SOCKET_DESCRIPTOR listenFd = LIBUS_SOCKET_ERROR; ------------------ | | 38| 5.84k|#define LIBUS_SOCKET_DESCRIPTOR int ------------------ LIBUS_SOCKET_DESCRIPTOR listenFd = LIBUS_SOCKET_ERROR; ------------------ | | 44| 5.84k|#define LIBUS_SOCKET_ERROR -1 ------------------ 484| 5.84k| struct addrinfo *listenAddr; 485| 11.6k| for (struct addrinfo *a = result; a && listenFd == LIBUS_SOCKET_ERROR; a = a->ai_next) { ------------------ | | 44| 5.84k|#define LIBUS_SOCKET_ERROR -1 ------------------ | Branch (485:39): [True: 5.84k, False: 5.84k] | Branch (485:44): [True: 5.84k, False: 0] ------------------ 486| 5.84k| if (a->ai_family == AF_INET6) { ------------------ | Branch (486:13): [True: 2.75k, False: 3.08k] ------------------ 487| 2.75k| listenFd = bsd_create_socket(a->ai_family, a->ai_socktype, a->ai_protocol); 488| 2.75k| listenAddr = a; 489| 2.75k| } 490| 5.84k| } 491| | 492| 8.93k| for (struct addrinfo *a = result; a && listenFd == LIBUS_SOCKET_ERROR; a = a->ai_next) { ------------------ | | 44| 5.84k|#define LIBUS_SOCKET_ERROR -1 ------------------ | Branch (492:39): [True: 5.84k, False: 3.08k] | Branch (492:44): [True: 3.08k, False: 2.75k] ------------------ 493| 3.08k| if (a->ai_family == AF_INET) { ------------------ | Branch (493:13): [True: 3.08k, False: 1] ------------------ 494| 3.08k| listenFd = bsd_create_socket(a->ai_family, a->ai_socktype, a->ai_protocol); 495| 3.08k| listenAddr = a; 496| 3.08k| } 497| 3.08k| } 498| | 499| 5.84k| if (listenFd == LIBUS_SOCKET_ERROR) { ------------------ | | 44| 5.84k|#define LIBUS_SOCKET_ERROR -1 ------------------ | Branch (499:9): [True: 1, False: 5.84k] ------------------ 500| 1| freeaddrinfo(result); 501| 1| return LIBUS_SOCKET_ERROR; ------------------ | | 44| 1|#define LIBUS_SOCKET_ERROR -1 ------------------ 502| 1| } 503| | 504| 5.84k| if (port != 0) { ------------------ | Branch (504:9): [True: 5.84k, False: 0] ------------------ 505| | /* Otherwise, always enable SO_REUSEPORT and SO_REUSEADDR _unless_ options specify otherwise */ 506| |#ifdef _WIN32 507| | if (options & LIBUS_LISTEN_EXCLUSIVE_PORT) { 508| | int optval2 = 1; 509| | setsockopt(listenFd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (void *) &optval2, sizeof(optval2)); 510| | } else { 511| | int optval3 = 1; 512| | setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, (void *) &optval3, sizeof(optval3)); 513| | } 514| |#else 515| 5.84k| #if /*defined(__linux) &&*/ defined(SO_REUSEPORT) 516| 5.84k| if (!(options & LIBUS_LISTEN_EXCLUSIVE_PORT)) { ------------------ | Branch (516:13): [True: 5.84k, False: 0] ------------------ 517| 5.84k| int optval = 1; 518| 5.84k| setsockopt(listenFd, SOL_SOCKET, SO_REUSEPORT, (void *) &optval, sizeof(optval)); 519| 5.84k| } 520| 5.84k| #endif 521| 5.84k| int enabled = 1; 522| 5.84k| setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, (void *) &enabled, sizeof(enabled)); 523| 5.84k|#endif 524| | 525| 5.84k| } 526| | 527| 5.84k|#ifdef IPV6_V6ONLY 528| 5.84k| int disabled = 0; 529| 5.84k| setsockopt(listenFd, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &disabled, sizeof(disabled)); 530| 5.84k|#endif 531| | 532| 5.84k| if (bind(listenFd, listenAddr->ai_addr, (socklen_t) listenAddr->ai_addrlen) || listen(listenFd, 512)) { ------------------ | Branch (532:9): [True: 0, False: 5.84k] | Branch (532:84): [True: 10, False: 5.83k] ------------------ 533| 10| bsd_close_socket(listenFd); 534| 10| freeaddrinfo(result); 535| 10| return LIBUS_SOCKET_ERROR; ------------------ | | 44| 10|#define LIBUS_SOCKET_ERROR -1 ------------------ 536| 10| } 537| | 538| 5.83k| freeaddrinfo(result); 539| 5.83k| return listenFd; 540| 5.84k|} default_is_low_prio_handler: 25| 732k|int default_is_low_prio_handler(struct us_socket_t *s) { 26| 732k| return 0; 27| 732k|} us_listen_socket_close: 35| 5.83k|void us_listen_socket_close(int ssl, struct us_listen_socket_t *ls) { 36| | /* us_listen_socket_t extends us_socket_t so we close in similar ways */ 37| 5.83k| if (!us_socket_is_closed(0, &ls->s)) { ------------------ | Branch (37:9): [True: 5.83k, False: 0] ------------------ 38| 5.83k| us_internal_socket_context_unlink_listen_socket(ls->s.context, ls); 39| 5.83k| us_poll_stop((struct us_poll_t *) &ls->s, ls->s.context->loop); 40| 5.83k| bsd_close_socket(us_poll_fd((struct us_poll_t *) &ls->s)); 41| | 42| | /* Link this socket to the close-list and let it be deleted after this iteration */ 43| 5.83k| ls->s.next = ls->s.context->loop->data.closed_head; 44| 5.83k| ls->s.context->loop->data.closed_head = &ls->s; 45| | 46| | /* Any socket with prev = context is marked as closed */ 47| 5.83k| ls->s.prev = (struct us_socket_t *) ls->s.context; 48| 5.83k| } 49| | 50| | /* We cannot immediately free a listen socket as we can be inside an accept loop */ 51| 5.83k|} us_internal_socket_context_unlink_listen_socket: 71| 5.83k|void us_internal_socket_context_unlink_listen_socket(struct us_socket_context_t *context, struct us_listen_socket_t *ls) { 72| | /* We have to properly update the iterator used to sweep sockets for timeouts */ 73| 5.83k| if (ls == (struct us_listen_socket_t *) context->iterator) { ------------------ | Branch (73:9): [True: 0, False: 5.83k] ------------------ 74| 0| context->iterator = ls->s.next; 75| 0| } 76| | 77| 5.83k| if (ls->s.prev == ls->s.next) { ------------------ | Branch (77:9): [True: 5.83k, False: 0] ------------------ 78| 5.83k| context->head_listen_sockets = 0; 79| 5.83k| } else { 80| 0| if (ls->s.prev) { ------------------ | Branch (80:13): [True: 0, False: 0] ------------------ 81| 0| ls->s.prev->next = ls->s.next; 82| 0| } else { 83| 0| context->head_listen_sockets = (struct us_listen_socket_t *) ls->s.next; 84| 0| } 85| 0| if (ls->s.next) { ------------------ | Branch (85:13): [True: 0, False: 0] ------------------ 86| 0| ls->s.next->prev = ls->s.prev; 87| 0| } 88| 0| } 89| 5.83k|} us_internal_socket_context_unlink_socket: 91| 1.79M|void us_internal_socket_context_unlink_socket(struct us_socket_context_t *context, struct us_socket_t *s) { 92| | /* We have to properly update the iterator used to sweep sockets for timeouts */ 93| 1.79M| if (s == context->iterator) { ------------------ | Branch (93:9): [True: 14.3k, False: 1.78M] ------------------ 94| 14.3k| context->iterator = s->next; 95| 14.3k| } 96| | 97| 1.79M| if (s->prev == s->next) { ------------------ | Branch (97:9): [True: 293k, False: 1.50M] ------------------ 98| 293k| context->head_sockets = 0; 99| 1.50M| } else { 100| 1.50M| if (s->prev) { ------------------ | Branch (100:13): [True: 872k, False: 630k] ------------------ 101| 872k| s->prev->next = s->next; 102| 872k| } else { 103| 630k| context->head_sockets = s->next; 104| 630k| } 105| 1.50M| if (s->next) { ------------------ | Branch (105:13): [True: 1.37M, False: 126k] ------------------ 106| 1.37M| s->next->prev = s->prev; 107| 1.37M| } 108| 1.50M| } 109| 1.79M|} us_internal_socket_context_link_listen_socket: 112| 5.83k|void us_internal_socket_context_link_listen_socket(struct us_socket_context_t *context, struct us_listen_socket_t *ls) { 113| 5.83k| ls->s.context = context; 114| 5.83k| ls->s.next = (struct us_socket_t *) context->head_listen_sockets; 115| 5.83k| ls->s.prev = 0; 116| 5.83k| if (context->head_listen_sockets) { ------------------ | Branch (116:9): [True: 0, False: 5.83k] ------------------ 117| 0| context->head_listen_sockets->s.prev = &ls->s; 118| 0| } 119| 5.83k| context->head_listen_sockets = ls; 120| 5.83k|} us_internal_socket_context_link_socket: 123| 1.79M|void us_internal_socket_context_link_socket(struct us_socket_context_t *context, struct us_socket_t *s) { 124| 1.79M| s->context = context; 125| 1.79M| s->next = context->head_sockets; 126| 1.79M| s->prev = 0; 127| 1.79M| if (context->head_sockets) { ------------------ | Branch (127:9): [True: 1.50M, False: 293k] ------------------ 128| 1.50M| context->head_sockets->prev = s; 129| 1.50M| } 130| 1.79M| context->head_sockets = s; 131| 1.79M|} us_socket_context_loop: 133| 7.34M|struct us_loop_t *us_socket_context_loop(int ssl, struct us_socket_context_t *context) { 134| 7.34M| return context->loop; 135| 7.34M|} us_create_socket_context: 204| 17.5k|struct us_socket_context_t *us_create_socket_context(int ssl, struct us_loop_t *loop, int context_ext_size, struct us_socket_context_options_t options) { 205| |#ifndef LIBUS_NO_SSL 206| | if (ssl) { 207| | /* This function will call us, again, with SSL = false and a bigger ext_size */ 208| | return (struct us_socket_context_t *) us_internal_create_ssl_socket_context(loop, context_ext_size, options); 209| | } 210| |#endif 211| | 212| | /* This path is taken once either way - always BEFORE whatever SSL may do LATER. 213| | * context_ext_size will however be modified larger in case of SSL, to hold SSL extensions */ 214| | 215| 17.5k| struct us_socket_context_t *context = malloc(sizeof(struct us_socket_context_t) + context_ext_size); 216| 17.5k| context->loop = loop; 217| 17.5k| context->head_sockets = 0; 218| 17.5k| context->head_listen_sockets = 0; 219| 17.5k| context->iterator = 0; 220| 17.5k| context->next = 0; 221| 17.5k| context->is_low_prio = default_is_low_prio_handler; 222| | 223| | /* Begin at 0 */ 224| 17.5k| context->timestamp = 0; 225| 17.5k| context->long_timestamp = 0; 226| 17.5k| context->global_tick = 0; 227| | 228| | /* Some new events must be set to null for backwards compatibility */ 229| 17.5k| context->on_pre_open = 0; 230| | 231| 17.5k| us_internal_loop_link(loop, context); 232| | 233| | /* If we are called from within SSL code, SSL code will make further changes to us */ 234| 17.5k| return context; 235| 17.5k|} us_socket_context_free: 237| 17.5k|void us_socket_context_free(int ssl, struct us_socket_context_t *context) { 238| |#ifndef LIBUS_NO_SSL 239| | if (ssl) { 240| | /* This function will call us again with SSL=false */ 241| | us_internal_ssl_socket_context_free((struct us_internal_ssl_socket_context_t *) context); 242| | return; 243| | } 244| |#endif 245| | 246| | /* This path is taken once either way - always AFTER whatever SSL may do BEFORE. 247| | * This is the opposite order compared to when creating the context - SSL code is cleaning up before non-SSL */ 248| | 249| 17.5k| us_internal_loop_unlink(context->loop, context); 250| 17.5k| free(context); 251| 17.5k|} us_socket_context_listen: 253| 5.84k|struct us_listen_socket_t *us_socket_context_listen(int ssl, struct us_socket_context_t *context, const char *host, int port, int options, int socket_ext_size) { 254| |#ifndef LIBUS_NO_SSL 255| | if (ssl) { 256| | return us_internal_ssl_socket_context_listen((struct us_internal_ssl_socket_context_t *) context, host, port, options, socket_ext_size); 257| | } 258| |#endif 259| | 260| 5.84k| LIBUS_SOCKET_DESCRIPTOR listen_socket_fd = bsd_create_listen_socket(host, port, options); ------------------ | | 38| 5.84k|#define LIBUS_SOCKET_DESCRIPTOR int ------------------ 261| | 262| 5.84k| if (listen_socket_fd == LIBUS_SOCKET_ERROR) { ------------------ | | 44| 5.84k|#define LIBUS_SOCKET_ERROR -1 ------------------ | Branch (262:9): [True: 17, False: 5.83k] ------------------ 263| 17| return 0; 264| 17| } 265| | 266| 5.83k| struct us_poll_t *p = us_create_poll(context->loop, 0, sizeof(struct us_listen_socket_t)); 267| 5.83k| us_poll_init(p, listen_socket_fd, POLL_TYPE_SEMI_SOCKET); 268| 5.83k| us_poll_start(p, context->loop, LIBUS_SOCKET_READABLE); ------------------ | | 27| 5.83k|#define LIBUS_SOCKET_READABLE EPOLLIN ------------------ 269| | 270| 5.83k| struct us_listen_socket_t *ls = (struct us_listen_socket_t *) p; 271| | 272| 5.83k| ls->s.context = context; 273| 5.83k| ls->s.timeout = 255; 274| 5.83k| ls->s.long_timeout = 255; 275| 5.83k| ls->s.low_prio_state = 0; 276| 5.83k| ls->s.next = 0; 277| 5.83k| us_internal_socket_context_link_listen_socket(context, ls); 278| | 279| 5.83k| ls->socket_ext_size = socket_ext_size; 280| | 281| 5.83k| return ls; 282| 5.84k|} us_create_child_socket_context: 373| 11.6k|struct us_socket_context_t *us_create_child_socket_context(int ssl, struct us_socket_context_t *context, int context_ext_size) { 374| |#ifndef LIBUS_NO_SSL 375| | if (ssl) { 376| | return (struct us_socket_context_t *) us_internal_create_child_ssl_socket_context((struct us_internal_ssl_socket_context_t *) context, context_ext_size); 377| | } 378| |#endif 379| | 380| | /* For TCP we simply create a new context as nothing is shared */ 381| 11.6k| struct us_socket_context_options_t options = {0}; 382| 11.6k| return us_create_socket_context(ssl, context->loop, context_ext_size, options); 383| 11.6k|} us_socket_context_adopt_socket: 386| 164k|struct us_socket_t *us_socket_context_adopt_socket(int ssl, struct us_socket_context_t *context, struct us_socket_t *s, int ext_size) { 387| |#ifndef LIBUS_NO_SSL 388| | if (ssl) { 389| | return (struct us_socket_t *) us_internal_ssl_socket_context_adopt_socket((struct us_internal_ssl_socket_context_t *) context, (struct us_internal_ssl_socket_t *) s, ext_size); 390| | } 391| |#endif 392| | 393| | /* Cannot adopt a closed socket */ 394| 164k| if (us_socket_is_closed(ssl, s)) { ------------------ | Branch (394:9): [True: 0, False: 164k] ------------------ 395| 0| return s; 396| 0| } 397| | 398| 164k| if (s->low_prio_state != 1) { ------------------ | Branch (398:9): [True: 164k, False: 0] ------------------ 399| | /* This properly updates the iterator if in on_timeout */ 400| 164k| us_internal_socket_context_unlink_socket(s->context, s); 401| 164k| } 402| | 403| 164k| struct us_socket_t *new_s = (struct us_socket_t *) us_poll_resize(&s->p, s->context->loop, sizeof(struct us_socket_t) + ext_size); 404| 164k| new_s->timeout = 255; 405| 164k| new_s->long_timeout = 255; 406| | 407| 164k| if (new_s->low_prio_state == 1) { ------------------ | Branch (407:9): [True: 0, False: 164k] ------------------ 408| | /* update pointers in low-priority queue */ 409| 0| if (!new_s->prev) new_s->context->loop->data.low_prio_head = new_s; ------------------ | Branch (409:13): [True: 0, False: 0] ------------------ 410| 0| else new_s->prev->next = new_s; 411| | 412| 0| if (new_s->next) new_s->next->prev = new_s; ------------------ | Branch (412:13): [True: 0, False: 0] ------------------ 413| 164k| } else { 414| 164k| us_internal_socket_context_link_socket(context, new_s); 415| 164k| } 416| | 417| 164k| return new_s; 418| 164k|} us_socket_context_on_open: 426| 5.84k|void us_socket_context_on_open(int ssl, struct us_socket_context_t *context, struct us_socket_t *(*on_open)(struct us_socket_t *s, int is_client, char *ip, int ip_length)) { 427| |#ifndef LIBUS_NO_SSL 428| | if (ssl) { 429| | us_internal_ssl_socket_context_on_open((struct us_internal_ssl_socket_context_t *) context, (struct us_internal_ssl_socket_t * (*)(struct us_internal_ssl_socket_t *, int, char *, int)) on_open); 430| | return; 431| | } 432| |#endif 433| | 434| 5.84k| context->on_open = on_open; 435| 5.84k|} us_socket_context_on_close: 437| 17.5k|void us_socket_context_on_close(int ssl, struct us_socket_context_t *context, struct us_socket_t *(*on_close)(struct us_socket_t *s, int code, void *reason)) { 438| |#ifndef LIBUS_NO_SSL 439| | if (ssl) { 440| | us_internal_ssl_socket_context_on_close((struct us_internal_ssl_socket_context_t *) context, (struct us_internal_ssl_socket_t * (*)(struct us_internal_ssl_socket_t *, int code, void *reason)) on_close); 441| | return; 442| | } 443| |#endif 444| | 445| 17.5k| context->on_close = on_close; 446| 17.5k|} us_socket_context_on_data: 448| 17.5k|void us_socket_context_on_data(int ssl, struct us_socket_context_t *context, struct us_socket_t *(*on_data)(struct us_socket_t *s, char *data, int length)) { 449| |#ifndef LIBUS_NO_SSL 450| | if (ssl) { 451| | us_internal_ssl_socket_context_on_data((struct us_internal_ssl_socket_context_t *) context, (struct us_internal_ssl_socket_t * (*)(struct us_internal_ssl_socket_t *, char *, int)) on_data); 452| | return; 453| | } 454| |#endif 455| | 456| 17.5k| context->on_data = on_data; 457| 17.5k|} us_socket_context_on_writable: 459| 17.5k|void us_socket_context_on_writable(int ssl, struct us_socket_context_t *context, struct us_socket_t *(*on_writable)(struct us_socket_t *s)) { 460| |#ifndef LIBUS_NO_SSL 461| | if (ssl) { 462| | us_internal_ssl_socket_context_on_writable((struct us_internal_ssl_socket_context_t *) context, (struct us_internal_ssl_socket_t * (*)(struct us_internal_ssl_socket_t *)) on_writable); 463| | return; 464| | } 465| |#endif 466| | 467| 17.5k| context->on_writable = on_writable; 468| 17.5k|} us_socket_context_on_long_timeout: 470| 11.6k|void us_socket_context_on_long_timeout(int ssl, struct us_socket_context_t *context, struct us_socket_t *(*on_long_timeout)(struct us_socket_t *)) { 471| |#ifndef LIBUS_NO_SSL 472| | if (ssl) { 473| | us_internal_ssl_socket_context_on_long_timeout((struct us_internal_ssl_socket_context_t *) context, (struct us_internal_ssl_socket_t * (*)(struct us_internal_ssl_socket_t *)) on_long_timeout); 474| | return; 475| | } 476| |#endif 477| | 478| 11.6k| context->on_socket_long_timeout = on_long_timeout; 479| 11.6k|} us_socket_context_on_timeout: 481| 17.5k|void us_socket_context_on_timeout(int ssl, struct us_socket_context_t *context, struct us_socket_t *(*on_timeout)(struct us_socket_t *)) { 482| |#ifndef LIBUS_NO_SSL 483| | if (ssl) { 484| | us_internal_ssl_socket_context_on_timeout((struct us_internal_ssl_socket_context_t *) context, (struct us_internal_ssl_socket_t * (*)(struct us_internal_ssl_socket_t *)) on_timeout); 485| | return; 486| | } 487| |#endif 488| | 489| 17.5k| context->on_socket_timeout = on_timeout; 490| 17.5k|} us_socket_context_on_end: 492| 17.5k|void us_socket_context_on_end(int ssl, struct us_socket_context_t *context, struct us_socket_t *(*on_end)(struct us_socket_t *)) { 493| |#ifndef LIBUS_NO_SSL 494| | if (ssl) { 495| | us_internal_ssl_socket_context_on_end((struct us_internal_ssl_socket_context_t *) context, (struct us_internal_ssl_socket_t * (*)(struct us_internal_ssl_socket_t *)) on_end); 496| | return; 497| | } 498| |#endif 499| | 500| 17.5k| context->on_end = on_end; 501| 17.5k|} us_socket_context_ext: 514| 4.94M|void *us_socket_context_ext(int ssl, struct us_socket_context_t *context) { 515| |#ifndef LIBUS_NO_SSL 516| | if (ssl) { 517| | return us_internal_ssl_socket_context_ext((struct us_internal_ssl_socket_context_t *) context); 518| | } 519| |#endif 520| | 521| 4.94M| return context + 1; 522| 4.94M|} us_loop_free: 36| 5.84k|void us_loop_free(struct us_loop_t *loop) { 37| 5.84k| us_internal_loop_data_free(loop); 38| 5.84k| close(loop->fd); 39| 5.84k| free(loop); 40| 5.84k|} us_create_poll: 43| 1.65M|struct us_poll_t *us_create_poll(struct us_loop_t *loop, int fallthrough, unsigned int ext_size) { 44| 1.65M| if (!fallthrough) { ------------------ | Branch (44:9): [True: 1.63M, False: 17.5k] ------------------ 45| 1.63M| loop->num_polls++; 46| 1.63M| } 47| 1.65M| return malloc(sizeof(struct us_poll_t) + ext_size); 48| 1.65M|} us_poll_free: 51| 1.65M|void us_poll_free(struct us_poll_t *p, struct us_loop_t *loop) { 52| 1.65M| loop->num_polls--; 53| 1.65M| free(p); 54| 1.65M|} us_poll_init: 61| 1.65M|void us_poll_init(struct us_poll_t *p, LIBUS_SOCKET_DESCRIPTOR fd, int poll_type) { 62| 1.65M| p->state.fd = fd; 63| 1.65M| p->state.poll_type = poll_type; 64| 1.65M|} us_poll_events: 66| 13.4M|int us_poll_events(struct us_poll_t *p) { 67| 13.4M| return ((p->state.poll_type & POLL_TYPE_POLLING_IN) ? LIBUS_SOCKET_READABLE : 0) | ((p->state.poll_type & POLL_TYPE_POLLING_OUT) ? LIBUS_SOCKET_WRITABLE : 0); ------------------ | | 27| 13.4M|#define LIBUS_SOCKET_READABLE EPOLLIN ------------------ return ((p->state.poll_type & POLL_TYPE_POLLING_IN) ? LIBUS_SOCKET_READABLE : 0) | ((p->state.poll_type & POLL_TYPE_POLLING_OUT) ? LIBUS_SOCKET_WRITABLE : 0); ------------------ | | 28| 13.4M|#define LIBUS_SOCKET_WRITABLE EPOLLOUT ------------------ | Branch (67:13): [True: 13.3M, False: 85.5k] | Branch (67:89): [True: 1.25M, False: 12.1M] ------------------ 68| 13.4M|} us_poll_fd: 70| 11.6M|LIBUS_SOCKET_DESCRIPTOR us_poll_fd(struct us_poll_t *p) { 71| 11.6M| return p->state.fd; 72| 11.6M|} us_internal_poll_type: 75| 12.9M|int us_internal_poll_type(struct us_poll_t *p) { 76| 12.9M| return p->state.poll_type & 3; 77| 12.9M|} us_internal_poll_set_type: 80| 401k|void us_internal_poll_set_type(struct us_poll_t *p, int poll_type) { 81| 401k| p->state.poll_type = poll_type | (p->state.poll_type & 12); 82| 401k|} us_timer_ext: 85| 1.63M|void *us_timer_ext(struct us_timer_t *timer) { 86| 1.63M| return ((struct us_internal_callback_t *) timer) + 1; 87| 1.63M|} us_create_loop: 96| 5.84k|struct us_loop_t *us_create_loop(void *hint, void (*wakeup_cb)(struct us_loop_t *loop), void (*pre_cb)(struct us_loop_t *loop), void (*post_cb)(struct us_loop_t *loop), unsigned int ext_size) { 97| 5.84k| struct us_loop_t *loop = (struct us_loop_t *) malloc(sizeof(struct us_loop_t) + ext_size); 98| 5.84k| loop->num_polls = 0; 99| | /* These could be accessed if we close a poll before starting the loop */ 100| 5.84k| loop->num_ready_polls = 0; 101| 5.84k| loop->current_ready_poll = 0; 102| | 103| 5.84k|#ifdef LIBUS_USE_EPOLL 104| 5.84k| loop->fd = epoll_create1(EPOLL_CLOEXEC); 105| |#else 106| | loop->fd = kqueue(); 107| |#endif 108| | 109| 5.84k| us_internal_loop_data_init(loop, wakeup_cb, pre_cb, post_cb); 110| 5.84k| return loop; 111| 5.84k|} us_loop_run: 113| 5.84k|void us_loop_run(struct us_loop_t *loop) { 114| 5.84k| us_loop_integrate(loop); 115| | 116| | /* While we have non-fallthrough polls we shouldn't fall through */ 117| 2.19M| while (loop->num_polls) { ------------------ | Branch (117:12): [True: 2.18M, False: 5.84k] ------------------ 118| | /* Emit pre callback */ 119| 2.18M| us_internal_loop_pre(loop); 120| | 121| | /* Fetch ready polls */ 122| 2.18M|#ifdef LIBUS_USE_EPOLL 123| 2.18M| loop->num_ready_polls = epoll_wait(loop->fd, loop->ready_polls, 1024, -1); 124| |#else 125| | loop->num_ready_polls = kevent(loop->fd, NULL, 0, loop->ready_polls, 1024, NULL); 126| |#endif 127| | 128| | /* Iterate ready polls, dispatching them by type */ 129| 10.5M| for (loop->current_ready_poll = 0; loop->current_ready_poll < loop->num_ready_polls; loop->current_ready_poll++) { ------------------ | Branch (129:44): [True: 8.40M, False: 2.18M] ------------------ 130| 8.40M| struct us_poll_t *poll = GET_READY_POLL(loop, loop->current_ready_poll); ------------------ | | 28| 8.40M|#define GET_READY_POLL(loop, index) (struct us_poll_t *) loop->ready_polls[index].data.ptr ------------------ 131| | /* Any ready poll marked with nullptr will be ignored */ 132| 8.40M| if (poll) { ------------------ | Branch (132:17): [True: 8.40M, False: 0] ------------------ 133| 8.40M|#ifdef LIBUS_USE_EPOLL 134| 8.40M| int events = loop->ready_polls[loop->current_ready_poll].events; 135| 8.40M| int error = loop->ready_polls[loop->current_ready_poll].events & (EPOLLERR | EPOLLHUP); 136| |#else 137| | /* EVFILT_READ, EVFILT_TIME, EVFILT_USER are all mapped to LIBUS_SOCKET_READABLE */ 138| | int events = LIBUS_SOCKET_READABLE; 139| | if (loop->ready_polls[loop->current_ready_poll].filter == EVFILT_WRITE) { 140| | events = LIBUS_SOCKET_WRITABLE; 141| | } 142| | int error = loop->ready_polls[loop->current_ready_poll].flags & (EV_ERROR | EV_EOF); 143| |#endif 144| | /* Always filter all polls by what they actually poll for (callback polls always poll for readable) */ 145| 8.40M| events &= us_poll_events(poll); 146| 8.40M| if (events || error) { ------------------ | Branch (146:21): [True: 5.56M, False: 2.83M] | Branch (146:31): [True: 2.83M, False: 0] ------------------ 147| 8.40M| us_internal_dispatch_ready_poll(poll, error, events); 148| 8.40M| } 149| 8.40M| } 150| 8.40M| } 151| | /* Emit post callback */ 152| 2.18M| us_internal_loop_post(loop); 153| 2.18M| } 154| 5.84k|} us_internal_loop_update_pending_ready_polls: 156| 1.65M|void us_internal_loop_update_pending_ready_polls(struct us_loop_t *loop, struct us_poll_t *old_poll, struct us_poll_t *new_poll, int old_events, int new_events) { 157| 1.65M|#ifdef LIBUS_USE_EPOLL 158| | /* Epoll only has one ready poll per poll */ 159| 1.65M| int num_entries_possibly_remaining = 1; 160| |#else 161| | /* Ready polls may contain same poll twice under kqueue, as one poll may hold two filters */ 162| | int num_entries_possibly_remaining = 2;//((old_events & LIBUS_SOCKET_READABLE) ? 1 : 0) + ((old_events & LIBUS_SOCKET_WRITABLE) ? 1 : 0); 163| |#endif 164| | 165| | /* Todo: for kqueue if we track things in us_change_poll it is possible to have a fast path with no seeking in cases of: 166| | * current poll being us AND we only poll for one thing */ 167| | 168| 3.32M| for (int i = loop->current_ready_poll; i < loop->num_ready_polls && num_entries_possibly_remaining; i++) { ------------------ | Branch (168:44): [True: 3.26M, False: 54.7k] | Branch (168:73): [True: 1.66M, False: 1.60M] ------------------ 169| 1.66M| if (GET_READY_POLL(loop, i) == old_poll) { ------------------ | | 28| 1.66M|#define GET_READY_POLL(loop, index) (struct us_poll_t *) loop->ready_polls[index].data.ptr ------------------ | Branch (169:13): [True: 1.61M, False: 47.4k] ------------------ 170| | 171| | // if new events does not contain the ready events of this poll then remove (no we filter that out later on) 172| 1.61M| SET_READY_POLL(loop, i, new_poll); ------------------ | | 29| 1.61M|#define SET_READY_POLL(loop, index, poll) loop->ready_polls[index].data.ptr = poll ------------------ 173| | 174| 1.61M| num_entries_possibly_remaining--; 175| 1.61M| } 176| 1.66M| } 177| 1.65M|} us_poll_resize: 205| 164k|struct us_poll_t *us_poll_resize(struct us_poll_t *p, struct us_loop_t *loop, unsigned int ext_size) { 206| 164k| int events = us_poll_events(p); 207| | 208| 164k| struct us_poll_t *new_p = realloc(p, sizeof(struct us_poll_t) + ext_size); 209| 164k| if (p != new_p && events) { ------------------ | Branch (209:9): [True: 0, False: 164k] | Branch (209:23): [True: 0, False: 0] ------------------ 210| 0|#ifdef LIBUS_USE_EPOLL 211| | /* Hack: forcefully update poll by stripping away already set events */ 212| 0| new_p->state.poll_type = us_internal_poll_type(new_p); 213| 0| us_poll_change(new_p, loop, events); 214| |#else 215| | /* Forcefully update poll by resetting them with new_p as user data */ 216| | kqueue_change(loop->fd, new_p->state.fd, 0, events, new_p); 217| |#endif 218| | 219| | /* This is needed for epoll also (us_change_poll doesn't update the old poll) */ 220| 0| us_internal_loop_update_pending_ready_polls(loop, p, new_p, events, events); 221| 0| } 222| | 223| 164k| return new_p; 224| 164k|} us_poll_start: 226| 1.65M|void us_poll_start(struct us_poll_t *p, struct us_loop_t *loop, int events) { 227| 1.65M| p->state.poll_type = us_internal_poll_type(p) | ((events & LIBUS_SOCKET_READABLE) ? POLL_TYPE_POLLING_IN : 0) | ((events & LIBUS_SOCKET_WRITABLE) ? POLL_TYPE_POLLING_OUT : 0); ------------------ | | 27| 1.65M|#define LIBUS_SOCKET_READABLE EPOLLIN ------------------ p->state.poll_type = us_internal_poll_type(p) | ((events & LIBUS_SOCKET_READABLE) ? POLL_TYPE_POLLING_IN : 0) | ((events & LIBUS_SOCKET_WRITABLE) ? POLL_TYPE_POLLING_OUT : 0); ------------------ | | 28| 1.65M|#define LIBUS_SOCKET_WRITABLE EPOLLOUT ------------------ | Branch (227:54): [True: 1.65M, False: 0] | Branch (227:118): [True: 0, False: 1.65M] ------------------ 228| | 229| 1.65M|#ifdef LIBUS_USE_EPOLL 230| 1.65M| struct epoll_event event; 231| 1.65M| event.events = events; 232| 1.65M| event.data.ptr = p; 233| 1.65M| epoll_ctl(loop->fd, EPOLL_CTL_ADD, p->state.fd, &event); 234| |#else 235| | kqueue_change(loop->fd, p->state.fd, 0, events, p); 236| |#endif 237| 1.65M|} us_poll_change: 239| 1.16M|void us_poll_change(struct us_poll_t *p, struct us_loop_t *loop, int events) { 240| 1.16M| int old_events = us_poll_events(p); 241| 1.16M| if (old_events != events) { ------------------ | Branch (241:9): [True: 1.04M, False: 120k] ------------------ 242| | 243| 1.04M| p->state.poll_type = us_internal_poll_type(p) | ((events & LIBUS_SOCKET_READABLE) ? POLL_TYPE_POLLING_IN : 0) | ((events & LIBUS_SOCKET_WRITABLE) ? POLL_TYPE_POLLING_OUT : 0); ------------------ | | 27| 1.04M|#define LIBUS_SOCKET_READABLE EPOLLIN ------------------ p->state.poll_type = us_internal_poll_type(p) | ((events & LIBUS_SOCKET_READABLE) ? POLL_TYPE_POLLING_IN : 0) | ((events & LIBUS_SOCKET_WRITABLE) ? POLL_TYPE_POLLING_OUT : 0); ------------------ | | 28| 1.04M|#define LIBUS_SOCKET_WRITABLE EPOLLOUT ------------------ | Branch (243:58): [True: 956k, False: 85.5k] | Branch (243:122): [True: 555k, False: 486k] ------------------ 244| | 245| 1.04M|#ifdef LIBUS_USE_EPOLL 246| 1.04M| struct epoll_event event; 247| 1.04M| event.events = events; 248| 1.04M| event.data.ptr = p; 249| 1.04M| epoll_ctl(loop->fd, EPOLL_CTL_MOD, p->state.fd, &event); 250| |#else 251| | kqueue_change(loop->fd, p->state.fd, old_events, events, p); 252| |#endif 253| | /* Set all removed events to null-polls in pending ready poll list */ 254| | //us_internal_loop_update_pending_ready_polls(loop, p, p, old_events, events); 255| 1.04M| } 256| 1.16M|} us_poll_stop: 258| 1.65M|void us_poll_stop(struct us_poll_t *p, struct us_loop_t *loop) { 259| 1.65M| int old_events = us_poll_events(p); 260| 1.65M| int new_events = 0; 261| 1.65M|#ifdef LIBUS_USE_EPOLL 262| 1.65M| struct epoll_event event; 263| 1.65M| epoll_ctl(loop->fd, EPOLL_CTL_DEL, p->state.fd, &event); 264| |#else 265| | if (old_events) { 266| | kqueue_change(loop->fd, p->state.fd, old_events, new_events, NULL); 267| | } 268| |#endif 269| | 270| | /* Disable any instance of us in the pending ready poll list */ 271| 1.65M| us_internal_loop_update_pending_ready_polls(loop, p, 0, old_events, new_events); 272| 1.65M|} us_internal_accept_poll_event: 274| 4.97M|unsigned int us_internal_accept_poll_event(struct us_poll_t *p) { 275| 4.97M|#ifdef LIBUS_USE_EPOLL 276| 4.97M| int fd = us_poll_fd(p); 277| 4.97M| uint64_t buf; 278| 4.97M| int read_length = read(fd, &buf, 8); 279| 4.97M| (void)read_length; 280| 4.97M| return buf; 281| |#else 282| | /* Kqueue has no underlying FD for timers or user events */ 283| | return 0; 284| |#endif 285| 4.97M|} us_create_timer: 289| 11.6k|struct us_timer_t *us_create_timer(struct us_loop_t *loop, int fallthrough, unsigned int ext_size) { 290| 11.6k| struct us_poll_t *p = us_create_poll(loop, fallthrough, sizeof(struct us_internal_callback_t) + ext_size); 291| 11.6k| int timerfd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK | TFD_CLOEXEC); 292| 11.6k| if (timerfd == -1) { ------------------ | Branch (292:9): [True: 0, False: 11.6k] ------------------ 293| 0| return NULL; 294| 0| } 295| 11.6k| us_poll_init(p, timerfd, POLL_TYPE_CALLBACK); 296| | 297| 11.6k| struct us_internal_callback_t *cb = (struct us_internal_callback_t *) p; 298| 11.6k| cb->loop = loop; 299| 11.6k| cb->cb_expects_the_loop = 0; 300| 11.6k| cb->leave_poll_ready = 0; 301| | 302| 11.6k| return (struct us_timer_t *) cb; 303| 11.6k|} us_timer_close: 325| 11.6k|void us_timer_close(struct us_timer_t *timer) { 326| 11.6k| struct us_internal_callback_t *cb = (struct us_internal_callback_t *) timer; 327| | 328| 11.6k| us_poll_stop(&cb->p, cb->loop); 329| 11.6k| close(us_poll_fd(&cb->p)); 330| | 331| | /* (regular) sockets are the only polls which are not freed immediately */ 332| 11.6k| us_poll_free((struct us_poll_t *) timer, cb->loop); 333| 11.6k|} us_timer_set: 335| 11.6k|void us_timer_set(struct us_timer_t *t, void (*cb)(struct us_timer_t *t), int ms, int repeat_ms) { 336| 11.6k| struct us_internal_callback_t *internal_cb = (struct us_internal_callback_t *) t; 337| | 338| 11.6k| internal_cb->cb = (void (*)(struct us_internal_callback_t *)) cb; 339| | 340| 11.6k| struct itimerspec timer_spec = { 341| 11.6k| {repeat_ms / 1000, (long) (repeat_ms % 1000) * (long) 1000000}, 342| 11.6k| {ms / 1000, (long) (ms % 1000) * (long) 1000000} 343| 11.6k| }; 344| | 345| 11.6k| timerfd_settime(us_poll_fd((struct us_poll_t *) t), 0, &timer_spec, NULL); 346| 11.6k| us_poll_start((struct us_poll_t *) t, internal_cb->loop, LIBUS_SOCKET_READABLE); ------------------ | | 27| 11.6k|#define LIBUS_SOCKET_READABLE EPOLLIN ------------------ 347| 11.6k|} us_internal_create_async: 374| 5.84k|struct us_internal_async *us_internal_create_async(struct us_loop_t *loop, int fallthrough, unsigned int ext_size) { 375| 5.84k| struct us_poll_t *p = us_create_poll(loop, fallthrough, sizeof(struct us_internal_callback_t) + ext_size); 376| 5.84k| us_poll_init(p, eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC), POLL_TYPE_CALLBACK); 377| | 378| 5.84k| struct us_internal_callback_t *cb = (struct us_internal_callback_t *) p; 379| 5.84k| cb->loop = loop; 380| 5.84k| cb->cb_expects_the_loop = 1; 381| 5.84k| cb->leave_poll_ready = 0; 382| | 383| 5.84k| return (struct us_internal_async *) cb; 384| 5.84k|} us_internal_async_close: 387| 5.84k|void us_internal_async_close(struct us_internal_async *a) { 388| 5.84k| struct us_internal_callback_t *cb = (struct us_internal_callback_t *) a; 389| | 390| 5.84k| us_poll_stop(&cb->p, cb->loop); 391| 5.84k| close(us_poll_fd(&cb->p)); 392| | 393| | /* (regular) sockets are the only polls which are not freed immediately */ 394| 5.84k| us_poll_free((struct us_poll_t *) a, cb->loop); 395| 5.84k|} us_internal_async_set: 397| 5.84k|void us_internal_async_set(struct us_internal_async *a, void (*cb)(struct us_internal_async *)) { 398| 5.84k| struct us_internal_callback_t *internal_cb = (struct us_internal_callback_t *) a; 399| | 400| 5.84k| internal_cb->cb = (void (*)(struct us_internal_callback_t *)) cb; 401| | 402| 5.84k| us_poll_start((struct us_poll_t *) a, internal_cb->loop, LIBUS_SOCKET_READABLE); ------------------ | | 27| 5.84k|#define LIBUS_SOCKET_READABLE EPOLLIN ------------------ 403| 5.84k|} us_internal_async_wakeup: 405| 7.41k|void us_internal_async_wakeup(struct us_internal_async *a) { 406| 7.41k| uint64_t one = 1; 407| 7.41k| int written = write(us_poll_fd((struct us_poll_t *) a), &one, 8); 408| 7.41k| (void)written; 409| 7.41k|} us_internal_loop_data_init: 26| 5.84k| void (*pre_cb)(struct us_loop_t *loop), void (*post_cb)(struct us_loop_t *loop)) { 27| 5.84k| loop->data.sweep_timer = us_create_timer(loop, 1, 0); 28| 5.84k| loop->data.recv_buf = malloc(LIBUS_RECV_BUFFER_LENGTH + LIBUS_RECV_BUFFER_PADDING * 2); ------------------ | | 22| 5.84k|#define LIBUS_RECV_BUFFER_LENGTH 524288 ------------------ loop->data.recv_buf = malloc(LIBUS_RECV_BUFFER_LENGTH + LIBUS_RECV_BUFFER_PADDING * 2); ------------------ | | 26| 5.84k|#define LIBUS_RECV_BUFFER_PADDING 32 ------------------ 29| 5.84k| loop->data.ssl_data = 0; 30| 5.84k| loop->data.head = 0; 31| 5.84k| loop->data.iterator = 0; 32| 5.84k| loop->data.closed_head = 0; 33| 5.84k| loop->data.low_prio_head = 0; 34| 5.84k| loop->data.low_prio_budget = 0; 35| | 36| 5.84k| loop->data.pre_cb = pre_cb; 37| 5.84k| loop->data.post_cb = post_cb; 38| 5.84k| loop->data.iteration_nr = 0; 39| | 40| 5.84k| loop->data.wakeup_async = us_internal_create_async(loop, 1, 0); 41| 5.84k| us_internal_async_set(loop->data.wakeup_async, (void (*)(struct us_internal_async *)) wakeup_cb); 42| 5.84k|} us_internal_loop_data_free: 44| 5.84k|void us_internal_loop_data_free(struct us_loop_t *loop) { 45| |#ifndef LIBUS_NO_SSL 46| | us_internal_free_loop_ssl_data(loop); 47| |#endif 48| | 49| 5.84k| free(loop->data.recv_buf); 50| | 51| 5.84k| us_timer_close(loop->data.sweep_timer); 52| 5.84k| us_internal_async_close(loop->data.wakeup_async); 53| 5.84k|} us_wakeup_loop: 55| 7.41k|void us_wakeup_loop(struct us_loop_t *loop) { 56| 7.41k| us_internal_async_wakeup(loop->data.wakeup_async); 57| 7.41k|} us_internal_loop_link: 59| 17.5k|void us_internal_loop_link(struct us_loop_t *loop, struct us_socket_context_t *context) { 60| | /* Insert this context as the head of loop */ 61| 17.5k| context->next = loop->data.head; 62| 17.5k| context->prev = 0; 63| 17.5k| if (loop->data.head) { ------------------ | Branch (63:9): [True: 11.6k, False: 5.84k] ------------------ 64| 11.6k| loop->data.head->prev = context; 65| 11.6k| } 66| 17.5k| loop->data.head = context; 67| 17.5k|} us_internal_loop_unlink: 70| 17.5k|void us_internal_loop_unlink(struct us_loop_t *loop, struct us_socket_context_t *context) { 71| 17.5k| if (loop->data.head == context) { ------------------ | Branch (71:9): [True: 5.84k, False: 11.6k] ------------------ 72| 5.84k| loop->data.head = context->next; 73| 5.84k| if (loop->data.head) { ------------------ | Branch (73:13): [True: 0, False: 5.84k] ------------------ 74| 0| loop->data.head->prev = 0; 75| 0| } 76| 11.6k| } else { 77| 11.6k| context->prev->next = context->next; 78| 11.6k| if (context->next) { ------------------ | Branch (78:13): [True: 0, False: 11.6k] ------------------ 79| 0| context->next->prev = context->prev; 80| 0| } 81| 11.6k| } 82| 17.5k|} us_internal_timer_sweep: 85| 1.71M|void us_internal_timer_sweep(struct us_loop_t *loop) { 86| 1.71M| struct us_internal_loop_data_t *loop_data = &loop->data; 87| | /* For all socket contexts in this loop */ 88| 6.85M| for (loop_data->iterator = loop_data->head; loop_data->iterator; loop_data->iterator = loop_data->iterator->next) { ------------------ | Branch (88:49): [True: 5.13M, False: 1.71M] ------------------ 89| | 90| 5.13M| struct us_socket_context_t *context = loop_data->iterator; 91| | 92| | /* Update this context's timestamps (this could be moved to loop and done once) */ 93| 5.13M| context->global_tick++; 94| 5.13M| unsigned char short_ticks = context->timestamp = context->global_tick % 240; 95| 5.13M| unsigned char long_ticks = context->long_timestamp = (context->global_tick / 15) % 240; 96| | 97| | /* Begin at head */ 98| 5.13M| struct us_socket_t *s = context->head_sockets; 99| 5.16M| while (s) { ------------------ | Branch (99:16): [True: 233k, False: 4.93M] ------------------ 100| | /* Seek until end or timeout found (tightest loop) */ 101| 616k| while (1) { ------------------ | Branch (101:20): [Folded - Ignored] ------------------ 102| | /* We only read from 1 random cache line here */ 103| 616k| if (short_ticks == s->timeout || long_ticks == s->long_timeout) { ------------------ | Branch (103:21): [True: 30.3k, False: 585k] | Branch (103:50): [True: 0, False: 585k] ------------------ 104| 30.3k| break; 105| 30.3k| } 106| | 107| | /* Did we reach the end without a find? */ 108| 585k| if ((s = s->next) == 0) { ------------------ | Branch (108:21): [True: 203k, False: 382k] ------------------ 109| 203k| goto next_context; 110| 203k| } 111| 585k| } 112| | 113| | /* Here we have a timeout to emit (slow path) */ 114| 30.3k| context->iterator = s; 115| | 116| 30.3k| if (short_ticks == s->timeout) { ------------------ | Branch (116:17): [True: 30.3k, False: 0] ------------------ 117| 30.3k| s->timeout = 255; 118| 30.3k| context->on_socket_timeout(s); 119| 30.3k| } 120| | 121| 30.3k| if (context->iterator == s && long_ticks == s->long_timeout) { ------------------ | Branch (121:17): [True: 15.9k, False: 14.3k] | Branch (121:43): [True: 0, False: 15.9k] ------------------ 122| 0| s->long_timeout = 255; 123| 0| context->on_socket_long_timeout(s); 124| 0| } 125| | 126| | /* Check for unlink / link (if the event handler did not modify the chain, we step 1) */ 127| 30.3k| if (s == context->iterator) { ------------------ | Branch (127:17): [True: 15.9k, False: 14.3k] ------------------ 128| 15.9k| s = s->next; 129| 15.9k| } else { 130| | /* The iterator was changed by event handler */ 131| 14.3k| s = context->iterator; 132| 14.3k| } 133| 30.3k| } 134| | /* We always store a 0 to context->iterator here since we are no longer iterating this context */ 135| 5.13M| next_context: 136| 5.13M| context->iterator = 0; 137| 5.13M| } 138| 1.71M|} us_internal_handle_low_priority_sockets: 145| 2.18M|void us_internal_handle_low_priority_sockets(struct us_loop_t *loop) { 146| 2.18M| struct us_internal_loop_data_t *loop_data = &loop->data; 147| 2.18M| struct us_socket_t *s; 148| | 149| 2.18M| loop_data->low_prio_budget = MAX_LOW_PRIO_SOCKETS_PER_LOOP_ITERATION; 150| | 151| 2.18M| for (s = loop_data->low_prio_head; s && loop_data->low_prio_budget > 0; s = loop_data->low_prio_head, loop_data->low_prio_budget--) { ------------------ | Branch (151:40): [True: 0, False: 2.18M] | Branch (151:45): [True: 0, False: 0] ------------------ 152| | /* Unlink this socket from the low-priority queue */ 153| 0| loop_data->low_prio_head = s->next; 154| 0| if (s->next) s->next->prev = 0; ------------------ | Branch (154:13): [True: 0, False: 0] ------------------ 155| 0| s->next = 0; 156| | 157| 0| us_internal_socket_context_link_socket(s->context, s); 158| 0| us_poll_change(&s->p, us_socket_context(0, s)->loop, us_poll_events(&s->p) | LIBUS_SOCKET_READABLE); ------------------ | | 27| 0|#define LIBUS_SOCKET_READABLE EPOLLIN ------------------ 159| | 160| 0| s->low_prio_state = 2; 161| 0| } 162| 2.18M|} us_internal_free_closed_sockets: 165| 2.18M|void us_internal_free_closed_sockets(struct us_loop_t *loop) { 166| | /* Free all closed sockets (maybe it is better to reverse order?) */ 167| 2.18M| if (loop->data.closed_head) { ------------------ | Branch (167:9): [True: 342k, False: 1.84M] ------------------ 168| 1.98M| for (struct us_socket_t *s = loop->data.closed_head; s; ) { ------------------ | Branch (168:62): [True: 1.63M, False: 342k] ------------------ 169| 1.63M| struct us_socket_t *next = s->next; 170| 1.63M| us_poll_free((struct us_poll_t *) s, loop); 171| 1.63M| s = next; 172| 1.63M| } 173| 342k| loop->data.closed_head = 0; 174| 342k| } 175| 2.18M|} sweep_timer_cb: 177| 1.71M|void sweep_timer_cb(struct us_internal_callback_t *cb) { 178| 1.71M| us_internal_timer_sweep(cb->loop); 179| 1.71M|} us_internal_loop_pre: 186| 2.18M|void us_internal_loop_pre(struct us_loop_t *loop) { 187| 2.18M| loop->data.iteration_nr++; 188| 2.18M| us_internal_handle_low_priority_sockets(loop); 189| 2.18M| loop->data.pre_cb(loop); 190| 2.18M|} us_internal_loop_post: 192| 2.18M|void us_internal_loop_post(struct us_loop_t *loop) { 193| 2.18M| us_internal_free_closed_sockets(loop); 194| 2.18M| loop->data.post_cb(loop); 195| 2.18M|} us_adopt_accepted_socket: 198| 1.63M| unsigned int socket_ext_size, char *addr_ip, int addr_ip_length) { 199| |#ifndef LIBUS_NO_SSL 200| | if (ssl) { 201| | return (struct us_socket_t *)us_internal_ssl_adopt_accepted_socket((struct us_internal_ssl_socket_context_t *)context, accepted_fd, 202| | socket_ext_size, addr_ip, addr_ip_length); 203| | } 204| |#endif 205| 1.63M| struct us_poll_t *accepted_p = us_create_poll(context->loop, 0, sizeof(struct us_socket_t) - sizeof(struct us_poll_t) + socket_ext_size); 206| 1.63M| us_poll_init(accepted_p, accepted_fd, POLL_TYPE_SOCKET); 207| 1.63M| us_poll_start(accepted_p, context->loop, LIBUS_SOCKET_READABLE); ------------------ | | 27| 1.63M|#define LIBUS_SOCKET_READABLE EPOLLIN ------------------ 208| | 209| 1.63M| struct us_socket_t *s = (struct us_socket_t *) accepted_p; 210| | 211| 1.63M| s->context = context; 212| 1.63M| s->timeout = 255; 213| 1.63M| s->long_timeout = 255; 214| 1.63M| s->low_prio_state = 0; 215| | 216| | /* We always use nodelay */ 217| 1.63M| bsd_socket_nodelay(accepted_fd, 1); 218| | 219| 1.63M| us_internal_socket_context_link_socket(context, s); 220| | 221| 1.63M| context->on_open(s, 0, addr_ip, addr_ip_length); 222| 1.63M| return s; 223| 1.63M|} us_internal_dispatch_ready_poll: 225| 8.40M|void us_internal_dispatch_ready_poll(struct us_poll_t *p, int error, int events) { 226| 8.40M| switch (us_internal_poll_type(p)) { ------------------ | Branch (226:13): [True: 0, False: 8.40M] ------------------ 227| 4.97M| case POLL_TYPE_CALLBACK: { ------------------ | Branch (227:5): [True: 4.97M, False: 3.42M] ------------------ 228| 4.97M| struct us_internal_callback_t *cb = (struct us_internal_callback_t *) p; 229| | /* Timers, asyncs should accept (read), while UDP sockets should obviously not */ 230| 4.97M| if (!cb->leave_poll_ready) { ------------------ | Branch (230:17): [True: 4.97M, False: 0] ------------------ 231| | /* Let's just have this macro to silence the CodeQL alert regarding empty function when using libuv */ 232| 4.97M| #ifndef LIBUS_USE_LIBUV 233| 4.97M| us_internal_accept_poll_event(p); 234| 4.97M| #endif 235| 4.97M| } 236| 4.97M| cb->cb(cb->cb_expects_the_loop ? (struct us_internal_callback_t *) cb->loop : (struct us_internal_callback_t *) &cb->p); ------------------ | Branch (236:20): [True: 1.63M, False: 3.34M] ------------------ 237| 4.97M| } 238| 4.97M| break; 239| 1.56M| case POLL_TYPE_SEMI_SOCKET: { ------------------ | Branch (239:5): [True: 1.56M, False: 6.84M] ------------------ 240| | /* Both connect and listen sockets are semi-sockets 241| | * but they poll for different events */ 242| 1.56M| if (us_poll_events(p) == LIBUS_SOCKET_WRITABLE) { ------------------ | | 28| 1.56M|#define LIBUS_SOCKET_WRITABLE EPOLLOUT ------------------ | Branch (242:17): [True: 0, False: 1.56M] ------------------ 243| 0| struct us_socket_t *s = (struct us_socket_t *) p; 244| | 245| | /* It is perfectly possible to come here with an error */ 246| 0| if (error) { ------------------ | Branch (246:21): [True: 0, False: 0] ------------------ 247| | /* Emit error, close without emitting on_close */ 248| 0| s->context->on_connect_error(s, 0); 249| 0| us_socket_close_connecting(0, s); 250| 0| } else { 251| | /* All sockets poll for readable */ 252| 0| us_poll_change(p, s->context->loop, LIBUS_SOCKET_READABLE); ------------------ | | 27| 0|#define LIBUS_SOCKET_READABLE EPOLLIN ------------------ 253| | 254| | /* We always use nodelay */ 255| 0| bsd_socket_nodelay(us_poll_fd(p), 1); 256| | 257| | /* We are now a proper socket */ 258| 0| us_internal_poll_set_type(p, POLL_TYPE_SOCKET); 259| | 260| | /* If we used a connection timeout we have to reset it here */ 261| 0| us_socket_timeout(0, s, 0); 262| | 263| 0| s->context->on_open(s, 1, 0, 0); 264| 0| } 265| 1.56M| } else { 266| 1.56M| struct us_listen_socket_t *listen_socket = (struct us_listen_socket_t *) p; 267| 1.56M| struct bsd_addr_t addr; 268| | 269| 1.56M| LIBUS_SOCKET_DESCRIPTOR client_fd = bsd_accept_socket(us_poll_fd(p), &addr); ------------------ | | 38| 1.56M|#define LIBUS_SOCKET_DESCRIPTOR int ------------------ 270| 1.56M| if (client_fd == LIBUS_SOCKET_ERROR) { ------------------ | | 44| 1.56M|#define LIBUS_SOCKET_ERROR -1 ------------------ | Branch (270:21): [True: 1.30M, False: 261k] ------------------ 271| | /* Todo: start timer here */ 272| | 273| 1.30M| } else { 274| | 275| | /* Todo: stop timer if any */ 276| | 277| 1.63M| do { 278| 1.63M| struct us_socket_context_t *context = us_socket_context(0, &listen_socket->s); 279| | /* See if we want to export the FD or keep it here (this event can be unset) */ 280| 1.63M| if (context->on_pre_open == 0 || context->on_pre_open(client_fd) == client_fd) { ------------------ | Branch (280:29): [True: 1.63M, False: 0] | Branch (280:58): [True: 0, False: 0] ------------------ 281| | 282| | /* Adopt the newly accepted socket */ 283| 1.63M| us_adopt_accepted_socket(0, context, 284| 1.63M| client_fd, listen_socket->socket_ext_size, bsd_addr_get_ip(&addr), bsd_addr_get_ip_length(&addr)); 285| | 286| | /* Exit accept loop if listen socket was closed in on_open handler */ 287| 1.63M| if (us_socket_is_closed(0, &listen_socket->s)) { ------------------ | Branch (287:33): [True: 0, False: 1.63M] ------------------ 288| 0| break; 289| 0| } 290| | 291| 1.63M| } 292| | 293| 1.63M| } while ((client_fd = bsd_accept_socket(us_poll_fd(p), &addr)) != LIBUS_SOCKET_ERROR); ------------------ | | 44| 1.63M|#define LIBUS_SOCKET_ERROR -1 ------------------ | Branch (293:30): [True: 1.37M, False: 261k] ------------------ 294| 261k| } 295| 1.56M| } 296| 1.56M| } 297| 0| break; 298| 1.90k| case POLL_TYPE_SOCKET_SHUT_DOWN: ------------------ | Branch (298:5): [True: 1.90k, False: 8.40M] ------------------ 299| 1.86M| case POLL_TYPE_SOCKET: { ------------------ | Branch (299:5): [True: 1.86M, False: 6.54M] ------------------ 300| | /* We should only use s, no p after this point */ 301| 1.86M| struct us_socket_t *s = (struct us_socket_t *) p; 302| | 303| | /* Such as epollerr epollhup */ 304| 1.86M| if (error) { ------------------ | Branch (304:17): [True: 1.11M, False: 751k] ------------------ 305| | /* Todo: decide what code we give here */ 306| 1.11M| s = us_socket_close(0, s, 0, NULL); 307| 1.11M| return; 308| 1.11M| } 309| | 310| 751k| if (events & LIBUS_SOCKET_WRITABLE) { ------------------ | | 28| 751k|#define LIBUS_SOCKET_WRITABLE EPOLLOUT ------------------ | Branch (310:17): [True: 32.8k, False: 718k] ------------------ 311| | /* Note: if we failed a write as a socket of one loop then adopted 312| | * to another loop, this will be wrong. Absurd case though */ 313| 32.8k| s->context->loop->data.last_write_failed = 0; 314| | 315| 32.8k| s = s->context->on_writable(s); 316| | 317| 32.8k| if (us_socket_is_closed(0, s)) { ------------------ | Branch (317:21): [True: 203, False: 32.6k] ------------------ 318| 203| return; 319| 203| } 320| | 321| | /* If we have no failed write or if we shut down, then stop polling for more writable */ 322| 32.6k| if (!s->context->loop->data.last_write_failed || us_socket_is_shut_down(0, s)) { ------------------ | Branch (322:21): [True: 10.2k, False: 22.4k] | Branch (322:66): [True: 0, False: 22.4k] ------------------ 323| 10.2k| us_poll_change(&s->p, us_socket_context(0, s)->loop, us_poll_events(&s->p) & LIBUS_SOCKET_READABLE); ------------------ | | 27| 10.2k|#define LIBUS_SOCKET_READABLE EPOLLIN ------------------ 324| 10.2k| } 325| 32.6k| } 326| | 327| 751k| if (events & LIBUS_SOCKET_READABLE) { ------------------ | | 27| 751k|#define LIBUS_SOCKET_READABLE EPOLLIN ------------------ | Branch (327:17): [True: 732k, False: 18.8k] ------------------ 328| | /* Contexts may prioritize down sockets that are currently readable, e.g. when SSL handshake has to be done. 329| | * SSL handshakes are CPU intensive, so we limit the number of handshakes per loop iteration, and move the rest 330| | * to the low-priority queue */ 331| 732k| if (s->context->is_low_prio(s)) { ------------------ | Branch (331:21): [True: 0, False: 732k] ------------------ 332| 0| if (s->low_prio_state == 2) { ------------------ | Branch (332:25): [True: 0, False: 0] ------------------ 333| 0| s->low_prio_state = 0; /* Socket has been delayed and now it's time to process incoming data for one iteration */ 334| 0| } else if (s->context->loop->data.low_prio_budget > 0) { ------------------ | Branch (334:32): [True: 0, False: 0] ------------------ 335| 0| s->context->loop->data.low_prio_budget--; /* Still having budget for this iteration - do normal processing */ 336| 0| } else { 337| 0| us_poll_change(&s->p, us_socket_context(0, s)->loop, us_poll_events(&s->p) & LIBUS_SOCKET_WRITABLE); ------------------ | | 28| 0|#define LIBUS_SOCKET_WRITABLE EPOLLOUT ------------------ 338| 0| us_internal_socket_context_unlink_socket(s->context, s); 339| | 340| | /* Link this socket to the low-priority queue - we use a LIFO queue, to prioritize newer clients that are 341| | * maybe not already timeouted - sounds unfair, but works better in real-life with smaller client-timeouts 342| | * under high load */ 343| 0| s->prev = 0; 344| 0| s->next = s->context->loop->data.low_prio_head; 345| 0| if (s->next) s->next->prev = s; ------------------ | Branch (345:29): [True: 0, False: 0] ------------------ 346| 0| s->context->loop->data.low_prio_head = s; 347| | 348| 0| s->low_prio_state = 1; 349| | 350| 0| break; 351| 0| } 352| 0| } 353| | 354| 732k| int length; 355| 732k| read_more: 356| 732k| length = bsd_recv(us_poll_fd(&s->p), s->context->loop->data.recv_buf + LIBUS_RECV_BUFFER_PADDING, LIBUS_RECV_BUFFER_LENGTH, 0); ------------------ | | 26| 732k|#define LIBUS_RECV_BUFFER_PADDING 32 ------------------ length = bsd_recv(us_poll_fd(&s->p), s->context->loop->data.recv_buf + LIBUS_RECV_BUFFER_PADDING, LIBUS_RECV_BUFFER_LENGTH, 0); ------------------ | | 22| 732k|#define LIBUS_RECV_BUFFER_LENGTH 524288 ------------------ 357| 732k| if (length > 0) { ------------------ | Branch (357:21): [True: 638k, False: 93.8k] ------------------ 358| 638k| s = s->context->on_data(s, s->context->loop->data.recv_buf + LIBUS_RECV_BUFFER_PADDING, length); ------------------ | | 26| 638k|#define LIBUS_RECV_BUFFER_PADDING 32 ------------------ 359| | 360| | /* If we filled the entire recv buffer, we need to immediately read again since otherwise a 361| | * pending hangup event in the same even loop iteration can close the socket before we get 362| | * the chance to read again next iteration */ 363| 638k| if (length == LIBUS_RECV_BUFFER_LENGTH && s && !us_socket_is_closed(0, s)) { ------------------ | | 22| 1.27M|#define LIBUS_RECV_BUFFER_LENGTH 524288 ------------------ | Branch (363:25): [True: 0, False: 638k] | Branch (363:63): [True: 0, False: 0] | Branch (363:68): [True: 0, False: 0] ------------------ 364| 0| goto read_more; 365| 0| } 366| | 367| 638k| } else if (!length) { ------------------ | Branch (367:28): [True: 85.8k, False: 8.02k] ------------------ 368| 85.8k| if (us_socket_is_shut_down(0, s)) { ------------------ | Branch (368:25): [True: 298, False: 85.5k] ------------------ 369| | /* We got FIN back after sending it */ 370| | /* Todo: We should give "CLEAN SHUTDOWN" as reason here */ 371| 298| s = us_socket_close(0, s, 0, NULL); 372| 85.5k| } else { 373| | /* We got FIN, so stop polling for readable */ 374| 85.5k| us_poll_change(&s->p, us_socket_context(0, s)->loop, us_poll_events(&s->p) & LIBUS_SOCKET_WRITABLE); ------------------ | | 28| 85.5k|#define LIBUS_SOCKET_WRITABLE EPOLLOUT ------------------ 375| 85.5k| s = s->context->on_end(s); 376| 85.5k| } 377| 85.8k| } else if (length == LIBUS_SOCKET_ERROR && !bsd_would_block()) { ------------------ | | 44| 16.0k|#define LIBUS_SOCKET_ERROR -1 ------------------ | Branch (377:28): [True: 8.02k, False: 0] | Branch (377:60): [True: 0, False: 8.02k] ------------------ 378| | /* Todo: decide also here what kind of reason we should give */ 379| 0| s = us_socket_close(0, s, 0, NULL); 380| 0| } 381| 732k| } 382| 751k| } 383| 751k| break; 384| 8.40M| } 385| 8.40M|} us_loop_integrate: 388| 5.84k|void us_loop_integrate(struct us_loop_t *loop) { 389| 5.84k| us_timer_set(loop->data.sweep_timer, (void (*)(struct us_timer_t *)) sweep_timer_cb, LIBUS_TIMEOUT_GRANULARITY * 1000, LIBUS_TIMEOUT_GRANULARITY * 1000); ------------------ | | 24| 5.84k|#define LIBUS_TIMEOUT_GRANULARITY 4 ------------------ us_timer_set(loop->data.sweep_timer, (void (*)(struct us_timer_t *)) sweep_timer_cb, LIBUS_TIMEOUT_GRANULARITY * 1000, LIBUS_TIMEOUT_GRANULARITY * 1000); ------------------ | | 24| 5.84k|#define LIBUS_TIMEOUT_GRANULARITY 4 ------------------ 390| 5.84k|} us_loop_ext: 392| 13.4M|void *us_loop_ext(struct us_loop_t *loop) { 393| 13.4M| return loop + 1; 394| 13.4M|} us_socket_context: 61| 13.6M|struct us_socket_context_t *us_socket_context(int ssl, struct us_socket_t *s) { 62| 13.6M| return s->context; 63| 13.6M|} us_socket_timeout: 65| 2.23M|void us_socket_timeout(int ssl, struct us_socket_t *s, unsigned int seconds) { 66| 2.23M| if (seconds) { ------------------ | Branch (66:9): [True: 2.06M, False: 171k] ------------------ 67| 2.06M| s->timeout = ((unsigned int)s->context->timestamp + ((seconds + 3) >> 2)) % 240; 68| 2.06M| } else { 69| 171k| s->timeout = 255; 70| 171k| } 71| 2.23M|} us_socket_long_timeout: 73| 164k|void us_socket_long_timeout(int ssl, struct us_socket_t *s, unsigned int minutes) { 74| 164k| if (minutes) { ------------------ | Branch (74:9): [True: 0, False: 164k] ------------------ 75| 0| s->long_timeout = ((unsigned int)s->context->long_timestamp + minutes) % 240; 76| 164k| } else { 77| 164k| s->long_timeout = 255; 78| 164k| } 79| 164k|} us_socket_is_closed: 87| 9.58M|int us_socket_is_closed(int ssl, struct us_socket_t *s) { 88| 9.58M| return s->prev == (struct us_socket_t *) s->context; 89| 9.58M|} us_socket_close: 116| 1.63M|struct us_socket_t *us_socket_close(int ssl, struct us_socket_t *s, int code, void *reason) { 117| 1.63M| if (!us_socket_is_closed(0, s)) { ------------------ | Branch (117:9): [True: 1.63M, False: 0] ------------------ 118| 1.63M| if (s->low_prio_state == 1) { ------------------ | Branch (118:13): [True: 0, False: 1.63M] ------------------ 119| | /* Unlink this socket from the low-priority queue */ 120| 0| if (!s->prev) s->context->loop->data.low_prio_head = s->next; ------------------ | Branch (120:17): [True: 0, False: 0] ------------------ 121| 0| else s->prev->next = s->next; 122| | 123| 0| if (s->next) s->next->prev = s->prev; ------------------ | Branch (123:17): [True: 0, False: 0] ------------------ 124| | 125| 0| s->prev = 0; 126| 0| s->next = 0; 127| 0| s->low_prio_state = 0; 128| 1.63M| } else { 129| 1.63M| us_internal_socket_context_unlink_socket(s->context, s); 130| 1.63M| } 131| 1.63M| us_poll_stop((struct us_poll_t *) s, s->context->loop); 132| 1.63M| bsd_close_socket(us_poll_fd((struct us_poll_t *) s)); 133| | 134| | /* Link this socket to the close-list and let it be deleted after this iteration */ 135| 1.63M| s->next = s->context->loop->data.closed_head; 136| 1.63M| s->context->loop->data.closed_head = s; 137| | 138| | /* Any socket with prev = context is marked as closed */ 139| 1.63M| s->prev = (struct us_socket_t *) s->context; 140| | 141| 1.63M| return s->context->on_close(s, code, reason); 142| 1.63M| } 143| 0| return s; 144| 1.63M|} us_socket_write: 173| 696k|int us_socket_write(int ssl, struct us_socket_t *s, const char *data, int length, int msg_more) { 174| |#ifndef LIBUS_NO_SSL 175| | if (ssl) { 176| | return us_internal_ssl_socket_write((struct us_internal_ssl_socket_t *) s, data, length, msg_more); 177| | } 178| |#endif 179| | 180| 696k| if (us_socket_is_closed(ssl, s) || us_socket_is_shut_down(ssl, s)) { ------------------ | Branch (180:9): [True: 0, False: 696k] | Branch (180:40): [True: 0, False: 696k] ------------------ 181| 0| return 0; 182| 0| } 183| | 184| 696k| int written = bsd_send(us_poll_fd(&s->p), data, length, msg_more); 185| 696k| if (written != length) { ------------------ | Branch (185:9): [True: 665k, False: 31.5k] ------------------ 186| 665k| s->context->loop->data.last_write_failed = 1; 187| 665k| us_poll_change(&s->p, s->context->loop, LIBUS_SOCKET_READABLE | LIBUS_SOCKET_WRITABLE); ------------------ | | 27| 665k|#define LIBUS_SOCKET_READABLE EPOLLIN ------------------ us_poll_change(&s->p, s->context->loop, LIBUS_SOCKET_READABLE | LIBUS_SOCKET_WRITABLE); ------------------ | | 28| 665k|#define LIBUS_SOCKET_WRITABLE EPOLLOUT ------------------ 188| 665k| } 189| | 190| 696k| return written < 0 ? 0 : written; ------------------ | Branch (190:12): [True: 19.7k, False: 677k] ------------------ 191| 696k|} us_socket_ext: 193| 11.4M|void *us_socket_ext(int ssl, struct us_socket_t *s) { 194| |#ifndef LIBUS_NO_SSL 195| | if (ssl) { 196| | return us_internal_ssl_socket_ext((struct us_internal_ssl_socket_t *) s); 197| | } 198| |#endif 199| | 200| 11.4M| return s + 1; 201| 11.4M|} us_socket_is_shut_down: 203| 1.83M|int us_socket_is_shut_down(int ssl, struct us_socket_t *s) { 204| |#ifndef LIBUS_NO_SSL 205| | if (ssl) { 206| | return us_internal_ssl_socket_is_shut_down((struct us_internal_ssl_socket_t *) s); 207| | } 208| |#endif 209| | 210| 1.83M| return us_internal_poll_type(&s->p) == POLL_TYPE_SOCKET_SHUT_DOWN; 211| 1.83M|} us_socket_shutdown: 213| 401k|void us_socket_shutdown(int ssl, struct us_socket_t *s) { 214| |#ifndef LIBUS_NO_SSL 215| | if (ssl) { 216| | us_internal_ssl_socket_shutdown((struct us_internal_ssl_socket_t *) s); 217| | return; 218| | } 219| |#endif 220| | 221| | /* Todo: should we emit on_close if calling shutdown on an already half-closed socket? 222| | * We need more states in that case, we need to track RECEIVED_FIN 223| | * so far, the app has to track this and call close as needed */ 224| 401k| if (!us_socket_is_closed(ssl, s) && !us_socket_is_shut_down(ssl, s)) { ------------------ | Branch (224:9): [True: 401k, False: 0] | Branch (224:41): [True: 401k, False: 269] ------------------ 225| 401k| us_internal_poll_set_type(&s->p, POLL_TYPE_SOCKET_SHUT_DOWN); 226| 401k| us_poll_change(&s->p, s->context->loop, us_poll_events(&s->p) & LIBUS_SOCKET_READABLE); ------------------ | | 27| 401k|#define LIBUS_SOCKET_READABLE EPOLLIN ------------------ 227| 401k| bsd_shutdown_socket(us_poll_fd((struct us_poll_t *) s)); 228| 401k| } 229| 401k|} _Z4testv: 10| 5.84k|void test() { 11| | 12| 5.84k| struct PerSocketData { 13| 5.84k| int nothing; 14| 5.84k| std::shared_ptr valid; 15| 5.84k| }; 16| | 17| | /* First byte determines what compressor to use */ 18| 5.84k| unsigned char compressorByte; 19| 5.84k| if (consume_byte(&compressorByte)) { ------------------ | Branch (19:9): [True: 0, False: 5.84k] ------------------ 20| | //uWS::Loop::get()->free(); 21| 0| return; 22| 0| } 23| | 24| 5.84k| uWS::CompressOptions compressors[] = { 25| 5.84k| uWS::DISABLED, 26| 5.84k| uWS::SHARED_COMPRESSOR, 27| 5.84k| uWS::DEDICATED_COMPRESSOR_3KB, 28| 5.84k| uWS::DEDICATED_COMPRESSOR_4KB, 29| 5.84k| uWS::DEDICATED_COMPRESSOR_8KB, 30| 5.84k| uWS::DEDICATED_COMPRESSOR_16KB, 31| 5.84k| uWS::DEDICATED_COMPRESSOR_32KB, 32| 5.84k| uWS::DEDICATED_COMPRESSOR_64KB, 33| 5.84k| uWS::DEDICATED_COMPRESSOR_128KB, 34| 5.84k| uWS::DEDICATED_COMPRESSOR_256KB 35| 5.84k| }; 36| | 37| 5.84k| uWS::CompressOptions compressor = compressors[compressorByte % 10]; 38| | 39| 5.84k| { 40| 5.84k| auto app = uWS::App().ws("/broadcast", { 41| | /* Settings */ 42| 5.84k| .compression = compressor, 43| | /* We want this to be low so that we can hit it, yet bigger than 256 */ 44| 5.84k| .maxPayloadLength = 300, 45| 5.84k| .idleTimeout = 12, 46| | /* Handlers */ 47| 5.84k| .open = [](auto *ws) { 48| | /* Subscribe to anything */ 49| 5.84k| ws->subscribe(/*req->getHeader(*/"topic"/*)*/); 50| 5.84k| }, 51| 5.84k| .message = [](auto *ws, std::string_view message, uWS::OpCode opCode) { 52| 5.84k| if (message.length() && message[0] == 'C') { 53| 5.84k| ws->close(); 54| 5.84k| } else if (message.length() && message[0] == 'E') { 55| 5.84k| ws->end(1006); 56| 5.84k| } else { 57| | /* Publish to topic sent by message */ 58| 5.84k| ws->publish(message, message, opCode, true); 59| | 60| 5.84k| if (message.length() && message[0] == 'U') { 61| 5.84k| ws->unsubscribe(message); 62| 5.84k| } 63| 5.84k| } 64| 5.84k| }, 65| 5.84k| .drain = [](auto *ws) { 66| | /* Check getBufferedAmount here */ 67| 5.84k| }, 68| 5.84k| .ping = [](auto *ws, std::string_view) { 69| | 70| 5.84k| }, 71| 5.84k| .pong = [](auto *ws, std::string_view) { 72| | 73| 5.84k| }, 74| 5.84k| .close = [](auto *ws, int code, std::string_view message) { 75| | /* Cause reported crash */ 76| 5.84k| ws->close(); 77| 5.84k| } 78| 5.84k| }).ws("/*", { 79| | /* Settings */ 80| 5.84k| .compression = compressor, 81| | /* We want this to be low so that we can hit it, yet bigger than 256 */ 82| 5.84k| .maxPayloadLength = 300, 83| 5.84k| .idleTimeout = 12, 84| | /* Handlers */ 85| 5.84k| .open = [](auto *ws) { 86| | 87| 5.84k| ws->getUserData()->valid.reset(new bool{true}); 88| | 89| | //if (req->getHeader("close_me").length()) { 90| | // ws->close(); 91| | //} else if (req->getHeader("end_me").length()) { 92| | // ws->end(1006); 93| | //} 94| 5.84k| }, 95| 5.84k| .message = [](auto *ws, std::string_view message, uWS::OpCode opCode) { 96| 5.84k| if (message.length() > 300) { 97| | /* Inform the sanitizer of the fault */ 98| 5.84k| fprintf(stderr, "Too long message passed\n"); 99| 5.84k| free((void *) -1); 100| 5.84k| } 101| | 102| 5.84k| if (message.length() && message[0] == 'C') { 103| 5.84k| ws->close(); 104| 5.84k| } else if (message.length() && message[0] == 'E') { 105| 5.84k| ws->end(1006); 106| 5.84k| } else { 107| 5.84k| ws->send(message, opCode, true); 108| 5.84k| } 109| 5.84k| }, 110| 5.84k| .drain = [](auto *ws) { 111| | /* Check getBufferedAmount here */ 112| 5.84k| }, 113| 5.84k| .ping = [](auto *ws, std::string_view) { 114| | /* Here we test send and end while uncorked, by having them send from deferred */ 115| 5.84k| PerSocketData *psd = (PerSocketData *) ws->getUserData(); 116| | 117| 5.84k| uWS::Loop::get()->defer([ws, valid = psd->valid]() { 118| 5.84k| if (*valid.get()) { 119| | /* We haven't been closed */ 120| 5.84k| ws->send("Hello!", uWS::TEXT, false); 121| 5.84k| ws->end(1000); 122| 5.84k| } 123| 5.84k| }); 124| 5.84k| }, 125| 5.84k| .pong = [](auto *ws, std::string_view) { 126| | 127| 5.84k| }, 128| 5.84k| .close = [](auto *ws, int code, std::string_view message) { 129| 5.84k| (*ws->getUserData()->valid.get()) = false; 130| 5.84k| } 131| 5.84k| }).listen(9001, [](us_listen_socket_t *listenSocket) { 132| 5.84k| listen_socket = listenSocket; 133| 5.84k| }); 134| | 135| 5.84k| app.run(); 136| 5.84k| } 137| | 138| 5.84k| uWS::Loop::get()->free(); 139| 5.84k|} _Z8teardownv: 142| 5.83k|void teardown() { 143| | /* If we are called twice there's a bug (it potentially could if 144| | * all open sockets cannot be error-closed in one epoll_wait call). 145| | * But we only allow 1k FDs and we have a buffer of 1024 from epoll_wait */ 146| 5.83k| if (!listen_socket) { ------------------ | Branch (146:6): [True: 0, False: 5.83k] ------------------ 147| 0| exit(-1); 148| 0| } 149| | 150| | /* We might have open sockets still, and these will be error-closed by epoll_wait */ 151| | // us_socket_context_close - close all open sockets created with this socket context 152| 5.83k| if (listen_socket) { ------------------ | Branch (152:9): [True: 5.83k, False: 0] ------------------ 153| 5.83k| us_listen_socket_close(0, listen_socket); 154| 5.83k| listen_socket = NULL; 155| 5.83k| } 156| 5.83k|} EpollEchoServer.cpp:_ZZ4testvENK3$_0clIN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEEDaPT_: 47| 130k| .open = [](auto *ws) { 48| | /* Subscribe to anything */ 49| 130k| ws->subscribe(/*req->getHeader(*/"topic"/*)*/); 50| 130k| }, EpollEchoServer.cpp:_ZZ4testvENK3$_1clIN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEEDaPT_NSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS1_6OpCodeE: 51| 29.1k| .message = [](auto *ws, std::string_view message, uWS::OpCode opCode) { 52| 29.1k| if (message.length() && message[0] == 'C') { ------------------ | Branch (52:21): [True: 28.7k, False: 407] | Branch (52:41): [True: 265, False: 28.4k] ------------------ 53| 265| ws->close(); 54| 28.8k| } else if (message.length() && message[0] == 'E') { ------------------ | Branch (54:28): [True: 28.4k, False: 407] | Branch (54:48): [True: 195, False: 28.2k] ------------------ 55| 195| ws->end(1006); 56| 28.6k| } else { 57| | /* Publish to topic sent by message */ 58| 28.6k| ws->publish(message, message, opCode, true); 59| | 60| 28.6k| if (message.length() && message[0] == 'U') { ------------------ | Branch (60:25): [True: 28.2k, False: 407] | Branch (60:45): [True: 1.01k, False: 27.2k] ------------------ 61| 1.01k| ws->unsubscribe(message); 62| 1.01k| } 63| 28.6k| } 64| 29.1k| }, EpollEchoServer.cpp:_ZZ4testvENK3$_2clIN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEEDaPT_: 65| 19.4k| .drain = [](auto *ws) { 66| | /* Check getBufferedAmount here */ 67| 19.4k| }, EpollEchoServer.cpp:_ZZ4testvENK3$_3clIN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEEDaPT_NSt3__117basic_string_viewIcNS7_11char_traitsIcEEEE: 68| 3.94k| .ping = [](auto *ws, std::string_view) { 69| | 70| 3.94k| }, EpollEchoServer.cpp:_ZZ4testvENK3$_4clIN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEEDaPT_NSt3__117basic_string_viewIcNS7_11char_traitsIcEEEE: 71| 1.49k| .pong = [](auto *ws, std::string_view) { 72| | 73| 1.49k| }, EpollEchoServer.cpp:_ZZ4testvENK3$_5clIN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEEDaPT_iNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEE: 74| 130k| .close = [](auto *ws, int code, std::string_view message) { 75| | /* Cause reported crash */ 76| 130k| ws->close(); 77| 130k| } EpollEchoServer.cpp:_ZZ4testvENK3$_6clIN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEEDaPT_: 85| 33.8k| .open = [](auto *ws) { 86| | 87| 33.8k| ws->getUserData()->valid.reset(new bool{true}); 88| | 89| | //if (req->getHeader("close_me").length()) { 90| | // ws->close(); 91| | //} else if (req->getHeader("end_me").length()) { 92| | // ws->end(1006); 93| | //} 94| 33.8k| }, EpollEchoServer.cpp:_ZZ4testvENK3$_7clIN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEEDaPT_NSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS1_6OpCodeE: 95| 9.49k| .message = [](auto *ws, std::string_view message, uWS::OpCode opCode) { 96| 9.49k| if (message.length() > 300) { ------------------ | Branch (96:21): [True: 0, False: 9.49k] ------------------ 97| | /* Inform the sanitizer of the fault */ 98| 0| fprintf(stderr, "Too long message passed\n"); 99| 0| free((void *) -1); 100| 0| } 101| | 102| 9.49k| if (message.length() && message[0] == 'C') { ------------------ | Branch (102:21): [True: 7.43k, False: 2.06k] | Branch (102:41): [True: 288, False: 7.14k] ------------------ 103| 288| ws->close(); 104| 9.20k| } else if (message.length() && message[0] == 'E') { ------------------ | Branch (104:28): [True: 7.14k, False: 2.06k] | Branch (104:48): [True: 398, False: 6.74k] ------------------ 105| 398| ws->end(1006); 106| 8.81k| } else { 107| 8.81k| ws->send(message, opCode, true); 108| 8.81k| } 109| 9.49k| }, EpollEchoServer.cpp:_ZZ4testvENK3$_8clIN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEEDaPT_: 110| 5.43k| .drain = [](auto *ws) { 111| | /* Check getBufferedAmount here */ 112| 5.43k| }, EpollEchoServer.cpp:_ZZ4testvENK3$_9clIN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEEDaPT_NSt3__117basic_string_viewIcNS7_11char_traitsIcEEEE: 113| 7.41k| .ping = [](auto *ws, std::string_view) { 114| | /* Here we test send and end while uncorked, by having them send from deferred */ 115| 7.41k| PerSocketData *psd = (PerSocketData *) ws->getUserData(); 116| | 117| 7.41k| uWS::Loop::get()->defer([ws, valid = psd->valid]() { 118| 7.41k| if (*valid.get()) { 119| | /* We haven't been closed */ 120| 7.41k| ws->send("Hello!", uWS::TEXT, false); 121| 7.41k| ws->end(1000); 122| 7.41k| } 123| 7.41k| }); 124| 7.41k| }, EpollEchoServer.cpp:_ZZZ4testvENK3$_9clIN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEEDaPT_NSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEENKUlvE_clEv: 117| 3.78k| uWS::Loop::get()->defer([ws, valid = psd->valid]() { 118| 3.78k| if (*valid.get()) { ------------------ | Branch (118:25): [True: 1.50k, False: 2.27k] ------------------ 119| | /* We haven't been closed */ 120| 1.50k| ws->send("Hello!", uWS::TEXT, false); 121| 1.50k| ws->end(1000); 122| 1.50k| } 123| 3.78k| }); EpollEchoServer.cpp:_ZZ4testvENK4$_10clIN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEEDaPT_NSt3__117basic_string_viewIcNS7_11char_traitsIcEEEE: 125| 2.06k| .pong = [](auto *ws, std::string_view) { 126| | 127| 2.06k| }, EpollEchoServer.cpp:_ZZ4testvENK4$_11clIN3uWS9WebSocketILb0ELb1EZ4testvE13PerSocketDataEEEEDaPT_iNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEE: 128| 33.8k| .close = [](auto *ws, int code, std::string_view message) { 129| 33.8k| (*ws->getUserData()->valid.get()) = false; 130| 33.8k| } EpollEchoServer.cpp:_ZZ4testvENK4$_12clEP18us_listen_socket_t: 131| 5.84k| }).listen(9001, [](us_listen_socket_t *listenSocket) { 132| 5.84k| listen_socket = listenSocket; 133| 5.84k| }); set_consumable_data: 71| 5.84k|void set_consumable_data(const unsigned char *new_data, int new_length) { 72| 5.84k| consumable_data = (unsigned char *) new_data; 73| 5.84k| consumable_data_length = new_length; 74| 5.84k|} consume_byte: 77| 3.21M|int consume_byte(unsigned char *b) { 78| 3.21M| if (consumable_data_length) { ------------------ | Branch (78:6): [True: 3.20M, False: 4.34k] ------------------ 79| 3.20M| *b = consumable_data[0]; 80| 3.20M| consumable_data++; 81| 3.20M| consumable_data_length--; 82| 3.20M| return 0; 83| 3.20M| } 84| 4.34k| return -1; 85| 3.21M|} allocate_fd: 90| 1.66M|int allocate_fd() { 91| | // this can be massively optimized by having a list of free blocks or the like 92| 218M| for (int fd = 0; fd < MAX_FDS; fd++) { ------------------ | Branch (92:19): [True: 218M, False: 405] ------------------ 93| 218M| if (!fd_to_file[fd]) { ------------------ | Branch (93:7): [True: 1.66M, False: 216M] ------------------ 94| 1.66M| num_fds++; 95| 1.66M| return fd + RESERVED_SYSTEM_FDS; 96| 1.66M| } 97| 218M| } 98| 405| return -1; 99| 1.66M|} init_fd: 102| 1.66M|void init_fd(int fd, int type, struct file *f) { 103| 1.66M| if (fd >= RESERVED_SYSTEM_FDS) { ------------------ | Branch (103:6): [True: 1.66M, False: 0] ------------------ 104| 1.66M| fd_to_file[fd - RESERVED_SYSTEM_FDS] = f; 105| 1.66M| fd_to_file[fd - RESERVED_SYSTEM_FDS]->type = type; 106| 1.66M| fd_to_file[fd - RESERVED_SYSTEM_FDS]->next = NULL; 107| 1.66M| fd_to_file[fd - RESERVED_SYSTEM_FDS]->prev = NULL; 108| 1.66M| } 109| 1.66M|} map_fd: 111| 18.2M|struct file *map_fd(int fd) { 112| 18.2M| if (fd >= RESERVED_SYSTEM_FDS && fd < MAX_FDS + RESERVED_SYSTEM_FDS) { ------------------ | Branch (112:6): [True: 18.2M, False: 0] | Branch (112:35): [True: 18.2M, False: 0] ------------------ 113| 18.2M| return fd_to_file[fd - RESERVED_SYSTEM_FDS]; 114| 18.2M| } 115| 0| return NULL; 116| 18.2M|} free_fd: 119| 1.66M|int free_fd(int fd) { 120| 1.66M| if (fd >= RESERVED_SYSTEM_FDS && fd < MAX_FDS + RESERVED_SYSTEM_FDS) { ------------------ | Branch (120:6): [True: 1.66M, False: 0] | Branch (120:35): [True: 1.66M, False: 0] ------------------ 121| 1.66M| if (fd_to_file[fd - RESERVED_SYSTEM_FDS]) { ------------------ | Branch (121:7): [True: 1.66M, False: 0] ------------------ 122| 1.66M| fd_to_file[fd - RESERVED_SYSTEM_FDS] = 0; 123| 1.66M| num_fds--; 124| 1.66M| return 0; 125| 1.66M| } 126| 1.66M| } 127| | 128| 0| return -1; 129| 1.66M|} __wrap_epoll_create1: 141| 5.84k|int __wrap_epoll_create1(int flags) { 142| | 143| | /* Todo: check that we do not allocate more than one epoll FD */ 144| 5.84k| int fd = allocate_fd(); 145| | 146| 5.84k| if (fd != -1) { ------------------ | Branch (146:6): [True: 5.84k, False: 0] ------------------ 147| 5.84k| struct epoll_file *ef = (struct epoll_file *)malloc(sizeof(struct epoll_file)); 148| | 149| | /* Init the epoll_file */ 150| 5.84k| ef->poll_set_head = NULL; 151| 5.84k| ef->poll_set_tail = NULL; 152| | 153| 5.84k| init_fd(fd, FD_TYPE_EPOLL, (struct file *)ef); 154| 5.84k| } 155| | 156| |#ifdef PRINTF_DEBUG 157| | printf("epoll_create1 returning epfd: %d\n", fd); 158| |#endif 159| | 160| 5.84k| return fd; 161| 5.84k|} __wrap_epoll_ctl: 165| 4.35M|int __wrap_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) { 166| | 167| 4.35M| struct epoll_file *ef = (struct epoll_file *)map_fd(epfd); 168| 4.35M| if (!ef) { ------------------ | Branch (168:6): [True: 0, False: 4.35M] ------------------ 169| 0| return -1; 170| 0| } 171| | 172| 4.35M| struct file *f = (struct file *)map_fd(fd); 173| 4.35M| if (!f) { ------------------ | Branch (173:6): [True: 0, False: 4.35M] ------------------ 174| 0| return -1; 175| 0| } 176| | 177| | /* We add new polls in the head */ 178| 4.35M| if (op == EPOLL_CTL_ADD) { ------------------ | Branch (178:6): [True: 1.65M, False: 2.69M] ------------------ 179| | // if there is a head already 180| 1.65M| if (ef->poll_set_head) { ------------------ | Branch (180:7): [True: 1.64M, False: 5.84k] ------------------ 181| 1.64M| ef->poll_set_head->prev = f; 182| | 183| | // then it will be our next 184| 1.64M| f->next = ef->poll_set_head; 185| 1.64M| } else { 186| | // if there was no head then we became the tail also 187| 5.84k| ef->poll_set_tail = f; 188| 5.84k| } 189| | 190| | // we are now the head in any case 191| 1.65M| ef->poll_set_head = f; 192| | 193| 1.65M| f->epev = *event; 194| | 195| 2.69M| } else if (op == EPOLL_CTL_MOD) { ------------------ | Branch (195:13): [True: 1.04M, False: 1.65M] ------------------ 196| | /* Modifying is simply changing the file itself */ 197| 1.04M| f->epev = *event; 198| 1.65M| } else if (op == EPOLL_CTL_DEL) { ------------------ | Branch (198:13): [True: 1.65M, False: 0] ------------------ 199| | 200| 1.65M| if (f->prev) { ------------------ | Branch (200:7): [True: 826k, False: 829k] ------------------ 201| 826k| f->prev->next = f->next; 202| 829k| } else { 203| 829k| ef->poll_set_head = f->next; 204| 829k| } 205| | 206| 1.65M| if (f->next) { ------------------ | Branch (206:7): [True: 1.64M, False: 5.84k] ------------------ 207| 1.64M| f->next->prev = f->prev; 208| 1.64M| } else { 209| | // tail ska vara vår.prev 210| 5.84k| ef->poll_set_tail = f->prev; 211| 5.84k| } 212| | 213| | // a file that is not in the list should be reset to NULL 214| 1.65M| f->prev = NULL; 215| 1.65M| f->next = NULL; 216| 1.65M| } 217| | 218| | /* You have to poll for errors and hangups */ 219| 4.35M| f->epev.events |= EPOLLERR | EPOLLHUP; 220| | 221| 4.35M| return 0; 222| 4.35M|} __wrap_epoll_wait: 226| 2.18M| int maxevents, int timeout) { 227| | //printf("epoll_wait: %d\n", 0); 228| | 229| |#ifdef PRINTF_DEBUG 230| | printf("Calling epoll_wait\n"); 231| |#endif 232| | 233| 2.18M| struct epoll_file *ef = (struct epoll_file *)map_fd(epfd); 234| 2.18M| if (!ef) { ------------------ | Branch (234:6): [True: 0, False: 2.18M] ------------------ 235| 0| return -1; 236| 0| } 237| | 238| 2.18M| if (consumable_data_length) { ------------------ | Branch (238:6): [True: 2.17M, False: 5.83k] ------------------ 239| | 240| 2.17M| int ready_events = 0; 241| | 242| 13.3M| for (struct file *f = ef->poll_set_head; f; f = f->next) { ------------------ | Branch (242:44): [True: 11.1M, False: 2.17M] ------------------ 243| | 244| | 245| | /* Consume one fuzz byte, AND it with the event */ 246| 11.1M| if (!consumable_data_length) { ------------------ | Branch (246:8): [True: 460, False: 11.1M] ------------------ 247| | // break if we have no data 248| 460| break; 249| 460| } 250| | 251| | // here we have the main condition that drives everything 252| 11.1M| int ready_event = consumable_data[0] & f->epev.events; 253| | 254| | // consume the byte 255| 11.1M| consumable_data_length--; 256| 11.1M| consumable_data++; 257| | 258| 11.1M| if (ready_event) { ------------------ | Branch (258:8): [True: 8.34M, False: 2.79M] ------------------ 259| 8.34M| if (ready_events < maxevents) { ------------------ | Branch (259:9): [True: 8.34M, False: 0] ------------------ 260| 8.34M| events[ready_events] = f->epev; 261| | 262| | // todo: the event should be masked by the byte, not everything it wants shold be given all the time! 263| 8.34M| events[ready_events++].events = ready_event; 264| 8.34M| } else { 265| | // we are full, break 266| 0| break; 267| 0| } 268| 8.34M| } 269| | 270| 11.1M| } 271| | 272| 2.17M| return ready_events; 273| | 274| 2.17M| } else { 275| | 276| |#ifdef PRINTF_DEBUG 277| | printf("Calling teardown\n"); 278| |#endif 279| 5.83k| teardown(); 280| | 281| | // after shutting down the listen socket we clear the whole list (the bug in epoll_ctl remove) 282| | // so the below loop doesn't work - we never close anything more than the listen socket! 283| | 284| | /* You don't really need to emit teardown, you could simply emit error on every poll */ 285| | 286| 5.83k| int ready_events = 0; 287| | 288| |#ifdef PRINTF_DEBUG 289| | printf("Emitting error on every remaining FD\n"); 290| |#endif 291| 78.7k| for (struct file *f = ef->poll_set_head; f; f = f->next) { ------------------ | Branch (291:44): [True: 72.8k, False: 5.83k] ------------------ 292| | 293| 72.8k| if (f->type == FD_TYPE_SOCKET) { ------------------ | Branch (293:8): [True: 55.3k, False: 17.4k] ------------------ 294| | 295| 55.3k| if (ready_events < maxevents) { ------------------ | Branch (295:9): [True: 55.3k, False: 0] ------------------ 296| 55.3k| events[ready_events] = f->epev; 297| | 298| | // todo: the event should be masked by the byte, not everything it wants shold be given all the time! 299| 55.3k| events[ready_events++].events = EPOLLERR | EPOLLHUP; 300| 55.3k| } else { 301| | // we are full, break 302| 0| break; 303| 0| } 304| | 305| 55.3k| } 306| 72.8k| } 307| | 308| |#ifdef PRINTF_DEBUG 309| | printf("Ready events: %d\n", ready_events); 310| |#endif 311| | 312| 5.83k| return ready_events; 313| 5.83k| } 314| 2.18M|} __wrap_read: 332| 5.70M|int __wrap_read(int fd, void *buf, size_t count) { 333| | 334| 5.70M| if (fd < RESERVED_SYSTEM_FDS) { ------------------ | Branch (334:6): [True: 0, False: 5.70M] ------------------ 335| 0| return __real_read(fd, buf, count); 336| 0| } 337| | 338| |#ifdef PRINTF_DEBUG 339| | printf("Wrapped read\n"); 340| |#endif 341| | 342| | /* Let's try and clear the buffer first */ 343| | //memset(buf, 0, count); 344| | 345| 5.70M| struct file *f = map_fd(fd); 346| 5.70M| if (!f) { ------------------ | Branch (346:6): [True: 0, False: 5.70M] ------------------ 347| 0| return -1; 348| 0| } 349| | 350| 5.70M| errno = 0; 351| | 352| 5.70M| if (f->type == FD_TYPE_SOCKET) { ------------------ | Branch (352:6): [True: 732k, False: 4.97M] ------------------ 353| | 354| 732k| if (!consumable_data_length) { ------------------ | Branch (354:7): [True: 8.02k, False: 724k] ------------------ 355| 8.02k| errno = EWOULDBLOCK; 356| 8.02k| return -1; 357| 724k| } else { 358| 724k| int data_available = (unsigned char) consumable_data[0]; 359| 724k| consumable_data_length--; 360| 724k| consumable_data++; 361| | 362| 724k| if (consumable_data_length < data_available) { ------------------ | Branch (362:8): [True: 4.73k, False: 719k] ------------------ 363| 4.73k| data_available = consumable_data_length; 364| 4.73k| } 365| | 366| 724k| if (count < data_available) { ------------------ | Branch (366:8): [True: 0, False: 724k] ------------------ 367| 0| data_available = count; 368| 0| } 369| | 370| 724k| memcpy(buf, consumable_data, data_available); 371| | 372| 724k| consumable_data_length -= data_available; 373| 724k| consumable_data += data_available; 374| | 375| 724k| return data_available; 376| 724k| } 377| 732k| } 378| | 379| 4.97M| if (f->type == FD_TYPE_EVENT) { ------------------ | Branch (379:6): [True: 1.63M, False: 3.34M] ------------------ 380| 1.63M| memset(buf, 1, 8); 381| 1.63M| return 8; 382| 1.63M| } 383| | 384| 3.34M| if (f->type == FD_TYPE_TIMER) { ------------------ | Branch (384:6): [True: 3.34M, False: 0] ------------------ 385| 3.34M| memset(buf, 1, 8); 386| 3.34M| return 8; 387| 3.34M| } 388| | 389| 0| return -1; 390| 3.34M|} __wrap_recv: 393| 732k|int __wrap_recv(int sockfd, void *buf, size_t len, int flags) { 394| 732k| return __wrap_read(sockfd, buf, len); 395| 732k|} __wrap_send: 397| 696k|int __wrap_send(int sockfd, const void *buf, size_t len, int flags) { 398| | 399| 696k| if (consumable_data_length) { ------------------ | Branch (399:6): [True: 677k, False: 19.7k] ------------------ 400| | /* We can send len scaled by the 1 byte */ 401| 677k| unsigned char scale = consumable_data[0]; 402| 677k| consumable_data++; 403| 677k| consumable_data_length--; 404| | 405| 677k| int written = float(scale) / 255.0f * len; 406| | 407| 677k| if (written == 0) { ------------------ | Branch (407:7): [True: 281k, False: 395k] ------------------ 408| 281k| errno = EWOULDBLOCK; 409| 395k| } else { 410| 395k| errno = 0; 411| 395k| } 412| | 413| 677k| return written; 414| 677k| } else { 415| 19.7k| return -1; 416| 19.7k| } 417| 696k|} __wrap_bind: 424| 5.84k|int __wrap_bind() { 425| 5.84k| return 0; 426| 5.84k|} __wrap_setsockopt: 428| 1.64M|int __wrap_setsockopt() { 429| 1.64M| return 0; 430| 1.64M|} __wrap_fcntl: 433| 3.27M|int __wrap_fcntl(int fd, int cmd, ... /* arg */) { 434| 3.27M| if (fd < RESERVED_SYSTEM_FDS) { ------------------ | Branch (434:6): [True: 2, False: 3.27M] ------------------ 435| 2| va_list args; 436| 2| va_start(args, cmd); 437| 2| int ret = __real_fcntl(fd, cmd, args); 438| 2| va_end(args); 439| 2| return ret; 440| 2| } 441| | 442| 3.27M| return 0; 443| 3.27M|} __wrap_getaddrinfo: 448| 5.84k| struct addrinfo **res) { 449| | //printf("Wrapped getaddrinfo\n"); 450| | 451| 5.84k| struct addrinfo default_hints = {}; 452| | 453| 5.84k| if (!hints) { ------------------ | Branch (453:6): [True: 0, False: 5.84k] ------------------ 454| 0| hints = &default_hints; 455| 0| } 456| | 457| 5.84k| unsigned char b; 458| 5.84k| if (consume_byte(&b)) { ------------------ | Branch (458:6): [True: 6, False: 5.84k] ------------------ 459| 6| return -1; 460| 6| } 461| | 462| | /* This one should be thread_local */ 463| 5.84k| static /*thread_local*/ struct addrinfo ai; 464| 5.84k| ai.ai_flags = hints->ai_flags; 465| 5.84k| ai.ai_socktype = hints->ai_socktype; 466| 5.84k| ai.ai_protocol = hints->ai_protocol; 467| | 468| 5.84k| if (b > 127) { ------------------ | Branch (468:6): [True: 3.08k, False: 2.75k] ------------------ 469| 3.08k| ai.ai_family = AF_INET;//hints->ai_family; 470| 3.08k| } else { 471| 2.75k| ai.ai_family = AF_INET6;//hints->ai_family; 472| 2.75k| } 473| | 474| | /* This one is for generating the wrong family (maybe invalid?) */ 475| 5.84k| if (b == 0) { ------------------ | Branch (475:6): [True: 1, False: 5.84k] ------------------ 476| 1| ai.ai_family = hints->ai_family; 477| 1| } 478| | 479| 5.84k| ai.ai_next = NULL; 480| 5.84k| ai.ai_canonname = NULL; // fel 481| | 482| | // these should depend on inet6 or inet */ 483| 5.84k| ai.ai_addrlen = 4; // fel 484| 5.84k| ai.ai_addr = NULL; // ska peka på en sockaddr! 485| | 486| | // we need to return an addrinfo with family AF_INET6 487| | 488| 5.84k| *res = &ai; 489| 5.84k| return 0; 490| 5.84k|} __wrap_freeaddrinfo: 492| 5.84k|int __wrap_freeaddrinfo() { 493| 5.84k| return 0; 494| 5.84k|} __wrap_accept4: 521| 3.19M|int __wrap_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { 522| | /* We must end with -1 since we are called in a loop */ 523| | 524| 3.19M| unsigned char b; 525| 3.19M| if (consume_byte(&b)) { ------------------ | Branch (525:6): [True: 4.33k, False: 3.19M] ------------------ 526| 4.33k| return -1; 527| 4.33k| } 528| | 529| | /* This rule might change, anything below 10 is accepted */ 530| 3.19M| if (b < 10) { ------------------ | Branch (530:6): [True: 1.63M, False: 1.55M] ------------------ 531| | 532| 1.63M| int fd = allocate_fd(); 533| 1.63M| if (fd != -1) { ------------------ | Branch (533:7): [True: 1.63M, False: 405] ------------------ 534| | 535| | /* Allocate the file */ 536| 1.63M| struct socket_file *sf = (struct socket_file *) malloc(sizeof(struct socket_file)); 537| | 538| | /* Init the file */ 539| | 540| | /* Here we need to create a socket FD and return */ 541| 1.63M| init_fd(fd, FD_TYPE_SOCKET, (struct file *)sf); 542| | 543| | /* We need to provide an addr */ 544| | 545| | /* Begin by setting it to an empty in6 address */ 546| 1.63M| memset(&sf->addr, 0, sizeof(struct sockaddr_in6)); 547| 1.63M| sf->len = sizeof(struct sockaddr_in6); 548| 1.63M| sf->addr.in6.sin6_family = AF_INET6; 549| | 550| | /* Opt-in to ipv4 */ 551| 1.63M| if (b < 5) { ------------------ | Branch (551:8): [True: 1.43M, False: 199k] ------------------ 552| 1.43M| memset(&sf->addr, 0, sizeof(struct sockaddr_in6)); 553| 1.43M| sf->len = sizeof(struct sockaddr_in); 554| 1.43M| sf->addr.in.sin_family = AF_INET; 555| 1.43M| } 556| | 557| 1.63M| if (addr) { ------------------ | Branch (557:8): [True: 1.63M, False: 0] ------------------ 558| | /* Copy from socket to addr */ 559| 1.63M| memcpy(addr, &sf->addr, sf->len); 560| 1.63M| } 561| 1.63M| } 562| | 563| 1.63M| return fd; 564| 1.63M| } 565| | 566| 1.55M| return -1; 567| 3.19M|} __wrap_listen: 569| 5.84k|int __wrap_listen() { 570| | /* Listen consumes one byte and fails on -1 */ 571| 5.84k| unsigned char b; 572| 5.84k| if (consume_byte(&b)) { ------------------ | Branch (572:6): [True: 9, False: 5.83k] ------------------ 573| 9| return -1; 574| 9| } 575| | 576| 5.83k| if (b) { ------------------ | Branch (576:6): [True: 5.83k, False: 1] ------------------ 577| 5.83k| return 0; 578| 5.83k| } 579| | 580| 1| return -1; 581| 5.83k|} __wrap_socket: 584| 5.84k|int __wrap_socket(int domain, int type, int protocol) { 585| | 586| | /* Only accept valid families */ 587| 5.84k| if (domain != AF_INET && domain != AF_INET6) { ------------------ | Branch (587:6): [True: 2.75k, False: 3.08k] | Branch (587:27): [True: 0, False: 2.75k] ------------------ 588| 0| return -1; 589| 0| } 590| | 591| 5.84k| int fd = allocate_fd(); 592| | 593| 5.84k| if (fd != -1) { ------------------ | Branch (593:6): [True: 5.84k, False: 0] ------------------ 594| 5.84k| struct socket_file *sf = (struct socket_file *)malloc(sizeof(struct socket_file)); 595| | 596| | /* Init the file */ 597| | 598| 5.84k| init_fd(fd, FD_TYPE_SOCKET, (struct file *)sf); 599| 5.84k| } 600| | 601| |#ifdef PRINTF_DEBUG 602| | printf("socket returning fd: %d\n", fd); 603| |#endif 604| | 605| 5.84k| return fd; 606| 5.84k|} __wrap_shutdown: 608| 401k|int __wrap_shutdown() { 609| | //printf("Wrapped shutdown\n"); 610| 401k| return 0; 611| 401k|} __wrap_timerfd_create: 619| 11.6k|int __wrap_timerfd_create(int clockid, int flags) { 620| | 621| 11.6k| int fd = allocate_fd(); 622| | 623| 11.6k| if (fd != -1) { ------------------ | Branch (623:6): [True: 11.6k, False: 0] ------------------ 624| 11.6k| struct timer_file *tf = (struct timer_file *)malloc(sizeof(struct timer_file)); 625| | 626| | /* Init the file */ 627| | 628| | 629| 11.6k| init_fd(fd, FD_TYPE_TIMER, (struct file *)tf); 630| | 631| 11.6k| } 632| | 633| |#ifdef PRINTF_DEBUG 634| | printf("timerfd_create returning fd: %d\n", fd); 635| |#endif 636| | 637| 11.6k| return fd; 638| 11.6k|} __wrap_timerfd_settime: 642| 11.6k| struct itimerspec *old_value) { 643| | //printf("timerfd_settime: %d\n", fd); 644| 11.6k| return 0; 645| 11.6k|} __wrap_eventfd: 653| 5.84k|int __wrap_eventfd() { 654| | 655| 5.84k| int fd = allocate_fd(); 656| | 657| 5.84k| if (fd != -1) { ------------------ | Branch (657:6): [True: 5.84k, False: 0] ------------------ 658| 5.84k| struct event_file *ef = (struct event_file *)malloc(sizeof(struct event_file)); 659| | 660| | /* Init the file */ 661| | 662| 5.84k| init_fd(fd, FD_TYPE_EVENT, (struct file *)ef); 663| | 664| | //printf("eventfd: %d\n", fd); 665| 5.84k| } 666| | 667| |#ifdef PRINTF_DEBUG 668| | printf("eventfd returning fd: %d\n", fd); 669| |#endif 670| | 671| 5.84k| return fd; 672| 5.84k|} __wrap_close: 678| 1.66M|int __wrap_close(int fd) { 679| | 680| 1.66M| if (fd < RESERVED_SYSTEM_FDS) { ------------------ | Branch (680:6): [True: 0, False: 1.66M] ------------------ 681| 0| return __real_close(fd); 682| 0| } 683| | 684| 1.66M| struct file *f = map_fd(fd); 685| | 686| 1.66M| if (!f) { ------------------ | Branch (686:6): [True: 0, False: 1.66M] ------------------ 687| 0| return -1; 688| 0| } 689| | 690| 1.66M| if (f->type == FD_TYPE_EPOLL) { ------------------ | Branch (690:6): [True: 5.84k, False: 1.65M] ------------------ 691| |#ifdef PRINTF_DEBUG 692| | printf("Closing epoll FD: %d\n", fd); 693| |#endif 694| | 695| 5.84k| free(f); 696| | 697| 5.84k| return free_fd(fd); 698| | 699| 1.65M| } else if (f->type == FD_TYPE_TIMER) { ------------------ | Branch (699:13): [True: 11.6k, False: 1.64M] ------------------ 700| |#ifdef PRINTF_DEBUG 701| | printf("Closing timer fd: %d\n", fd); 702| |#endif 703| | 704| 11.6k| free(f); 705| | 706| 11.6k| return free_fd(fd); 707| 1.64M| } else if (f->type == FD_TYPE_EVENT) { ------------------ | Branch (707:13): [True: 5.84k, False: 1.63M] ------------------ 708| |#ifdef PRINTF_DEBUG 709| | printf("Closing event fd: %d\n", fd); 710| |#endif 711| | 712| 5.84k| free(f); 713| | 714| 5.84k| return free_fd(fd); 715| 1.63M| } else if (f->type == FD_TYPE_SOCKET) { ------------------ | Branch (715:13): [True: 1.63M, False: 0] ------------------ 716| |#ifdef PRINTF_DEBUG 717| | printf("Closing socket fd: %d\n", fd); 718| |#endif 719| | 720| | // we should call epoll_ctl remove here 721| | 722| 1.63M| free(f); 723| | 724| 1.63M| int ret = free_fd(fd); 725| | 726| |#ifdef PRINTF_DEBUG 727| | printf("Ret: %d\n", ret); 728| |#endif 729| | 730| | //free(-1); 731| 1.63M| return ret; 732| 1.63M| } 733| | 734| 0| return -1; 735| 1.66M|} LLVMFuzzerTestOneInput: 737| 5.84k|int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 738| 5.84k| set_consumable_data(data, size); 739| | 740| 5.84k| test(); 741| | 742| 5.84k| if (num_fds) { ------------------ | Branch (742:6): [True: 0, False: 5.84k] ------------------ 743| 0| printf("ERROR! Cannot leave open FDs after test!\n"); 744| 0| } 745| | 746| 5.84k| return 0; 747| 5.84k|}