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

File Not Found


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

File Not Found


uWebSockets/20 Server"); 224| 19.5k| }); EpollEchoServerPubSub.cpp:_ZN3uWS12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOS1_NSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEEONS1_17WebSocketBehaviorIT_EE: 270| 5.39k| TemplatedApp &&ws(std::string pattern, WebSocketBehavior &&behavior) { 271| | /* Don't compile if alignment rules cannot be satisfied */ 272| 5.39k| static_assert(alignof(UserData) <= LIBUS_EXT_ALIGNMENT, 273| 5.39k| "µWebSockets cannot satisfy UserData alignment requirements. You need to recompile µSockets with LIBUS_EXT_ALIGNMENT adjusted accordingly."); 274| | 275| 5.39k| if (!httpContext) { ------------------ | Branch (275:13): [True: 0, False: 5.39k] ------------------ 276| 0| return std::move(*this); 277| 0| } 278| | 279| | /* Terminate on misleading idleTimeout values */ 280| 5.39k| if (behavior.idleTimeout && behavior.idleTimeout < 8) { ------------------ | Branch (280:13): [True: 5.39k, False: 0] | Branch (280:37): [True: 0, False: 5.39k] ------------------ 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| 5.39k| if (behavior.idleTimeout > 240 * 4) { ------------------ | Branch (286:13): [True: 0, False: 5.39k] ------------------ 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| 5.39k| if (behavior.maxLifetime > 240) { ------------------ | Branch (292:13): [True: 0, False: 5.39k] ------------------ 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| 5.39k| if (!topicTree) { ------------------ | Branch (298:13): [True: 5.39k, False: 0] ------------------ 299| | 300| 5.39k| bool needsUncork = false; 301| 5.39k| 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.39k| auto *ws = (WebSocket *) s->user; 307| | 308| | /* If this is the first message we try and cork */ 309| 5.39k| if (flags & TopicTree::IteratorFlags::FIRST) { 310| 5.39k| if (ws->canCork() && !ws->isCorked()) { 311| 5.39k| ((AsyncSocket *)ws)->cork(); 312| 5.39k| needsUncork = true; 313| 5.39k| } 314| 5.39k| } 315| | 316| | /* If we ever overstep maxBackpresure, exit immediately */ 317| 5.39k| if (WebSocket::SendStatus::DROPPED == ws->send(message.message, (OpCode)message.opCode, message.compress)) { 318| 5.39k| if (needsUncork) { 319| 5.39k| ((AsyncSocket *)ws)->uncork(); 320| 5.39k| needsUncork = false; 321| 5.39k| } 322| | /* Stop draining */ 323| 5.39k| return true; 324| 5.39k| } 325| | 326| | /* If this is the last message we uncork if we are corked */ 327| 5.39k| if (flags & TopicTree::IteratorFlags::LAST) { 328| | /* We should not uncork in all cases? */ 329| 5.39k| if (needsUncork) { 330| 5.39k| ((AsyncSocket *)ws)->uncork(); 331| 5.39k| } 332| 5.39k| } 333| | 334| | /* Success */ 335| 5.39k| return false; 336| 5.39k| }); 337| | 338| | /* And hook it up with the loop */ 339| | /* We empty for both pre and post just to make sure */ 340| 5.39k| Loop::get()->addPostHandler(topicTree, [topicTree = topicTree](Loop */*loop*/) { 341| | /* Commit pub/sub batches every loop iteration */ 342| 5.39k| topicTree->drain(); 343| 5.39k| }); 344| | 345| 5.39k| Loop::get()->addPreHandler(topicTree, [topicTree = topicTree](Loop */*loop*/) { 346| | /* Commit pub/sub batches every loop iteration */ 347| 5.39k| topicTree->drain(); 348| 5.39k| }); 349| 5.39k| } 350| | 351| | /* Every route has its own websocket context with its own behavior and user data type */ 352| 5.39k| auto *webSocketContext = WebSocketContext::create(Loop::get(), (us_socket_context_t *) httpContext, topicTree); 353| | 354| | /* We need to clear this later on */ 355| 5.39k| webSocketContextDeleters.push_back([webSocketContext]() { 356| 5.39k| webSocketContext->free(); 357| 5.39k| }); 358| | 359| | /* We also keep this list for easy closing */ 360| 5.39k| 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| 5.39k| if (behavior.compression) { ------------------ | Branch (368:13): [True: 0, False: 5.39k] ------------------ 369| 0| LoopData *loopData = (LoopData *) us_loop_ext(us_socket_context_loop(SSL, webSocketContext->getSocketContext())); 370| | 371| | /* Initialize loop's deflate inflate streams */ 372| 0| if (!loopData->zlibContext) { ------------------ | Branch (372:17): [True: 0, False: 0] ------------------ 373| 0| loopData->zlibContext = new ZlibContext; 374| 0| loopData->inflationStream = new InflationStream(CompressOptions::DEDICATED_DECOMPRESSOR); 375| 0| loopData->deflationStream = new DeflationStream(CompressOptions::DEDICATED_COMPRESSOR); 376| 0| } 377| 0| } 378| | 379| | /* Copy all handlers */ 380| 5.39k| webSocketContext->getExt()->openHandler = std::move(behavior.open); 381| 5.39k| webSocketContext->getExt()->messageHandler = std::move(behavior.message); 382| 5.39k| webSocketContext->getExt()->droppedHandler = std::move(behavior.dropped); 383| 5.39k| webSocketContext->getExt()->drainHandler = std::move(behavior.drain); 384| 5.39k| webSocketContext->getExt()->subscriptionHandler = std::move(behavior.subscription); 385| 5.39k| webSocketContext->getExt()->closeHandler = std::move([closeHandler = std::move(behavior.close)](WebSocket *ws, int code, std::string_view message) mutable { 386| 5.39k| if (closeHandler) { 387| 5.39k| closeHandler(ws, code, message); 388| 5.39k| } 389| | 390| | /* Destruct user data after returning from close handler */ 391| 5.39k| ((UserData *) ws->getUserData())->~UserData(); 392| 5.39k| }); 393| 5.39k| webSocketContext->getExt()->pingHandler = std::move(behavior.ping); 394| 5.39k| webSocketContext->getExt()->pongHandler = std::move(behavior.pong); 395| | 396| | /* Copy settings */ 397| 5.39k| webSocketContext->getExt()->maxPayloadLength = behavior.maxPayloadLength; 398| 5.39k| webSocketContext->getExt()->maxBackpressure = behavior.maxBackpressure; 399| 5.39k| webSocketContext->getExt()->closeOnBackpressureLimit = behavior.closeOnBackpressureLimit; 400| 5.39k| webSocketContext->getExt()->resetIdleTimeoutOnSend = behavior.resetIdleTimeoutOnSend; 401| 5.39k| webSocketContext->getExt()->sendPingsAutomatically = behavior.sendPingsAutomatically; 402| 5.39k| webSocketContext->getExt()->maxLifetime = behavior.maxLifetime; 403| 5.39k| webSocketContext->getExt()->compression = behavior.compression; 404| | 405| | /* Calculate idleTimeoutCompnents */ 406| 5.39k| webSocketContext->getExt()->calculateIdleTimeoutCompnents(behavior.idleTimeout); 407| | 408| 5.39k| 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| 5.39k| std::string_view secWebSocketKey = req->getHeader("sec-websocket-key"); 412| 5.39k| if (secWebSocketKey.length() == 24) { 413| | 414| | /* Emit upgrade handler */ 415| 5.39k| if (behavior.upgrade) { 416| | 417| | /* Nasty, ugly Safari 15 hack */ 418| 5.39k| if (hasBrokenCompression(req->getHeader("user-agent"))) { 419| 5.39k| std::string_view secWebSocketExtensions = req->getHeader("sec-websocket-extensions"); 420| 5.39k| memset((void *) secWebSocketExtensions.data(), ' ', secWebSocketExtensions.length()); 421| 5.39k| } 422| | 423| 5.39k| behavior.upgrade(res, req, (struct us_socket_context_t *) webSocketContext); 424| 5.39k| } else { 425| | /* Default handler upgrades to WebSocket */ 426| 5.39k| std::string_view secWebSocketProtocol = req->getHeader("sec-websocket-protocol"); 427| 5.39k| std::string_view secWebSocketExtensions = req->getHeader("sec-websocket-extensions"); 428| | 429| | /* Safari 15 hack */ 430| 5.39k| if (hasBrokenCompression(req->getHeader("user-agent"))) { 431| 5.39k| secWebSocketExtensions = ""; 432| 5.39k| } 433| | 434| 5.39k| res->template upgrade({}, secWebSocketKey, secWebSocketProtocol, secWebSocketExtensions, (struct us_socket_context_t *) webSocketContext); 435| 5.39k| } 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| 5.39k| } else { 442| | /* Tell the router that we did not handle this request */ 443| 5.39k| req->setYield(true); 444| 5.39k| } 445| 5.39k| }, true); 446| 5.39k| return std::move(*this); 447| 5.39k| } EpollEchoServerPubSub.cpp:_ZZN3uWS12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOS1_NSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEEONS1_17WebSocketBehaviorIT_EEENUlPNS_10SubscriberERNS_16TopicTreeMessageENS_9TopicTreeISI_NS_19TopicTreeBigMessageEE13IteratorFlagsEE_clESH_SJ_SN_: 301| 50.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| 50.2k| auto *ws = (WebSocket *) s->user; 307| | 308| | /* If this is the first message we try and cork */ 309| 50.2k| if (flags & TopicTree::IteratorFlags::FIRST) { ------------------ | Branch (309:21): [True: 9.71k, False: 40.5k] ------------------ 310| 9.71k| if (ws->canCork() && !ws->isCorked()) { ------------------ | Branch (310:25): [True: 6.80k, False: 2.91k] | Branch (310:42): [True: 6.80k, False: 0] ------------------ 311| 6.80k| ((AsyncSocket *)ws)->cork(); 312| 6.80k| needsUncork = true; 313| 6.80k| } 314| 9.71k| } 315| | 316| | /* If we ever overstep maxBackpresure, exit immediately */ 317| 50.2k| if (WebSocket::SendStatus::DROPPED == ws->send(message.message, (OpCode)message.opCode, message.compress)) { ------------------ | Branch (317:21): [True: 495, False: 49.7k] ------------------ 318| 495| if (needsUncork) { ------------------ | Branch (318:25): [True: 283, False: 212] ------------------ 319| 283| ((AsyncSocket *)ws)->uncork(); 320| 283| needsUncork = false; 321| 283| } 322| | /* Stop draining */ 323| 495| return true; 324| 495| } 325| | 326| | /* If this is the last message we uncork if we are corked */ 327| 49.7k| if (flags & TopicTree::IteratorFlags::LAST) { ------------------ | Branch (327:21): [True: 9.22k, False: 40.5k] ------------------ 328| | /* We should not uncork in all cases? */ 329| 9.22k| if (needsUncork) { ------------------ | Branch (329:25): [True: 8.75k, False: 470] ------------------ 330| 8.75k| ((AsyncSocket *)ws)->uncork(); 331| 8.75k| } 332| 9.22k| } 333| | 334| | /* Success */ 335| 49.7k| return false; 336| 50.2k| }); EpollEchoServerPubSub.cpp:_ZZN3uWS12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOS1_NSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEEONS1_17WebSocketBehaviorIT_EEENKUlPNS_4LoopEE_clESH_: 340| 1.29M| Loop::get()->addPostHandler(topicTree, [topicTree = topicTree](Loop */*loop*/) { 341| | /* Commit pub/sub batches every loop iteration */ 342| 1.29M| topicTree->drain(); 343| 1.29M| }); EpollEchoServerPubSub.cpp:_ZZN3uWS12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOS1_NSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEEONS1_17WebSocketBehaviorIT_EEENKUlPNS_4LoopEE0_clESH_: 345| 1.29M| Loop::get()->addPreHandler(topicTree, [topicTree = topicTree](Loop */*loop*/) { 346| | /* Commit pub/sub batches every loop iteration */ 347| 1.29M| topicTree->drain(); 348| 1.29M| }); EpollEchoServerPubSub.cpp:_ZZN3uWS12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOS1_NSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEEONS1_17WebSocketBehaviorIT_EEENKUlvE_clEv: 355| 5.39k| webSocketContextDeleters.push_back([webSocketContext]() { 356| 5.39k| webSocketContext->free(); 357| 5.39k| }); EpollEchoServerPubSub.cpp:_ZZN3uWS12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOS1_NSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEEONS1_17WebSocketBehaviorIT_EEENUlPNS_9WebSocketILb1ELb1ES3_EEiNS5_17basic_string_viewIcS8_EEE_clESI_iSK_: 385| 105k| webSocketContext->getExt()->closeHandler = std::move([closeHandler = std::move(behavior.close)](WebSocket *ws, int code, std::string_view message) mutable { 386| 105k| if (closeHandler) { ------------------ | Branch (386:17): [True: 105k, False: 0] ------------------ 387| 105k| closeHandler(ws, code, message); 388| 105k| } 389| | 390| | /* Destruct user data after returning from close handler */ 391| 105k| ((UserData *) ws->getUserData())->~UserData(); 392| 105k| }); EpollEchoServerPubSub.cpp:_ZZN3uWS12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOS1_NSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEEONS1_17WebSocketBehaviorIT_EEENUlPSD_PT0_E_clINS_12HttpResponseILb1EEENS_11HttpRequestEEEDaSG_SI_: 408| 109k| 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| 109k| std::string_view secWebSocketKey = req->getHeader("sec-websocket-key"); 412| 109k| if (secWebSocketKey.length() == 24) { ------------------ | Branch (412:17): [True: 105k, False: 4.40k] ------------------ 413| | 414| | /* Emit upgrade handler */ 415| 105k| if (behavior.upgrade) { ------------------ | Branch (415:21): [True: 0, False: 105k] ------------------ 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| 105k| } else { 425| | /* Default handler upgrades to WebSocket */ 426| 105k| std::string_view secWebSocketProtocol = req->getHeader("sec-websocket-protocol"); 427| 105k| std::string_view secWebSocketExtensions = req->getHeader("sec-websocket-extensions"); 428| | 429| | /* Safari 15 hack */ 430| 105k| if (hasBrokenCompression(req->getHeader("user-agent"))) { ------------------ | Branch (430:25): [True: 218, False: 105k] ------------------ 431| 218| secWebSocketExtensions = ""; 432| 218| } 433| | 434| 105k| res->template upgrade({}, secWebSocketKey, secWebSocketProtocol, secWebSocketExtensions, (struct us_socket_context_t *) webSocketContext); 435| 105k| } 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| 105k| } else { 442| | /* Tell the router that we did not handle this request */ 443| 4.40k| req->setYield(true); 444| 4.40k| } 445| 109k| }, true); _ZN3uWS20hasBrokenCompressionENSt3__117basic_string_viewIcNS0_11char_traitsIcEEEE: 29| 105k| inline bool hasBrokenCompression(std::string_view userAgent) { 30| 105k| size_t posStart = userAgent.find(" Version/15."); 31| 105k| if (posStart == std::string_view::npos) return false; ------------------ | Branch (31:13): [True: 95.0k, False: 10.3k] ------------------ 32| 10.3k| posStart += 12; 33| | 34| 10.3k| size_t posEnd = userAgent.find(' ', posStart); 35| 10.3k| if (posEnd == std::string_view::npos) return false; ------------------ | Branch (35:13): [True: 402, False: 9.97k] ------------------ 36| | 37| 9.97k| unsigned int minorVersion = 0; 38| 9.97k| auto result = std::from_chars(userAgent.data() + posStart, userAgent.data() + posEnd, minorVersion); 39| 9.97k| if (result.ec != std::errc()) return false; ------------------ | Branch (39:13): [True: 1.11k, False: 8.86k] ------------------ 40| 8.86k| if (result.ptr != userAgent.data() + posEnd) return false; // do not accept trailing chars ------------------ | Branch (40:13): [True: 5.13k, False: 3.72k] ------------------ 41| 3.72k| if (minorVersion > 3) return false; // we target just Safari 15.0 - 15.3 ------------------ | Branch (41:13): [True: 2.73k, False: 994] ------------------ 42| | 43| 994| if (userAgent.find(" Safari/", posEnd) == std::string_view::npos) return false; ------------------ | Branch (43:13): [True: 776, False: 218] ------------------ 44| | 45| 218| return true; 46| 994| } _ZN3uWS12TemplatedAppILb1EE7publishENSt3__117basic_string_viewIcNS2_11char_traitsIcEEEES6_NS_6OpCodeEb: 151| 1.07M| bool publish(std::string_view topic, std::string_view message, OpCode opCode, bool compress = false) { 152| | /* Anything big bypasses corking efforts */ 153| 1.07M| if (message.length() >= LoopData::CORK_BUFFER_SIZE) { ------------------ | Branch (153:13): [True: 0, False: 1.07M] ------------------ 154| 0| return topicTree->publishBig(nullptr, topic, {message, opCode, compress}, [](Subscriber *s, TopicTreeBigMessage &message) { 155| 0| auto *ws = (WebSocket *) s->user; 156| | 157| | /* Send will drain if needed */ 158| 0| ws->send(message.message, (OpCode)message.opCode, message.compress); 159| 0| }); 160| 1.07M| } else { 161| 1.07M| return topicTree->publish(nullptr, topic, {std::string(message), opCode, compress}); 162| 1.07M| } 163| 1.07M| } _ZN3uWS12TemplatedAppILb1EE6listenEiON5ofats13any_invocableIFvP18us_listen_socket_tEEE: 555| 5.39k| TemplatedApp &&listen(int port, MoveOnlyFunction &&handler) { 556| 5.39k| handler(httpContext ? httpContext->listen(nullptr, port, 0) : nullptr); ------------------ | Branch (556:17): [True: 5.39k, False: 0] ------------------ 557| 5.39k| return std::move(*this); 558| 5.39k| } _ZN3uWS12TemplatedAppILb1EE3runEv: 590| 5.39k| TemplatedApp &&run() { 591| 5.39k| uWS::run(); 592| 5.39k| return std::move(*this); 593| 5.39k| } _ZN3uWS12TemplatedAppILb1EED2Ev: 177| 5.39k| ~TemplatedApp() { 178| | /* Let's just put everything here */ 179| 5.39k| if (httpContext) { ------------------ | Branch (179:13): [True: 5.39k, False: 0] ------------------ 180| 5.39k| httpContext->free(); 181| | 182| | /* Free all our webSocketContexts in a type less way */ 183| 5.39k| for (auto &webSocketContextDeleter : webSocketContextDeleters) { ------------------ | Branch (183:48): [True: 5.39k, False: 5.39k] ------------------ 184| 5.39k| webSocketContextDeleter(); 185| 5.39k| } 186| 5.39k| } 187| | 188| | /* Delete TopicTree */ 189| 5.39k| if (topicTree) { ------------------ | Branch (189:13): [True: 5.39k, False: 0] ------------------ 190| 5.39k| delete topicTree; 191| | 192| | /* And unregister loop callbacks */ 193| | /* We must unregister any loop post handler here */ 194| 5.39k| Loop::get()->removePostHandler(topicTree); 195| 5.39k| Loop::get()->removePreHandler(topicTree); 196| 5.39k| } 197| 5.39k| } _ZN3uWS11AsyncSocketILb1EE4corkEv: 133| 764k| void cork() { 134| | /* Extra check for invalid corking of others */ 135| 764k| if (getLoopData()->corkOffset && getLoopData()->corkedSocket != this) { ------------------ | Branch (135:13): [True: 0, False: 764k] | 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| 764k| getLoopData()->corkedSocket = this; 142| 764k| } _ZN3uWS11AsyncSocketILb1EE11getLoopDataEv: 85| 6.00M| LoopData *getLoopData() { 86| 6.00M| return (LoopData *) us_loop_ext(us_socket_context_loop(SSL, us_socket_context(SSL, (us_socket_t *) this))); 87| 6.00M| } _ZN3uWS11AsyncSocketILb1EE6uncorkEPKcib: 327| 766k| std::pair uncork(const char *src = nullptr, int length = 0, bool optionally = false) { 328| 766k| LoopData *loopData = getLoopData(); 329| | 330| 766k| if (loopData->corkedSocket == this) { ------------------ | Branch (330:13): [True: 764k, False: 2.23k] ------------------ 331| 764k| loopData->corkedSocket = nullptr; 332| | 333| 764k| if (loopData->corkOffset) { ------------------ | Branch (333:17): [True: 127k, False: 637k] ------------------ 334| | /* Corked data is already accounted for via its write call */ 335| 127k| auto [written, failed] = write(loopData->corkBuffer, (int) loopData->corkOffset, false, length); 336| 127k| loopData->corkOffset = 0; 337| | 338| 127k| if (failed) { ------------------ | Branch (338:21): [True: 111k, False: 15.8k] ------------------ 339| | /* We do not need to care for buffering here, write does that */ 340| 111k| return {0, true}; 341| 111k| } 342| 127k| } 343| | 344| | /* We should only return with new writes, not things written to cork already */ 345| 653k| return write(src, length, optionally, 0); 346| 764k| } else { 347| | /* We are not even corked! */ 348| 2.23k| return {0, false}; 349| 2.23k| } 350| 766k| } _ZN3uWS11AsyncSocketILb1EE5writeEPKcibi: 236| 3.68M| 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| 3.68M| if (us_socket_is_closed(SSL, (us_socket_t *) this)) { ------------------ | Branch (238:13): [True: 590k, False: 3.09M] ------------------ 239| 590k| return {length, false}; 240| 590k| } 241| | 242| 3.09M| LoopData *loopData = getLoopData(); 243| 3.09M| AsyncSocketData *asyncSocketData = getAsyncSocketData(); 244| | 245| | /* We are limited if we have a per-socket buffer */ 246| 3.09M| if (asyncSocketData->buffer.length()) { ------------------ | Branch (246:13): [True: 116k, False: 2.97M] ------------------ 247| | /* Write off as much as we can */ 248| 116k| 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| 116k| if ((unsigned int) written < asyncSocketData->buffer.length()) { ------------------ | Branch (251:17): [True: 111k, False: 5.46k] ------------------ 252| | 253| | /* Update buffering (todo: we can do better here if we keep track of what happens to this guy later on) */ 254| 111k| asyncSocketData->buffer.erase((unsigned int) written); 255| | 256| 111k| if (optionally) { ------------------ | Branch (256:21): [True: 2.20k, False: 109k] ------------------ 257| | /* Thankfully we can exit early here */ 258| 2.20k| 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| 111k| } 266| | 267| | /* At this point we simply have no buffer and can continue as normal */ 268| 5.46k| asyncSocketData->buffer.clear(); 269| 5.46k| } 270| | 271| 2.97M| if (length) { ------------------ | Branch (271:13): [True: 2.93M, False: 42.7k] ------------------ 272| 2.93M| if (loopData->corkedSocket == this) { ------------------ | Branch (272:17): [True: 2.82M, False: 113k] ------------------ 273| | /* We are corked */ 274| 2.82M| if (LoopData::CORK_BUFFER_SIZE - loopData->corkOffset >= (unsigned int) length) { ------------------ | Branch (274:21): [True: 2.82M, False: 0] ------------------ 275| | /* If the entire chunk fits in cork buffer */ 276| 2.82M| memcpy(loopData->corkBuffer + loopData->corkOffset, src, (unsigned int) length); 277| 2.82M| loopData->corkOffset += (unsigned int) length; 278| | /* Fall through to default return */ 279| 2.82M| } 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| 2.82M| } else { 295| | /* We are not corked */ 296| 113k| int written = us_socket_write(SSL, (us_socket_t *) this, src, length, nextLength != 0); 297| | 298| | /* Did we fail? */ 299| 113k| if (written < length) { ------------------ | Branch (299:21): [True: 111k, False: 2.06k] ------------------ 300| | /* If the write was optional then just bail out */ 301| 111k| if (optionally) { ------------------ | Branch (301:25): [True: 0, False: 111k] ------------------ 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| 111k| if (nextLength) { ------------------ | Branch (307:25): [True: 0, False: 111k] ------------------ 308| 0| asyncSocketData->buffer.reserve(asyncSocketData->buffer.length() + (size_t) (length - written + nextLength)); 309| 0| } 310| | 311| | /* Buffer this chunk */ 312| 111k| asyncSocketData->buffer.append(src + written, (size_t) (length - written)); 313| | 314| | /* Return the failure */ 315| 111k| return {length, true}; 316| 111k| } 317| | /* Fall through to default return */ 318| 113k| } 319| 2.93M| } 320| | 321| | /* Default fall through return */ 322| 2.86M| return {length, false}; 323| 2.97M| } _ZN3uWS11AsyncSocketILb1EE7timeoutEj: 95| 260k| void timeout(unsigned int seconds) { 96| 260k| us_socket_timeout(SSL, (us_socket_t *) this, seconds); 97| 260k| } _ZN3uWS11AsyncSocketILb1EE17getBufferedAmountEv: 193| 213k| unsigned int getBufferedAmount() { 194| | /* We return the actual amount of bytes in backbuffer, including pendingRemoval */ 195| 213k| return (unsigned int) getAsyncSocketData()->buffer.totalLength(); 196| 213k| } _ZN3uWS11AsyncSocketILb1EE8shutdownEv: 100| 3.45k| void shutdown() { 101| 3.45k| us_socket_shutdown(SSL, (us_socket_t *) this); 102| 3.45k| } _ZN3uWS11AsyncSocketILb1EE5closeEv: 117| 64.2k| us_socket_t *close() { 118| 64.2k| return us_socket_close(SSL, (us_socket_t *) this, 0, nullptr); 119| 64.2k| } _ZN3uWS11AsyncSocketILb1EE18getAsyncSocketDataEv: 90| 4.63M| AsyncSocketData *getAsyncSocketData() { 91| 4.63M| return (AsyncSocketData *) us_socket_ext(SSL, (us_socket_t *) this); 92| 4.63M| } _ZN3uWS11AsyncSocketILb1EE8isCorkedEv: 145| 317k| bool isCorked() { 146| 317k| return getLoopData()->corkedSocket == this; 147| 317k| } _ZN3uWS11AsyncSocketILb1EE7canCorkEv: 150| 10.8k| bool canCork() { 151| 10.8k| return getLoopData()->corkedSocket == nullptr; 152| 10.8k| } _ZN3uWS11AsyncSocketILb1EE13getSendBufferEm: 155| 63.1k| std::pair getSendBuffer(size_t size) { 156| | /* First step is to determine if we already have backpressure or not */ 157| 63.1k| LoopData *loopData = getLoopData(); 158| 63.1k| BackPressure &backPressure = getAsyncSocketData()->buffer; 159| 63.1k| size_t existingBackpressure = backPressure.length(); 160| 63.1k| if ((!existingBackpressure) && (isCorked() || canCork()) && (loopData->corkOffset + size < LoopData::CORK_BUFFER_SIZE)) { ------------------ | Branch (160:13): [True: 8.70k, False: 54.4k] | Branch (160:41): [True: 7.60k, False: 1.09k] | Branch (160:55): [True: 1.09k, False: 0] | Branch (160:69): [True: 8.70k, False: 0] ------------------ 161| | /* Cork automatically if we can */ 162| 8.70k| if (isCorked()) { ------------------ | Branch (162:17): [True: 7.60k, False: 1.09k] ------------------ 163| 7.60k| char *sendBuffer = loopData->corkBuffer + loopData->corkOffset; 164| 7.60k| loopData->corkOffset += (unsigned int) size; 165| 7.60k| return {sendBuffer, SendBufferAttribute::NEEDS_NOTHING}; 166| 7.60k| } else { 167| 1.09k| cork(); 168| 1.09k| char *sendBuffer = loopData->corkBuffer + loopData->corkOffset; 169| 1.09k| loopData->corkOffset += (unsigned int) size; 170| 1.09k| return {sendBuffer, SendBufferAttribute::NEEDS_UNCORK}; 171| 1.09k| } 172| 54.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| 54.4k| unsigned int ourCorkOffset = 0; 177| 54.4k| if (isCorked() && loopData->corkOffset) { ------------------ | Branch (177:17): [True: 51.8k, False: 2.63k] | Branch (177:31): [True: 0, False: 51.8k] ------------------ 178| 0| ourCorkOffset = loopData->corkOffset; 179| 0| loopData->corkOffset = 0; 180| 0| } 181| | 182| | /* Fallback is to use the backpressure as buffer */ 183| 54.4k| backPressure.resize(ourCorkOffset + existingBackpressure + size); 184| | 185| | /* And copy corkbuffer in front */ 186| 54.4k| memcpy((char *) backPressure.data() + existingBackpressure, loopData->corkBuffer, ourCorkOffset); 187| | 188| 54.4k| return {(char *) backPressure.data() + ourCorkOffset + existingBackpressure, SendBufferAttribute::NEEDS_DRAIN}; 189| 54.4k| } 190| 63.1k| } _ZN3uWS11AsyncSocketILb1EE13corkUncheckedEv: 121| 105k| void corkUnchecked() { 122| | /* What if another socket is corked? */ 123| 105k| getLoopData()->corkedSocket = this; 124| 105k| } _ZN3uWS15AsyncSocketDataILb1EEC2Ev: 82| 1.22M| AsyncSocketData() = default; _ZN3uWS12BackPressureC2Ev: 32| 1.22M| BackPressure() = default; _ZN3uWS12BackPressure6lengthEv: 44| 3.38M| size_t length() { 45| 3.38M| return buffer.length() - pendingRemoval; 46| 3.38M| } _ZN3uWS12BackPressure4dataEv: 57| 225k| const char *data() { 58| 225k| return buffer.data() + pendingRemoval; 59| 225k| } _ZN3uWS12BackPressure5eraseEj: 36| 111k| void erase(unsigned int length) { 37| 111k| pendingRemoval += length; 38| | /* Always erase a minimum of 1/32th the current backpressure */ 39| 111k| if (pendingRemoval > (buffer.length() >> 5)) { ------------------ | Branch (39:13): [True: 83.2k, False: 28.0k] ------------------ 40| 83.2k| buffer.erase(0, pendingRemoval); 41| 83.2k| pendingRemoval = 0; 42| 83.2k| } 43| 111k| } _ZN3uWS12BackPressure6appendEPKcm: 33| 220k| void append(const char *data, size_t length) { 34| 220k| buffer.append(data, length); 35| 220k| } _ZN3uWS12BackPressure5clearEv: 47| 5.46k| void clear() { 48| 5.46k| pendingRemoval = 0; 49| 5.46k| buffer.clear(); 50| 5.46k| } _ZN3uWS12BackPressure11totalLengthEv: 64| 213k| size_t totalLength() { 65| 213k| return buffer.length(); 66| 213k| } _ZN3uWS12BackPressure6resizeEm: 54| 54.4k| void resize(size_t length) { 55| 54.4k| buffer.resize(length + pendingRemoval); 56| 54.4k| } _ZN3uWS12BackPressureC2EOS0_: 28| 210k| BackPressure(BackPressure &&other) { 29| 210k| buffer = std::move(other.buffer); 30| 210k| pendingRemoval = other.pendingRemoval; 31| 210k| } _ZN3uWS15AsyncSocketDataILb0EEC2EONS_12BackPressureE: 77| 105k| AsyncSocketData(BackPressure &&backpressure) : buffer(std::move(backpressure)) { 78| | 79| 105k| } _ZN3uWS11BloomFilter5resetEv: 75| 127k| void reset() { 76| 127k| filter.reset(); 77| 127k| } _ZN3uWS11BloomFilter3addENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE: 64| 269k| void add(std::string_view key) { 65| 269k| if (key.length() >= 2) { ------------------ | Branch (65:13): [True: 268k, False: 1.25k] ------------------ 66| 268k| ScrambleArea s = getFeatures(key); 67| 268k| s.val = perfectHash(s.val); 68| 268k| filter[s.p[0]] = 1; 69| 268k| filter[s.p[1]] = 1; 70| 268k| filter[s.p[2]] = 1; 71| 268k| filter[s.p[3]] = 1; 72| 268k| } 73| 269k| } _ZN3uWS11BloomFilter11getFeaturesENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE: 41| 1.32M| ScrambleArea getFeatures(std::string_view key) { 42| 1.32M| ScrambleArea s; 43| 1.32M| s.p[0] = reinterpret_cast(key[0]); 44| 1.32M| s.p[1] = reinterpret_cast(key[key.length() - 1]); 45| 1.32M| s.p[2] = reinterpret_cast(key[key.length() - 2]); 46| 1.32M| s.p[3] = reinterpret_cast(key[key.length() >> 1]); 47| 1.32M| return s; 48| 1.32M| } _ZN3uWS11BloomFilter11perfectHashEj: 32| 1.32M| static inline uint32_t perfectHash(uint32_t features) { 33| 1.32M| return features *= 1843993368; 34| 1.32M| } _ZN3uWS11BloomFilter9mightHaveENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE: 51| 1.05M| bool mightHave(std::string_view key) { 52| 1.05M| if (key.length() < 2) { ------------------ | Branch (52:13): [True: 0, False: 1.05M] ------------------ 53| 0| return true; 54| 0| } 55| | 56| 1.05M| ScrambleArea s = getFeatures(key); 57| 1.05M| s.val = perfectHash(s.val); 58| 1.05M| return filter[s.p[0]] && ------------------ | Branch (58:16): [True: 472k, False: 586k] ------------------ 59| 1.05M| filter[s.p[1]] && ------------------ | Branch (59:9): [True: 257k, False: 214k] ------------------ 60| 1.05M| filter[s.p[2]] && ------------------ | Branch (60:9): [True: 254k, False: 2.51k] ------------------ 61| 1.05M| filter[s.p[3]]; ------------------ | Branch (61:9): [True: 253k, False: 1.07k] ------------------ 62| 1.05M| } _ZN3uWS24isParsingChunkedEncodingEm: 95| 3.69k| inline bool isParsingChunkedEncoding(uint64_t state) { 96| 3.69k| return state & ~STATE_SIZE_MASK; 97| 3.69k| } _ZN3uWS13ChunkIteratorC2EPNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPmb: 201| 4.89k| ChunkIterator(std::string_view *data, uint64_t *state, bool trailer = false) : data(data), state(state), trailer(trailer) { 202| 4.89k| chunk = uWS::getNextChunk(*data, *state, trailer); 203| 4.89k| } EpollEchoServerPubSub.cpp:_ZN3uWSL12getNextChunkERNSt3__117basic_string_viewIcNS0_11char_traitsIcEEEERmb: 104| 7.57k| static std::optional getNextChunk(std::string_view &data, uint64_t &state, bool trailer = false) { 105| | 106| 11.1k| while (data.length()) { ------------------ | Branch (106:16): [True: 8.00k, False: 3.15k] ------------------ 107| | 108| | // if in "drop trailer mode", just drop up to what we have as size 109| 8.00k| if (((state & STATE_IS_CHUNKED) == 0) && hasChunkSize(state) && chunkSize(state)) { ------------------ | Branch (109:17): [True: 537, False: 7.46k] | Branch (109:54): [True: 537, False: 0] | Branch (109:77): [True: 537, False: 0] ------------------ 110| | 111| | //printf("Parsing trailer now\n"); 112| | 113| 1.07k| while(data.length() && chunkSize(state)) { ------------------ | Branch (113:23): [True: 867, False: 204] | Branch (113:40): [True: 867, False: 0] ------------------ 114| 867| data.remove_prefix(1); 115| 867| decChunkSize(state, 1); 116| | 117| 867| if (chunkSize(state) == 0) { ------------------ | Branch (117:25): [True: 333, False: 534] ------------------ 118| | 119| | /* This is an actual place where we need 0 as state */ 120| 333| state = 0; 121| | 122| | /* The parser MUST stop consuming here */ 123| 333| return std::nullopt; 124| 333| } 125| 867| } 126| 204| continue; 127| 537| } 128| | 129| 7.46k| if (!hasChunkSize(state)) { ------------------ | Branch (129:17): [True: 4.90k, False: 2.56k] ------------------ 130| 4.90k| consumeHexNumber(data, state); 131| 4.90k| if (isParsingInvalidChunkedEncoding(state)) { ------------------ | Branch (131:21): [True: 1.21k, False: 3.68k] ------------------ 132| 1.21k| return std::nullopt; 133| 1.21k| } 134| 3.68k| if (hasChunkSize(state) && chunkSize(state) == 2) { ------------------ | Branch (134:21): [True: 2.39k, False: 1.29k] | Branch (134:44): [True: 565, False: 1.83k] ------------------ 135| | 136| | //printf("Setting state to trailer-parsing and emitting empty chunk\n"); 137| | 138| | // set trailer state and increase size to 4 139| 565| if (trailer) { ------------------ | Branch (139:25): [True: 0, False: 565] ------------------ 140| 0| state = 4 /*| STATE_IS_CHUNKED*/ | STATE_HAS_SIZE; 141| 565| } else { 142| 565| state = 2 /*| STATE_IS_CHUNKED*/ | STATE_HAS_SIZE; 143| 565| } 144| | 145| 565| return std::string_view(nullptr, 0); 146| 565| } 147| 3.12k| continue; 148| 3.68k| } 149| | 150| | // do we have data to emit all? 151| 2.56k| if (data.length() >= chunkSize(state)) { ------------------ | Branch (151:17): [True: 1.32k, False: 1.23k] ------------------ 152| | // emit all but 2 bytes then reset state to 0 and goto beginning 153| | // not fin 154| 1.32k| std::string_view emitSoon; 155| 1.32k| bool shouldEmit = false; 156| 1.32k| if (chunkSize(state) > 2) { ------------------ | Branch (156:21): [True: 1.07k, False: 255] ------------------ 157| 1.07k| emitSoon = std::string_view(data.data(), chunkSize(state) - 2); 158| 1.07k| shouldEmit = true; 159| 1.07k| } 160| 1.32k| data.remove_prefix(chunkSize(state)); 161| 1.32k| state = STATE_IS_CHUNKED; 162| 1.32k| if (shouldEmit) { ------------------ | Branch (162:21): [True: 1.07k, False: 255] ------------------ 163| 1.07k| return emitSoon; 164| 1.07k| } 165| 255| continue; 166| 1.32k| } else { 167| | /* We will consume all our input data */ 168| 1.23k| std::string_view emitSoon; 169| 1.23k| if (chunkSize(state) > 2) { ------------------ | Branch (169:21): [True: 1.04k, False: 194] ------------------ 170| 1.04k| uint64_t maximalAppEmit = chunkSize(state) - 2; 171| 1.04k| if (data.length() > maximalAppEmit) { ------------------ | Branch (171:25): [True: 203, False: 840] ------------------ 172| 203| emitSoon = data.substr(0, maximalAppEmit); 173| 840| } else { 174| | //cb(data); 175| 840| emitSoon = data; 176| 840| } 177| 1.04k| } 178| 1.23k| decChunkSize(state, (unsigned int) data.length()); 179| 1.23k| state |= STATE_IS_CHUNKED; 180| | // new: decrease data by its size (bug) 181| 1.23k| data.remove_prefix(data.length()); // ny bug fix för getNextChunk 182| 1.23k| if (emitSoon.length()) { ------------------ | Branch (182:21): [True: 1.04k, False: 194] ------------------ 183| 1.04k| return emitSoon; 184| 1.04k| } else { 185| 194| return std::nullopt; 186| 194| } 187| 1.23k| } 188| 2.56k| } 189| | 190| 3.15k| return std::nullopt; 191| 7.57k| } _ZN3uWS12hasChunkSizeEm: 90| 11.6k| inline bool hasChunkSize(uint64_t state) { 91| 11.6k| return state & STATE_HAS_SIZE; 92| 11.6k| } _ZN3uWS9chunkSizeEm: 38| 26.5k| inline uint64_t chunkSize(uint64_t state) { 39| 26.5k| return state & STATE_SIZE_MASK; 40| 26.5k| } _ZN3uWS12decChunkSizeERmj: 81| 2.10k| inline void decChunkSize(uint64_t &state, unsigned int by) { 82| | 83| | //unsigned int bits = state & STATE_IS_CHUNKED; 84| | 85| 2.10k| state = (state & ~STATE_SIZE_MASK) | (chunkSize(state) - by); 86| | 87| | //state |= bits; 88| 2.10k| } _ZN3uWS16consumeHexNumberERNSt3__117basic_string_viewIcNS0_11char_traitsIcEEEERm: 43| 4.90k| inline void consumeHexNumber(std::string_view &data, uint64_t &state) { 44| | /* Consume everything higher than 32 */ 45| 15.9k| while (data.length() && data.data()[0] > 32) { ------------------ | Branch (45:16): [True: 15.5k, False: 400] | Branch (45:33): [True: 12.2k, False: 3.28k] ------------------ 46| | 47| 12.2k| unsigned char digit = (unsigned char)data.data()[0]; 48| 12.2k| if (digit >= 'a') { ------------------ | Branch (48:17): [True: 1.22k, False: 11.0k] ------------------ 49| 1.22k| digit = (unsigned char) (digit - ('a' - ':')); 50| 11.0k| } else if (digit >= 'A') { ------------------ | Branch (50:24): [True: 2.91k, False: 8.10k] ------------------ 51| 2.91k| digit = (unsigned char) (digit - ('A' - ':')); 52| 2.91k| } 53| | 54| 12.2k| unsigned int number = ((unsigned int) digit - (unsigned int) '0'); 55| | 56| 12.2k| if (number > 16 || (chunkSize(state) & STATE_SIZE_OVERFLOW)) { ------------------ | Branch (56:17): [True: 993, False: 11.2k] | Branch (56:32): [True: 223, False: 11.0k] ------------------ 57| 1.21k| state = STATE_IS_ERROR; 58| 1.21k| return; 59| 1.21k| } 60| | 61| | // extract state bits 62| 11.0k| uint64_t bits = /*state &*/ STATE_IS_CHUNKED; 63| | 64| 11.0k| state = (state & STATE_SIZE_MASK) * 16ull + number; 65| | 66| 11.0k| state |= bits; 67| 11.0k| data.remove_prefix(1); 68| 11.0k| } 69| | /* Consume everything not /n */ 70| 14.4k| while (data.length() && data.data()[0] != '\n') { ------------------ | Branch (70:16): [True: 13.1k, False: 1.29k] | Branch (70:33): [True: 10.7k, False: 2.39k] ------------------ 71| 10.7k| data.remove_prefix(1); 72| 10.7k| } 73| | /* Now we stand on \n so consume it and enable size */ 74| 3.68k| if (data.length()) { ------------------ | Branch (74:13): [True: 2.39k, False: 1.29k] ------------------ 75| 2.39k| state += 2; // include the two last /r/n 76| 2.39k| state |= STATE_HAS_SIZE | STATE_IS_CHUNKED; 77| 2.39k| data.remove_prefix(1); 78| 2.39k| } 79| 3.68k| } _ZN3uWS13ChunkIterator5beginEv: 209| 4.89k| ChunkIterator begin() { 210| 4.89k| return *this; 211| 4.89k| } _ZN3uWS13ChunkIterator3endEv: 213| 4.89k| ChunkIterator end() { 214| 4.89k| return ChunkIterator(); 215| 4.89k| } _ZN3uWS13ChunkIteratorC2Ev: 205| 4.89k| ChunkIterator() { 206| | 207| 4.89k| } _ZNK3uWS13ChunkIteratorneERKS0_: 224| 7.57k| bool operator!=(const ChunkIterator &other) const { 225| 7.57k| return other.chunk.has_value() != chunk.has_value(); 226| 7.57k| } _ZN3uWS13ChunkIteratordeEv: 217| 2.67k| std::string_view operator*() { 218| 2.67k| if (!chunk.has_value()) { ------------------ | Branch (218:17): [True: 0, False: 2.67k] ------------------ 219| 0| std::abort(); 220| 0| } 221| 2.67k| return chunk.value(); 222| 2.67k| } _ZN3uWS13ChunkIteratorppEv: 228| 2.67k| ChunkIterator &operator++() { 229| 2.67k| chunk = uWS::getNextChunk(*data, *state, trailer); 230| 2.67k| return *this; 231| 2.67k| } _ZN3uWS31isParsingInvalidChunkedEncodingEm: 99| 9.79k| inline bool isParsingInvalidChunkedEncoding(uint64_t state) { 100| 9.79k| return state == STATE_IS_ERROR; 101| 9.79k| } _ZN3uWS11HttpContextILb1EE6createEPNS_4LoopE27us_socket_context_options_t: 394| 5.39k| static HttpContext *create(Loop *loop, us_socket_context_options_t options = {}) { 395| 5.39k| HttpContext *httpContext; 396| | 397| 5.39k| httpContext = (HttpContext *) us_create_socket_context(SSL, (us_loop_t *) loop, sizeof(HttpContextData), options); 398| | 399| 5.39k| if (!httpContext) { ------------------ | Branch (399:13): [True: 0, False: 5.39k] ------------------ 400| 0| return nullptr; 401| 0| } 402| | 403| | /* Init socket context data */ 404| 5.39k| new ((HttpContextData *) us_socket_context_ext(SSL, (us_socket_context_t *) httpContext)) HttpContextData(); 405| 5.39k| return httpContext->init(); 406| 5.39k| } _ZN3uWS11HttpContextILb1EE4initEv: 70| 5.39k| HttpContext *init() { 71| | /* Handle socket connections */ 72| 5.39k| 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.39k| us_socket_timeout(SSL, s, HTTP_IDLE_TIMEOUT_S); 75| | 76| | /* Init socket ext */ 77| 5.39k| new (us_socket_ext(SSL, s)) HttpResponseData; 78| | 79| | /* Call filter */ 80| 5.39k| HttpContextData *httpContextData = getSocketContextDataS(s); 81| 5.39k| for (auto &f : httpContextData->filterHandlers) { 82| 5.39k| f((HttpResponse *) s, 1); 83| 5.39k| } 84| | 85| 5.39k| return s; 86| 5.39k| }); 87| | 88| | /* Handle socket disconnections */ 89| 5.39k| us_socket_context_on_close(SSL, getSocketContext(), [](us_socket_t *s, int /*code*/, void */*reason*/) { 90| | /* Get socket ext */ 91| 5.39k| HttpResponseData *httpResponseData = (HttpResponseData *) us_socket_ext(SSL, s); 92| | 93| | /* Call filter */ 94| 5.39k| HttpContextData *httpContextData = getSocketContextDataS(s); 95| 5.39k| for (auto &f : httpContextData->filterHandlers) { 96| 5.39k| f((HttpResponse *) s, -1); 97| 5.39k| } 98| | 99| | /* Signal broken HTTP request only if we have a pending request */ 100| 5.39k| if (httpResponseData->onAborted) { 101| 5.39k| httpResponseData->onAborted(); 102| 5.39k| } 103| | 104| | /* Destruct socket ext */ 105| 5.39k| httpResponseData->~HttpResponseData(); 106| | 107| 5.39k| return s; 108| 5.39k| }); 109| | 110| | /* Handle HTTP data streams */ 111| 5.39k| 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.39k| HttpContextData *httpContextData = getSocketContextDataS(s); 120| | 121| | /* Do not accept any data while in shutdown state */ 122| 5.39k| if (us_socket_is_shut_down(SSL, (us_socket_t *) s)) { 123| 5.39k| return s; 124| 5.39k| } 125| | 126| 5.39k| HttpResponseData *httpResponseData = (HttpResponseData *) us_socket_ext(SSL, s); 127| | 128| | /* Cork this socket */ 129| 5.39k| ((AsyncSocket *) s)->cork(); 130| | 131| | /* Mark that we are inside the parser now */ 132| 5.39k| 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.39k| 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.39k| 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.39k| us_socket_timeout(SSL, (us_socket_t *) s, 0); 147| | 148| | /* Reset httpResponse */ 149| 5.39k| HttpResponseData *httpResponseData = (HttpResponseData *) us_socket_ext(SSL, (us_socket_t *) s); 150| 5.39k| httpResponseData->offset = 0; 151| | 152| | /* Are we not ready for another request yet? Terminate the connection. */ 153| 5.39k| if (httpResponseData->state & HttpResponseData::HTTP_RESPONSE_PENDING) { 154| 5.39k| us_socket_close(SSL, (us_socket_t *) s, 0, nullptr); 155| 5.39k| return nullptr; 156| 5.39k| } 157| | 158| | /* Mark pending request and emit it */ 159| 5.39k| httpResponseData->state = HttpResponseData::HTTP_RESPONSE_PENDING; 160| | 161| | /* Mark this response as connectionClose if ancient or connection: close */ 162| 5.39k| if (httpRequest->isAncient() || httpRequest->getHeader("connection").length() == 5) { 163| 5.39k| httpResponseData->state |= HttpResponseData::HTTP_CONNECTION_CLOSE; 164| 5.39k| } 165| | 166| | /* Select the router based on SNI (only possible for SSL) */ 167| 5.39k| auto *selectedRouter = &httpContextData->router; 168| 5.39k| if constexpr (SSL) { 169| 5.39k| void *domainRouter = us_socket_server_name_userdata(SSL, (struct us_socket_t *) s); 170| 5.39k| if (domainRouter) { 171| 5.39k| selectedRouter = (decltype(selectedRouter)) domainRouter; 172| 5.39k| } 173| 5.39k| } 174| | 175| | /* Route the method and URL */ 176| 5.39k| selectedRouter->getUserData() = {(HttpResponse *) s, httpRequest}; 177| 5.39k| if (!selectedRouter->route(httpRequest->getCaseSensitiveMethod(), httpRequest->getUrl())) { 178| | /* We have to force close this socket as we have no handler for it */ 179| 5.39k| us_socket_close(SSL, (us_socket_t *) s, 0, nullptr); 180| 5.39k| return nullptr; 181| 5.39k| } 182| | 183| | /* First of all we need to check if this socket was deleted due to upgrade */ 184| 5.39k| if (httpContextData->upgradedWebSocket) { 185| | /* We differ between closed and upgraded below */ 186| 5.39k| return nullptr; 187| 5.39k| } 188| | 189| | /* Was the socket closed? */ 190| 5.39k| if (us_socket_is_closed(SSL, (struct us_socket_t *) s)) { 191| 5.39k| return nullptr; 192| 5.39k| } 193| | 194| | /* We absolutely have to terminate parsing if shutdown */ 195| 5.39k| if (us_socket_is_shut_down(SSL, (us_socket_t *) s)) { 196| 5.39k| return nullptr; 197| 5.39k| } 198| | 199| | /* Returning from a request handler without responding or attaching an onAborted handler is ill-use */ 200| 5.39k| if (!((HttpResponse *) s)->hasResponded() && !httpResponseData->onAborted) { 201| | /* Throw exception here? */ 202| 5.39k| std::cerr << "Error: Returning from a request handler without responding or attaching an abort handler is forbidden!" << std::endl; 203| 5.39k| std::terminate(); 204| 5.39k| } 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.39k| if (!((HttpResponse *) s)->hasResponded() && httpResponseData->inStream) { 208| 5.39k| us_socket_timeout(SSL, (us_socket_t *) s, HTTP_IDLE_TIMEOUT_S); 209| 5.39k| } 210| | 211| | /* Continue parsing */ 212| 5.39k| return s; 213| | 214| 5.39k| }, [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.39k| if (httpResponseData->inStream) { 217| | 218| | /* Todo: can this handle timeout for non-post as well? */ 219| 5.39k| if (fin) { 220| | /* If we just got the last chunk (or empty chunk), disable timeout */ 221| 5.39k| us_socket_timeout(SSL, (struct us_socket_t *) user, 0); 222| 5.39k| } 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.39k| httpResponseData->received_bytes_per_timeout += (unsigned int) data.length(); 226| 5.39k| if (httpResponseData->received_bytes_per_timeout >= HTTP_RECEIVE_THROUGHPUT_BYTES * HTTP_IDLE_TIMEOUT_S) { 227| 5.39k| us_socket_timeout(SSL, (struct us_socket_t *) user, HTTP_IDLE_TIMEOUT_S); 228| 5.39k| httpResponseData->received_bytes_per_timeout = 0; 229| 5.39k| } 230| 5.39k| } 231| | 232| | /* We might respond in the handler, so do not change timeout after this */ 233| 5.39k| httpResponseData->inStream(data, fin); 234| | 235| | /* Was the socket closed? */ 236| 5.39k| if (us_socket_is_closed(SSL, (struct us_socket_t *) user)) { 237| 5.39k| return nullptr; 238| 5.39k| } 239| | 240| | /* We absolutely have to terminate parsing if shutdown */ 241| 5.39k| if (us_socket_is_shut_down(SSL, (us_socket_t *) user)) { 242| 5.39k| return nullptr; 243| 5.39k| } 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.39k| if (fin) { 248| 5.39k| httpResponseData->inStream = nullptr; 249| 5.39k| } 250| 5.39k| } 251| 5.39k| return user; 252| 5.39k| }); 253| | 254| | /* Mark that we are no longer parsing Http */ 255| 5.39k| 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.39k| 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.39k| us_socket_write(SSL, s, httpErrorResponses[err].data(), (int) httpErrorResponses[err].length(), false); 261| 5.39k| us_socket_shutdown(SSL, s); 262| | /* Close any socket on HTTP errors */ 263| 5.39k| 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.39k| returnedSocket = nullptr; 266| 5.39k| } 267| | 268| | /* We need to uncork in all cases, except for nullptr (closed socket, or upgraded socket) */ 269| 5.39k| if (returnedSocket != nullptr) { 270| | /* Timeout on uncork failure */ 271| 5.39k| auto [written, failed] = ((AsyncSocket *) returnedSocket)->uncork(); 272| 5.39k| 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.39k| ((AsyncSocket *) s)->timeout(HTTP_IDLE_TIMEOUT_S); 276| 5.39k| } 277| | 278| | /* We need to check if we should close this socket here now */ 279| 5.39k| if (httpResponseData->state & HttpResponseData::HTTP_CONNECTION_CLOSE) { 280| 5.39k| if ((httpResponseData->state & HttpResponseData::HTTP_RESPONSE_PENDING) == 0) { 281| 5.39k| if (((AsyncSocket *) s)->getBufferedAmount() == 0) { 282| 5.39k| ((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.39k| ((AsyncSocket *) s)->close(); 286| 5.39k| } 287| 5.39k| } 288| 5.39k| } 289| | 290| 5.39k| return (us_socket_t *) returnedSocket; 291| 5.39k| } 292| | 293| | /* If we upgraded, check here (differ between nullptr close and nullptr upgrade) */ 294| 5.39k| if (httpContextData->upgradedWebSocket) { 295| | /* This path is only for upgraded websockets */ 296| 5.39k| 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.39k| auto [written, failed] = asyncSocket->uncork(); 300| | 301| | /* If we succeeded in uncorking, check if we have sent WebSocket FIN */ 302| 5.39k| if (!failed) { 303| 5.39k| WebSocketData *webSocketData = (WebSocketData *) asyncSocket->getAsyncSocketData(); 304| 5.39k| if (webSocketData->isShuttingDown) { 305| | /* In that case, also send TCP FIN (this is similar to what we have in ws drain handler) */ 306| 5.39k| asyncSocket->shutdown(); 307| 5.39k| } 308| 5.39k| } 309| | 310| | /* Reset upgradedWebSocket before we return */ 311| 5.39k| httpContextData->upgradedWebSocket = nullptr; 312| | 313| | /* Return the new upgraded websocket */ 314| 5.39k| return (us_socket_t *) asyncSocket; 315| 5.39k| } 316| | 317| | /* It is okay to uncork a closed socket and we need to */ 318| 5.39k| ((AsyncSocket *) s)->uncork(); 319| | 320| | /* We cannot return nullptr to the underlying stack in any case */ 321| 5.39k| return s; 322| 5.39k| }); 323| | 324| | /* Handle HTTP write out (note: SSL_read may trigger this spuriously, the app need to handle spurious calls) */ 325| 5.39k| us_socket_context_on_writable(SSL, getSocketContext(), [](us_socket_t *s) { 326| | 327| 5.39k| AsyncSocket *asyncSocket = (AsyncSocket *) s; 328| 5.39k| 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.39k| 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.39k| 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.39k| bool success = httpResponseData->callOnWritable(httpResponseData->offset); 338| | 339| | /* The developer indicated that their onWritable failed. */ 340| 5.39k| if (!success) { 341| | /* Skip testing if we can drain anything since that might perform an extra syscall */ 342| 5.39k| return s; 343| 5.39k| } 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.39k| return s; 348| 5.39k| } 349| | 350| | /* Drain any socket buffer, this might empty our backpressure and thus finish the request */ 351| 5.39k| /*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.39k| if (httpResponseData->state & HttpResponseData::HTTP_CONNECTION_CLOSE) { 355| 5.39k| if ((httpResponseData->state & HttpResponseData::HTTP_RESPONSE_PENDING) == 0) { 356| 5.39k| if (asyncSocket->getBufferedAmount() == 0) { 357| 5.39k| 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.39k| asyncSocket->close(); 361| 5.39k| } 362| 5.39k| } 363| 5.39k| } 364| | 365| | /* Expect another writable event, or another request within the timeout */ 366| 5.39k| asyncSocket->timeout(HTTP_IDLE_TIMEOUT_S); 367| | 368| 5.39k| return s; 369| 5.39k| }); 370| | 371| | /* Handle FIN, HTTP does not support half-closed sockets, so simply close */ 372| 5.39k| us_socket_context_on_end(SSL, getSocketContext(), [](us_socket_t *s) { 373| | 374| | /* We do not care for half closed sockets */ 375| 5.39k| AsyncSocket *asyncSocket = (AsyncSocket *) s; 376| 5.39k| return asyncSocket->close(); 377| | 378| 5.39k| }); 379| | 380| | /* Handle socket timeouts, simply close them so to not confuse client with FIN */ 381| 5.39k| 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.39k| AsyncSocket *asyncSocket = (AsyncSocket *) s; 385| 5.39k| return asyncSocket->close(); 386| | 387| 5.39k| }); 388| | 389| 5.39k| return this; 390| 5.39k| } _ZN3uWS11HttpContextILb1EE16getSocketContextEv: 53| 164k| us_socket_context_t *getSocketContext() { 54| 164k| return (us_socket_context_t *) this; 55| 164k| } _ZZN3uWS11HttpContextILb1EE4initEvENKUlP11us_socket_tiPciE_clES3_iS4_i: 72| 1.22M| 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.22M| us_socket_timeout(SSL, s, HTTP_IDLE_TIMEOUT_S); 75| | 76| | /* Init socket ext */ 77| 1.22M| new (us_socket_ext(SSL, s)) HttpResponseData; 78| | 79| | /* Call filter */ 80| 1.22M| HttpContextData *httpContextData = getSocketContextDataS(s); 81| 1.22M| for (auto &f : httpContextData->filterHandlers) { ------------------ | Branch (81:26): [True: 0, False: 1.22M] ------------------ 82| 0| f((HttpResponse *) s, 1); 83| 0| } 84| | 85| 1.22M| return s; 86| 1.22M| }); _ZN3uWS11HttpContextILb1EE21getSocketContextDataSEP11us_socket_t: 65| 2.99M| static HttpContextData *getSocketContextDataS(us_socket_t *s) { 66| 2.99M| return (HttpContextData *) us_socket_context_ext(SSL, getSocketContext(s)); 67| 2.99M| } _ZN3uWS11HttpContextILb1EE16getSocketContextEP11us_socket_t: 57| 2.99M| static us_socket_context_t *getSocketContext(us_socket_t *s) { 58| 2.99M| return (us_socket_context_t *) us_socket_context(SSL, s); 59| 2.99M| } _ZZN3uWS11HttpContextILb1EE4initEvENKUlP11us_socket_tiPvE_clES3_iS4_: 89| 1.11M| us_socket_context_on_close(SSL, getSocketContext(), [](us_socket_t *s, int /*code*/, void */*reason*/) { 90| | /* Get socket ext */ 91| 1.11M| HttpResponseData *httpResponseData = (HttpResponseData *) us_socket_ext(SSL, s); 92| | 93| | /* Call filter */ 94| 1.11M| HttpContextData *httpContextData = getSocketContextDataS(s); 95| 1.11M| for (auto &f : httpContextData->filterHandlers) { ------------------ | Branch (95:26): [True: 0, False: 1.11M] ------------------ 96| 0| f((HttpResponse *) s, -1); 97| 0| } 98| | 99| | /* Signal broken HTTP request only if we have a pending request */ 100| 1.11M| if (httpResponseData->onAborted) { ------------------ | Branch (100:17): [True: 0, False: 1.11M] ------------------ 101| 0| httpResponseData->onAborted(); 102| 0| } 103| | 104| | /* Destruct socket ext */ 105| 1.11M| httpResponseData->~HttpResponseData(); 106| | 107| 1.11M| return s; 108| 1.11M| }); _ZZN3uWS11HttpContextILb1EE4initEvENKUlP11us_socket_tPciE_clES3_S4_i: 111| 660k| 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| 660k| HttpContextData *httpContextData = getSocketContextDataS(s); 120| | 121| | /* Do not accept any data while in shutdown state */ 122| 660k| if (us_socket_is_shut_down(SSL, (us_socket_t *) s)) { ------------------ | Branch (122:17): [True: 0, False: 660k] ------------------ 123| 0| return s; 124| 0| } 125| | 126| 660k| HttpResponseData *httpResponseData = (HttpResponseData *) us_socket_ext(SSL, s); 127| | 128| | /* Cork this socket */ 129| 660k| ((AsyncSocket *) s)->cork(); 130| | 131| | /* Mark that we are inside the parser now */ 132| 660k| 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| 660k| 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| 660k| 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| 660k| us_socket_timeout(SSL, (us_socket_t *) s, 0); 147| | 148| | /* Reset httpResponse */ 149| 660k| HttpResponseData *httpResponseData = (HttpResponseData *) us_socket_ext(SSL, (us_socket_t *) s); 150| 660k| httpResponseData->offset = 0; 151| | 152| | /* Are we not ready for another request yet? Terminate the connection. */ 153| 660k| if (httpResponseData->state & HttpResponseData::HTTP_RESPONSE_PENDING) { 154| 660k| us_socket_close(SSL, (us_socket_t *) s, 0, nullptr); 155| 660k| return nullptr; 156| 660k| } 157| | 158| | /* Mark pending request and emit it */ 159| 660k| httpResponseData->state = HttpResponseData::HTTP_RESPONSE_PENDING; 160| | 161| | /* Mark this response as connectionClose if ancient or connection: close */ 162| 660k| if (httpRequest->isAncient() || httpRequest->getHeader("connection").length() == 5) { 163| 660k| httpResponseData->state |= HttpResponseData::HTTP_CONNECTION_CLOSE; 164| 660k| } 165| | 166| | /* Select the router based on SNI (only possible for SSL) */ 167| 660k| auto *selectedRouter = &httpContextData->router; 168| 660k| if constexpr (SSL) { 169| 660k| void *domainRouter = us_socket_server_name_userdata(SSL, (struct us_socket_t *) s); 170| 660k| if (domainRouter) { 171| 660k| selectedRouter = (decltype(selectedRouter)) domainRouter; 172| 660k| } 173| 660k| } 174| | 175| | /* Route the method and URL */ 176| 660k| selectedRouter->getUserData() = {(HttpResponse *) s, httpRequest}; 177| 660k| if (!selectedRouter->route(httpRequest->getCaseSensitiveMethod(), httpRequest->getUrl())) { 178| | /* We have to force close this socket as we have no handler for it */ 179| 660k| us_socket_close(SSL, (us_socket_t *) s, 0, nullptr); 180| 660k| return nullptr; 181| 660k| } 182| | 183| | /* First of all we need to check if this socket was deleted due to upgrade */ 184| 660k| if (httpContextData->upgradedWebSocket) { 185| | /* We differ between closed and upgraded below */ 186| 660k| return nullptr; 187| 660k| } 188| | 189| | /* Was the socket closed? */ 190| 660k| if (us_socket_is_closed(SSL, (struct us_socket_t *) s)) { 191| 660k| return nullptr; 192| 660k| } 193| | 194| | /* We absolutely have to terminate parsing if shutdown */ 195| 660k| if (us_socket_is_shut_down(SSL, (us_socket_t *) s)) { 196| 660k| return nullptr; 197| 660k| } 198| | 199| | /* Returning from a request handler without responding or attaching an onAborted handler is ill-use */ 200| 660k| if (!((HttpResponse *) s)->hasResponded() && !httpResponseData->onAborted) { 201| | /* Throw exception here? */ 202| 660k| std::cerr << "Error: Returning from a request handler without responding or attaching an abort handler is forbidden!" << std::endl; 203| 660k| std::terminate(); 204| 660k| } 205| | 206| | /* If we have not responded and we have a data handler, we need to timeout to enfore client sending the data */ 207| 660k| if (!((HttpResponse *) s)->hasResponded() && httpResponseData->inStream) { 208| 660k| us_socket_timeout(SSL, (us_socket_t *) s, HTTP_IDLE_TIMEOUT_S); 209| 660k| } 210| | 211| | /* Continue parsing */ 212| 660k| return s; 213| | 214| 660k| }, [httpResponseData](void *user, std::string_view data, bool fin) -> void * { 215| | /* We always get an empty chunk even if there is no data */ 216| 660k| if (httpResponseData->inStream) { 217| | 218| | /* Todo: can this handle timeout for non-post as well? */ 219| 660k| if (fin) { 220| | /* If we just got the last chunk (or empty chunk), disable timeout */ 221| 660k| us_socket_timeout(SSL, (struct us_socket_t *) user, 0); 222| 660k| } 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| 660k| httpResponseData->received_bytes_per_timeout += (unsigned int) data.length(); 226| 660k| if (httpResponseData->received_bytes_per_timeout >= HTTP_RECEIVE_THROUGHPUT_BYTES * HTTP_IDLE_TIMEOUT_S) { 227| 660k| us_socket_timeout(SSL, (struct us_socket_t *) user, HTTP_IDLE_TIMEOUT_S); 228| 660k| httpResponseData->received_bytes_per_timeout = 0; 229| 660k| } 230| 660k| } 231| | 232| | /* We might respond in the handler, so do not change timeout after this */ 233| 660k| httpResponseData->inStream(data, fin); 234| | 235| | /* Was the socket closed? */ 236| 660k| if (us_socket_is_closed(SSL, (struct us_socket_t *) user)) { 237| 660k| return nullptr; 238| 660k| } 239| | 240| | /* We absolutely have to terminate parsing if shutdown */ 241| 660k| if (us_socket_is_shut_down(SSL, (us_socket_t *) user)) { 242| 660k| return nullptr; 243| 660k| } 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| 660k| if (fin) { 248| 660k| httpResponseData->inStream = nullptr; 249| 660k| } 250| 660k| } 251| 660k| return user; 252| 660k| }); 253| | 254| | /* Mark that we are no longer parsing Http */ 255| 660k| 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| 660k| if (returnedSocket == FULLPTR) { ------------------ | Branch (258:17): [True: 518k, False: 142k] ------------------ 259| | /* For errors, we only deliver them "at most once". We don't care if they get halfways delivered or not. */ 260| 518k| us_socket_write(SSL, s, httpErrorResponses[err].data(), (int) httpErrorResponses[err].length(), false); 261| 518k| us_socket_shutdown(SSL, s); 262| | /* Close any socket on HTTP errors */ 263| 518k| 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| 518k| returnedSocket = nullptr; 266| 518k| } 267| | 268| | /* We need to uncork in all cases, except for nullptr (closed socket, or upgraded socket) */ 269| 660k| if (returnedSocket != nullptr) { ------------------ | Branch (269:17): [True: 36.7k, False: 624k] ------------------ 270| | /* Timeout on uncork failure */ 271| 36.7k| auto [written, failed] = ((AsyncSocket *) returnedSocket)->uncork(); 272| 36.7k| if (failed) { ------------------ | Branch (272:21): [True: 6.93k, False: 29.8k] ------------------ 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| 6.93k| ((AsyncSocket *) s)->timeout(HTTP_IDLE_TIMEOUT_S); 276| 6.93k| } 277| | 278| | /* We need to check if we should close this socket here now */ 279| 36.7k| if (httpResponseData->state & HttpResponseData::HTTP_CONNECTION_CLOSE) { ------------------ | Branch (279:21): [True: 1.03k, False: 35.7k] ------------------ 280| 1.03k| if ((httpResponseData->state & HttpResponseData::HTTP_RESPONSE_PENDING) == 0) { ------------------ | Branch (280:25): [True: 1.03k, False: 0] ------------------ 281| 1.03k| if (((AsyncSocket *) s)->getBufferedAmount() == 0) { ------------------ | Branch (281:29): [True: 299, False: 737] ------------------ 282| 299| ((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| 299| ((AsyncSocket *) s)->close(); 286| 299| } 287| 1.03k| } 288| 1.03k| } 289| | 290| 36.7k| return (us_socket_t *) returnedSocket; 291| 36.7k| } 292| | 293| | /* If we upgraded, check here (differ between nullptr close and nullptr upgrade) */ 294| 624k| if (httpContextData->upgradedWebSocket) { ------------------ | Branch (294:17): [True: 105k, False: 518k] ------------------ 295| | /* This path is only for upgraded websockets */ 296| 105k| 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| 105k| auto [written, failed] = asyncSocket->uncork(); 300| | 301| | /* If we succeeded in uncorking, check if we have sent WebSocket FIN */ 302| 105k| if (!failed) { ------------------ | Branch (302:21): [True: 587, False: 104k] ------------------ 303| 587| WebSocketData *webSocketData = (WebSocketData *) asyncSocket->getAsyncSocketData(); 304| 587| if (webSocketData->isShuttingDown) { ------------------ | Branch (304:25): [True: 0, False: 587] ------------------ 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| 587| } 309| | 310| | /* Reset upgradedWebSocket before we return */ 311| 105k| httpContextData->upgradedWebSocket = nullptr; 312| | 313| | /* Return the new upgraded websocket */ 314| 105k| return (us_socket_t *) asyncSocket; 315| 105k| } 316| | 317| | /* It is okay to uncork a closed socket and we need to */ 318| 518k| ((AsyncSocket *) s)->uncork(); 319| | 320| | /* We cannot return nullptr to the underlying stack in any case */ 321| 518k| return s; 322| 624k| }); _ZZZN3uWS11HttpContextILb1EE4initEvENKUlP11us_socket_tPciE_clES3_S4_iENKUlPvPNS_11HttpRequestEE_clES6_S8_: 143| 124k| 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| 124k| us_socket_timeout(SSL, (us_socket_t *) s, 0); 147| | 148| | /* Reset httpResponse */ 149| 124k| HttpResponseData *httpResponseData = (HttpResponseData *) us_socket_ext(SSL, (us_socket_t *) s); 150| 124k| httpResponseData->offset = 0; 151| | 152| | /* Are we not ready for another request yet? Terminate the connection. */ 153| 124k| if (httpResponseData->state & HttpResponseData::HTTP_RESPONSE_PENDING) { ------------------ | Branch (153:21): [True: 0, False: 124k] ------------------ 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| 124k| httpResponseData->state = HttpResponseData::HTTP_RESPONSE_PENDING; 160| | 161| | /* Mark this response as connectionClose if ancient or connection: close */ 162| 124k| if (httpRequest->isAncient() || httpRequest->getHeader("connection").length() == 5) { ------------------ | Branch (162:21): [True: 0, False: 124k] | Branch (162:21): [True: 861, False: 124k] | Branch (162:49): [True: 861, False: 124k] ------------------ 163| 861| httpResponseData->state |= HttpResponseData::HTTP_CONNECTION_CLOSE; 164| 861| } 165| | 166| | /* Select the router based on SNI (only possible for SSL) */ 167| 124k| auto *selectedRouter = &httpContextData->router; 168| 124k| if constexpr (SSL) { ------------------ | Branch (168:31): [Folded - Ignored] ------------------ 169| 124k| void *domainRouter = us_socket_server_name_userdata(SSL, (struct us_socket_t *) s); 170| 124k| if (domainRouter) { ------------------ | Branch (170:25): [True: 0, False: 124k] ------------------ 171| 0| selectedRouter = (decltype(selectedRouter)) domainRouter; 172| 0| } 173| 124k| } 174| | 175| | /* Route the method and URL */ 176| 124k| selectedRouter->getUserData() = {(HttpResponse *) s, httpRequest}; 177| 124k| if (!selectedRouter->route(httpRequest->getCaseSensitiveMethod(), httpRequest->getUrl())) { ------------------ | Branch (177:21): [True: 0, False: 124k] ------------------ 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| 124k| if (httpContextData->upgradedWebSocket) { ------------------ | Branch (184:21): [True: 105k, False: 19.5k] ------------------ 185| | /* We differ between closed and upgraded below */ 186| 105k| return nullptr; 187| 105k| } 188| | 189| | /* Was the socket closed? */ 190| 19.5k| if (us_socket_is_closed(SSL, (struct us_socket_t *) s)) { ------------------ | Branch (190:21): [True: 0, False: 19.5k] ------------------ 191| 0| return nullptr; 192| 0| } 193| | 194| | /* We absolutely have to terminate parsing if shutdown */ 195| 19.5k| if (us_socket_is_shut_down(SSL, (us_socket_t *) s)) { ------------------ | Branch (195:21): [True: 0, False: 19.5k] ------------------ 196| 0| return nullptr; 197| 0| } 198| | 199| | /* Returning from a request handler without responding or attaching an onAborted handler is ill-use */ 200| 19.5k| if (!((HttpResponse *) s)->hasResponded() && !httpResponseData->onAborted) { ------------------ | Branch (200:21): [True: 0, False: 19.5k] | 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| 19.5k| if (!((HttpResponse *) s)->hasResponded() && httpResponseData->inStream) { ------------------ | Branch (207:21): [True: 0, False: 19.5k] | 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| 19.5k| return s; 213| | 214| 19.5k| }, [httpResponseData](void *user, std::string_view data, bool fin) -> void * { _ZZZN3uWS11HttpContextILb1EE4initEvENKUlP11us_socket_tPciE_clES3_S4_iENKUlPvNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEbE_clES6_SB_b: 214| 18.8k| }, [httpResponseData](void *user, std::string_view data, bool fin) -> void * { 215| | /* We always get an empty chunk even if there is no data */ 216| 18.8k| if (httpResponseData->inStream) { ------------------ | Branch (216:21): [True: 0, False: 18.8k] ------------------ 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| 18.8k| return user; 252| 18.8k| }); _ZZN3uWS11HttpContextILb1EE4initEvENKUlP11us_socket_tE_clES3_: 325| 2.40k| us_socket_context_on_writable(SSL, getSocketContext(), [](us_socket_t *s) { 326| | 327| 2.40k| AsyncSocket *asyncSocket = (AsyncSocket *) s; 328| 2.40k| 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| 2.40k| if (httpResponseData->onWritable) { ------------------ | Branch (331:17): [True: 0, False: 2.40k] ------------------ 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| 2.40k| /*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| 2.40k| if (httpResponseData->state & HttpResponseData::HTTP_CONNECTION_CLOSE) { ------------------ | Branch (354:17): [True: 746, False: 1.65k] ------------------ 355| 746| if ((httpResponseData->state & HttpResponseData::HTTP_RESPONSE_PENDING) == 0) { ------------------ | Branch (355:21): [True: 746, False: 0] ------------------ 356| 746| if (asyncSocket->getBufferedAmount() == 0) { ------------------ | Branch (356:25): [True: 194, False: 552] ------------------ 357| 194| 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| 194| asyncSocket->close(); 361| 194| } 362| 746| } 363| 746| } 364| | 365| | /* Expect another writable event, or another request within the timeout */ 366| 2.40k| asyncSocket->timeout(HTTP_IDLE_TIMEOUT_S); 367| | 368| 2.40k| return s; 369| 2.40k| }); _ZZN3uWS11HttpContextILb1EE4initEvENKUlP11us_socket_tE0_clES3_: 372| 59.6k| us_socket_context_on_end(SSL, getSocketContext(), [](us_socket_t *s) { 373| | 374| | /* We do not care for half closed sockets */ 375| 59.6k| AsyncSocket *asyncSocket = (AsyncSocket *) s; 376| 59.6k| return asyncSocket->close(); 377| | 378| 59.6k| }); _ZZN3uWS11HttpContextILb1EE4initEvENKUlP11us_socket_tE1_clES3_: 381| 4.10k| 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| 4.10k| AsyncSocket *asyncSocket = (AsyncSocket *) s; 385| 4.10k| return asyncSocket->close(); 386| | 387| 4.10k| }); _ZN3uWS11HttpContextILb1EE6onHttpENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEES8_ON5ofats13any_invocableIFvPNS_12HttpResponseILb1EEEPNS_11HttpRequestEEEEb: 423| 10.7k| void onHttp(std::string method, std::string pattern, MoveOnlyFunction *, HttpRequest *)> &&handler, bool upgrade = false) { 424| 10.7k| HttpContextData *httpContextData = getSocketContextData(); 425| | 426| | /* Todo: This is ugly, fix */ 427| 10.7k| std::vector methods; 428| 10.7k| if (method == "*") { ------------------ | Branch (428:13): [True: 5.39k, False: 5.39k] ------------------ 429| 5.39k| methods = {"*"}; 430| 5.39k| } else { 431| 5.39k| methods = {method}; 432| 5.39k| } 433| | 434| 10.7k| uint32_t priority = method == "*" ? httpContextData->currentRouter->LOW_PRIORITY : (upgrade ? httpContextData->currentRouter->HIGH_PRIORITY : httpContextData->currentRouter->MEDIUM_PRIORITY); ------------------ | Branch (434:29): [True: 5.39k, False: 5.39k] | Branch (434:93): [True: 5.39k, False: 0] ------------------ 435| | 436| | /* If we are passed nullptr then remove this */ 437| 10.7k| if (!handler) { ------------------ | Branch (437:13): [True: 0, False: 10.7k] ------------------ 438| 0| httpContextData->currentRouter->remove(methods[0], pattern, priority); 439| 0| return; 440| 0| } 441| | 442| | /* Record this route's parameter offsets */ 443| 10.7k| std::map> parameterOffsets; 444| 10.7k| unsigned short offset = 0; 445| 32.3k| for (unsigned int i = 0; i < pattern.length(); i++) { ------------------ | Branch (445:34): [True: 21.5k, False: 10.7k] ------------------ 446| 21.5k| if (pattern[i] == ':') { ------------------ | Branch (446:17): [True: 0, False: 21.5k] ------------------ 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| 21.5k| } 457| | 458| 10.7k| httpContextData->currentRouter->add(methods, pattern, [handler = std::move(handler), parameterOffsets = std::move(parameterOffsets)](auto *r) mutable { 459| 10.7k| auto user = r->getUserData(); 460| 10.7k| user.httpRequest->setYield(false); 461| 10.7k| user.httpRequest->setParameters(r->getParameters()); 462| 10.7k| user.httpRequest->setParameterOffsets(¶meterOffsets); 463| | 464| | /* Middleware? Automatically respond to expectations */ 465| 10.7k| std::string_view expect = user.httpRequest->getHeader("expect"); 466| 10.7k| if (expect.length() && expect == "100-continue") { 467| 10.7k| user.httpResponse->writeContinue(); 468| 10.7k| } 469| | 470| 10.7k| handler(user.httpResponse, user.httpRequest); 471| | 472| | /* If any handler yielded, the router will keep looking for a suitable handler. */ 473| 10.7k| if (user.httpRequest->getYield()) { 474| 10.7k| return false; 475| 10.7k| } 476| 10.7k| return true; 477| 10.7k| }, priority); 478| 10.7k| } _ZN3uWS11HttpContextILb1EE20getSocketContextDataEv: 61| 121k| HttpContextData *getSocketContextData() { 62| 121k| return (HttpContextData *) us_socket_context_ext(SSL, getSocketContext()); 63| 121k| } _ZZN3uWS11HttpContextILb1EE6onHttpENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEES8_ON5ofats13any_invocableIFvPNS_12HttpResponseILb1EEEPNS_11HttpRequestEEEEbENUlPT_E_clINS_10HttpRouterINS_15HttpContextDataILb1EE10RouterDataEEEEEDaSK_: 458| 129k| httpContextData->currentRouter->add(methods, pattern, [handler = std::move(handler), parameterOffsets = std::move(parameterOffsets)](auto *r) mutable { 459| 129k| auto user = r->getUserData(); 460| 129k| user.httpRequest->setYield(false); 461| 129k| user.httpRequest->setParameters(r->getParameters()); 462| 129k| user.httpRequest->setParameterOffsets(¶meterOffsets); 463| | 464| | /* Middleware? Automatically respond to expectations */ 465| 129k| std::string_view expect = user.httpRequest->getHeader("expect"); 466| 129k| if (expect.length() && expect == "100-continue") { ------------------ | Branch (466:17): [True: 648, False: 128k] | Branch (466:36): [True: 194, False: 454] ------------------ 467| 194| user.httpResponse->writeContinue(); 468| 194| } 469| | 470| 129k| handler(user.httpResponse, user.httpRequest); 471| | 472| | /* If any handler yielded, the router will keep looking for a suitable handler. */ 473| 129k| if (user.httpRequest->getYield()) { ------------------ | Branch (473:17): [True: 4.40k, False: 124k] ------------------ 474| 4.40k| return false; 475| 4.40k| } 476| 124k| return true; 477| 129k| }, priority); _ZN3uWS11HttpContextILb1EE6listenEPKcii: 481| 5.39k| us_listen_socket_t *listen(const char *host, int port, int options) { 482| 5.39k| return us_socket_context_listen(SSL, getSocketContext(), host, port, options, sizeof(HttpResponseData)); 483| 5.39k| } _ZN3uWS11HttpContextILb1EE4freeEv: 409| 5.39k| void free() { 410| | /* Destruct socket context data */ 411| 5.39k| HttpContextData *httpContextData = getSocketContextData(); 412| 5.39k| httpContextData->~HttpContextData(); 413| | 414| | /* Free the socket context in whole */ 415| 5.39k| us_socket_context_free(SSL, getSocketContext()); 416| 5.39k| } _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| 660k| 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| 660k| HttpRequest req; 588| | 589| 660k| if (remainingStreamingBytes) { ------------------ | Branch (589:13): [True: 2.39k, False: 658k] ------------------ 590| | 591| | /* It's either chunked or with a content-length */ 592| 2.39k| if (isParsingChunkedEncoding(remainingStreamingBytes)) { ------------------ | Branch (592:17): [True: 1.81k, False: 583] ------------------ 593| 1.81k| std::string_view dataToConsume(data, length); 594| 1.81k| for (auto chunk : uWS::ChunkIterator(&dataToConsume, &remainingStreamingBytes)) { ------------------ | Branch (594:33): [True: 592, False: 1.81k] ------------------ 595| 592| dataHandler(user, chunk, chunk.length() == 0); 596| 592| } 597| 1.81k| if (isParsingInvalidChunkedEncoding(remainingStreamingBytes)) { ------------------ | Branch (597:21): [True: 512, False: 1.30k] ------------------ 598| 512| return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR}; 599| 512| } 600| 1.30k| data = (char *) dataToConsume.data(); 601| 1.30k| length = (unsigned int) dataToConsume.length(); 602| 1.30k| } else { 603| | // this is exactly the same as below! 604| | // todo: refactor this 605| 583| if (remainingStreamingBytes >= length) { ------------------ | Branch (605:21): [True: 388, False: 195] ------------------ 606| 388| void *returnedUser = dataHandler(user, std::string_view(data, length), remainingStreamingBytes == length); 607| 388| remainingStreamingBytes -= length; 608| 388| return {0, returnedUser}; 609| 388| } else { 610| 195| void *returnedUser = dataHandler(user, std::string_view(data, remainingStreamingBytes), true); 611| | 612| 195| data += (unsigned int) remainingStreamingBytes; 613| 195| length -= (unsigned int) remainingStreamingBytes; 614| | 615| 195| remainingStreamingBytes = 0; 616| | 617| 195| if (returnedUser != user) { ------------------ | Branch (617:25): [True: 0, False: 195] ------------------ 618| 0| return {0, returnedUser}; 619| 0| } 620| 195| } 621| 583| } 622| | 623| 658k| } else if (fallback.length()) { ------------------ | Branch (623:20): [True: 19.8k, False: 638k] ------------------ 624| 19.8k| unsigned int had = (unsigned int) fallback.length(); 625| | 626| 19.8k| 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| 19.8k| fallback.reserve(fallback.length() + maxCopyDistance + std::max(MINIMUM_HTTP_POST_PADDING, sizeof(std::string))); 630| 19.8k| fallback.append(data, maxCopyDistance); 631| | 632| | // break here on break 633| 19.8k| std::pair consumed = fenceAndConsumePostPadded(fallback.data(), (unsigned int) fallback.length(), user, reserved, &req, requestHandler, dataHandler); 634| 19.8k| if (consumed.second != user) { ------------------ | Branch (634:17): [True: 1.82k, False: 17.9k] ------------------ 635| 1.82k| return consumed; 636| 1.82k| } 637| | 638| 17.9k| if (consumed.first) { ------------------ | Branch (638:17): [True: 2.13k, False: 15.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| 2.13k| fallback.clear(); 644| 2.13k| data += consumed.first - had; 645| 2.13k| length -= consumed.first - had; 646| | 647| 2.13k| if (remainingStreamingBytes) { ------------------ | Branch (647:21): [True: 1.30k, False: 829] ------------------ 648| | /* It's either chunked or with a content-length */ 649| 1.30k| if (isParsingChunkedEncoding(remainingStreamingBytes)) { ------------------ | Branch (649:25): [True: 804, False: 499] ------------------ 650| 804| std::string_view dataToConsume(data, length); 651| 804| for (auto chunk : uWS::ChunkIterator(&dataToConsume, &remainingStreamingBytes)) { ------------------ | Branch (651:41): [True: 684, False: 804] ------------------ 652| 684| dataHandler(user, chunk, chunk.length() == 0); 653| 684| } 654| 804| if (isParsingInvalidChunkedEncoding(remainingStreamingBytes)) { ------------------ | Branch (654:29): [True: 209, False: 595] ------------------ 655| 209| return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR}; 656| 209| } 657| 595| data = (char *) dataToConsume.data(); 658| 595| length = (unsigned int) dataToConsume.length(); 659| 595| } else { 660| | // this is exactly the same as above! 661| 499| if (remainingStreamingBytes >= (unsigned int) length) { ------------------ | Branch (661:29): [True: 304, False: 195] ------------------ 662| 304| void *returnedUser = dataHandler(user, std::string_view(data, length), remainingStreamingBytes == (unsigned int) length); 663| 304| remainingStreamingBytes -= length; 664| 304| return {0, returnedUser}; 665| 304| } else { 666| 195| void *returnedUser = dataHandler(user, std::string_view(data, remainingStreamingBytes), true); 667| | 668| 195| data += (unsigned int) remainingStreamingBytes; 669| 195| length -= (unsigned int) remainingStreamingBytes; 670| | 671| 195| remainingStreamingBytes = 0; 672| | 673| 195| if (returnedUser != user) { ------------------ | Branch (673:33): [True: 0, False: 195] ------------------ 674| 0| return {0, returnedUser}; 675| 0| } 676| 195| } 677| 499| } 678| 1.30k| } 679| | 680| 15.8k| } else { 681| 15.8k| if (fallback.length() == MAX_FALLBACK_SIZE) { ------------------ | Branch (681:21): [True: 195, False: 15.6k] ------------------ 682| 195| return {HTTP_ERROR_431_REQUEST_HEADER_FIELDS_TOO_LARGE, FULLPTR}; 683| 195| } 684| 15.6k| return {0, user}; 685| 15.8k| } 686| 17.9k| } 687| | 688| 641k| std::pair consumed = fenceAndConsumePostPadded(data, length, user, reserved, &req, requestHandler, dataHandler); 689| 641k| if (consumed.second != user) { ------------------ | Branch (689:13): [True: 621k, False: 20.3k] ------------------ 690| 621k| return consumed; 691| 621k| } 692| | 693| 20.3k| data += consumed.first; 694| 20.3k| length -= consumed.first; 695| | 696| 20.3k| if (length) { ------------------ | Branch (696:13): [True: 14.8k, False: 5.52k] ------------------ 697| 14.8k| if (length < MAX_FALLBACK_SIZE) { ------------------ | Branch (697:17): [True: 14.8k, False: 0] ------------------ 698| 14.8k| fallback.append(data, length); 699| 14.8k| } else { 700| 0| return {HTTP_ERROR_431_REQUEST_HEADER_FIELDS_TOO_LARGE, FULLPTR}; 701| 0| } 702| 14.8k| } 703| | 704| | // added for now 705| 20.3k| return {0, user}; 706| 20.3k| } _ZN3uWS10HttpParser25fenceAndConsumePostPaddedILi1EEENSt3__14pairIjPvEEPcjS4_S4_PNS_11HttpRequestERN5ofats13any_invocableIFS4_S4_S8_EEERNSA_IFS4_S4_NS2_17basic_string_viewIcNS2_11char_traitsIcEEEEbEEE: 448| 19.8k| 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| 19.8k| unsigned int consumedTotal = 0; 452| 19.8k| 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| 19.8k| data[length] = '\r'; 457| 19.8k| data[length + 1] = 'a'; /* Anything that is not \n, to trigger "invalid request" */ 458| | 459| 19.8k| for (unsigned int consumed; length && (consumed = getHeaders(data, data + length, req->headers, reserved, err)); ) { ------------------ | Branch (459:37): [True: 19.8k, False: 0] | Branch (459:47): [True: 3.95k, False: 15.8k] ------------------ 460| 3.95k| data += consumed; 461| 3.95k| length -= consumed; 462| 3.95k| consumedTotal += consumed; 463| | 464| | /* Even if we could parse it, check for length here as well */ 465| 3.95k| if (consumed > MAX_FALLBACK_SIZE) { ------------------ | Branch (465:17): [True: 0, False: 3.95k] ------------------ 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.95k| req->ancientHttp = false; 471| | 472| | /* Add all headers to bloom filter */ 473| 3.95k| req->bf.reset(); 474| 14.4k| for (HttpRequest::Header *h = req->headers; (++h)->key.length(); ) { ------------------ | Branch (474:57): [True: 10.5k, False: 3.95k] ------------------ 475| 10.5k| req->bf.add(h->key); 476| 10.5k| } 477| | 478| | /* Break if no host header (but we can have empty string which is different from nullptr) */ 479| 3.95k| if (!req->getHeader("host").data()) { ------------------ | Branch (479:17): [True: 278, False: 3.67k] ------------------ 480| 278| return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR}; 481| 278| } 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| 3.67k| std::string_view transferEncodingString = req->getHeader("transfer-encoding"); 489| 3.67k| std::string_view contentLengthString = req->getHeader("content-length"); 490| 3.67k| if (transferEncodingString.length() && contentLengthString.length()) { ------------------ | Branch (490:17): [True: 1.12k, False: 2.55k] | Branch (490:52): [True: 317, False: 804] ------------------ 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| 317| return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR}; 495| 317| } 496| | 497| | /* Parse query */ 498| 3.36k| const char *querySeparatorPtr = (const char *) memchr(req->headers->value.data(), '?', req->headers->value.length()); 499| 3.36k| req->querySeparator = (unsigned int) ((querySeparatorPtr ? querySeparatorPtr : req->headers->value.data() + req->headers->value.length()) - req->headers->value.data()); ------------------ | Branch (499:52): [True: 265, False: 3.09k] ------------------ 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| 3.36k| void *returnedUser = requestHandler(user, req); 505| 3.36k| if (returnedUser != user) { ------------------ | Branch (505:17): [True: 815, False: 2.54k] ------------------ 506| | /* We are upgraded to WebSocket or otherwise broken */ 507| 815| return {consumedTotal, returnedUser}; 508| 815| } 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| 2.54k| if (transferEncodingString.length()) { ------------------ | Branch (519:17): [True: 804, False: 1.74k] ------------------ 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| 804| 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| 804| 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.74k| } else if (contentLengthString.length()) { ------------------ | Branch (549:24): [True: 914, False: 828] ------------------ 550| 914| remainingStreamingBytes = toUnsignedInteger(contentLengthString); 551| 914| if (remainingStreamingBytes == UINT64_MAX) { ------------------ | Branch (551:21): [True: 414, False: 500] ------------------ 552| | /* Parser error */ 553| 414| return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR}; 554| 414| } 555| | 556| 500| 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| 828| } else { 566| | /* If we came here without a body; emit an empty data chunk to signal no data */ 567| 828| dataHandler(user, {}, true); 568| 828| } 569| | 570| | /* Consume minimally should break as easrly as possible */ 571| 2.13k| if (CONSUME_MINIMALLY) { ------------------ | Branch (571:17): [Folded - Ignored] ------------------ 572| 2.13k| break; 573| 2.13k| } 574| 2.13k| } 575| | /* Whenever we return FULLPTR, the interpretation of "consumed" should be the HttpError enum. */ 576| 17.9k| if (err) { ------------------ | Branch (576:13): [True: 0, False: 17.9k] ------------------ 577| 0| return {err, FULLPTR}; 578| 0| } 579| 17.9k| return {consumedTotal, user}; 580| 17.9k| } _ZN3uWS10HttpParser10getHeadersEPcS1_PNS_11HttpRequest6HeaderEPvRj: 337| 672k| static unsigned int getHeaders(char *postPaddedBuffer, char *end, struct HttpRequest::Header *headers, void *reserved, unsigned int &err) { 338| 672k| 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| 672k| (void) reserved; 358| 672k| (void) end; 359| 672k| #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| 672k| if (!(postPaddedBuffer = consumeRequestLine(postPaddedBuffer, headers[0]))) { ------------------ | Branch (367:13): [True: 514k, False: 158k] ------------------ 368| | /* Error - invalid request line */ 369| | /* Assuming it is 505 HTTP Version Not Supported */ 370| 514k| err = HTTP_ERROR_505_HTTP_VERSION_NOT_SUPPORTED; 371| 514k| return 0; 372| 514k| } 373| 158k| headers++; 374| | 375| 346k| for (unsigned int i = 1; i < UWS_HTTP_MAX_HEADERS_COUNT - 1; i++) { ------------------ | | 53| 346k|#define UWS_HTTP_MAX_HEADERS_COUNT 100 ------------------ | Branch (375:34): [True: 346k, False: 194] ------------------ 376| | /* Lower case and consume the field name */ 377| 346k| preliminaryKey = postPaddedBuffer; 378| 346k| postPaddedBuffer = (char *) consumeFieldName(postPaddedBuffer); 379| 346k| 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| 346k| if (postPaddedBuffer[0] != ':') { ------------------ | Branch (382:17): [True: 17.0k, False: 329k] ------------------ 383| | /* Error: invalid chars in field name */ 384| 17.0k| return 0; 385| 17.0k| } 386| 329k| postPaddedBuffer++; 387| | 388| 329k| preliminaryValue = postPaddedBuffer; 389| | /* The goal of this call is to find next "\r\n", or any invalid field value chars, fast */ 390| 329k| while (true) { ------------------ | Branch (390:20): [Folded - Ignored] ------------------ 391| 329k| postPaddedBuffer = (char *) tryConsumeFieldValue(postPaddedBuffer); 392| | /* If this is not CR then we caught some stinky invalid char on the way */ 393| 329k| if (postPaddedBuffer[0] != '\r') { ------------------ | Branch (393:21): [True: 4.05k, False: 325k] ------------------ 394| | /* If TAB then keep searching */ 395| 4.05k| if (postPaddedBuffer[0] == '\t') { ------------------ | Branch (395:25): [True: 556, False: 3.49k] ------------------ 396| 556| postPaddedBuffer++; 397| 556| continue; 398| 556| } 399| | /* Error - invalid chars in field value */ 400| 3.49k| return 0; 401| 4.05k| } 402| 325k| break; 403| 329k| } 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| 325k| if (postPaddedBuffer[1] == '\n') { ------------------ | Branch (406:17): [True: 316k, False: 8.75k] ------------------ 407| | /* Store this header, it is valid */ 408| 316k| headers->value = std::string_view(preliminaryValue, (size_t) (postPaddedBuffer - preliminaryValue)); 409| 316k| postPaddedBuffer += 2; 410| | 411| | /* Trim trailing whitespace (SP, HTAB) */ 412| 340k| while (headers->value.length() && headers->value.back() < 33) { ------------------ | Branch (412:24): [True: 297k, False: 42.7k] | Branch (412:51): [True: 23.9k, False: 274k] ------------------ 413| 23.9k| headers->value.remove_suffix(1); 414| 23.9k| } 415| | 416| | /* Trim initial whitespace (SP, HTAB) */ 417| 465k| while (headers->value.length() && headers->value.front() < 33) { ------------------ | Branch (417:24): [True: 422k, False: 42.7k] | Branch (417:51): [True: 148k, False: 274k] ------------------ 418| 148k| headers->value.remove_prefix(1); 419| 148k| } 420| | 421| 316k| headers++; 422| | 423| | /* We definitely have at least one header (or request line), so check if we are done */ 424| 316k| if (*postPaddedBuffer == '\r') { ------------------ | Branch (424:21): [True: 128k, False: 188k] ------------------ 425| 128k| if (postPaddedBuffer[1] == '\n') { ------------------ | Branch (425:25): [True: 127k, False: 1.27k] ------------------ 426| | /* This cann take the very last header space */ 427| 127k| headers->key = std::string_view(nullptr, 0); 428| 127k| return (unsigned int) ((postPaddedBuffer + 2) - start); 429| 127k| } else { 430| | /* \r\n\r plus non-\n letter is malformed request, or simply out of search space */ 431| 1.27k| return 0; 432| 1.27k| } 433| 128k| } 434| 316k| } else { 435| | /* We are either out of search space or this is a malformed request */ 436| 8.75k| return 0; 437| 8.75k| } 438| 325k| } 439| | /* We ran out of header space, too large request */ 440| 194| return 0; 441| 158k| } _ZN3uWS10HttpParser18consumeRequestLineEPcRNS_11HttpRequest6HeaderE: 293| 672k| static inline char *consumeRequestLine(char *data, HttpRequest::Header &header) { 294| | /* Scan until single SP, assume next is / (origin request) */ 295| 672k| char *start = data; 296| | /* This catches the post padded CR and fails */ 297| 1.91M| while (data[0] > 32) data++; ------------------ | Branch (297:16): [True: 1.24M, False: 672k] ------------------ 298| 672k| if (data[0] == 32 && data[1] == '/') { ------------------ | Branch (298:13): [True: 183k, False: 488k] | Branch (298:30): [True: 162k, False: 21.0k] ------------------ 299| 162k| header.key = {start, (size_t) (data - start)}; 300| 162k| data++; 301| | /* Scan for less than 33 (catches post padded CR and fails) */ 302| 162k| start = data; 303| 162k| for (; true; data += 8) { ------------------ | Branch (303:20): [Folded - Ignored] ------------------ 304| 162k| uint64_t word; 305| 162k| memcpy(&word, data, sizeof(uint64_t)); 306| 162k| if (hasLess(word, 33)) { ------------------ | Branch (306:21): [True: 162k, False: 678] ------------------ 307| 476k| while (*(unsigned char *)data > 32) data++; ------------------ | Branch (307:28): [True: 314k, False: 162k] ------------------ 308| | /* Now we stand on space */ 309| 162k| header.value = {start, (size_t) (data - start)}; 310| | /* Check that the following is http 1.1 */ 311| 162k| if (memcmp(" HTTP/1.1\r\n", data, 11) == 0) { ------------------ | Branch (311:25): [True: 158k, False: 4.21k] ------------------ 312| 158k| return data + 11; 313| 158k| } 314| 4.21k| return nullptr; 315| 162k| } 316| 162k| } 317| 162k| } 318| 509k| return nullptr; 319| 672k| } _ZN3uWS10HttpParser7hasLessEmm: 220| 1.00M| static inline uint64_t hasLess(uint64_t x, uint64_t n) { 221| 1.00M| return (((x)-~0ULL/255*(n))&~(x)&~0ULL/255*128); 222| 1.00M| } _ZN3uWS10HttpParser16consumeFieldNameEPc: 264| 346k| static inline void *consumeFieldName(char *p) { 265| | /* Best case fast path (particularly useful with clang) */ 266| 654k| while (true) { ------------------ | Branch (266:16): [Folded - Ignored] ------------------ 267| 673k| while ((*p >= 65) & (*p <= 90)) [[likely]] { ------------------ | Branch (267:20): [True: 19.1k, False: 654k] ------------------ 268| 19.1k| *p |= 32; 269| 19.1k| p++; 270| 19.1k| } 271| 3.56M| while (((*p >= 97) & (*p <= 122))) [[likely]] { ------------------ | Branch (271:20): [True: 2.90M, False: 654k] ------------------ 272| 2.90M| p++; 273| 2.90M| } 274| 654k| if (*p == ':') { ------------------ | Branch (274:17): [True: 326k, False: 327k] ------------------ 275| 326k| return (void *)p; 276| 326k| } 277| 327k| if (*p == '-') { ------------------ | Branch (277:17): [True: 293k, False: 33.5k] ------------------ 278| 293k| p++; 279| 293k| } else if (!((*p >= 65) & (*p <= 90))) { ------------------ | Branch (279:24): [True: 19.2k, False: 14.2k] ------------------ 280| | /* Exit fast path parsing */ 281| 19.2k| break; 282| 19.2k| } 283| 327k| } 284| | 285| | /* Generic */ 286| 43.2k| while (isFieldNameByteFastLowercased(*(unsigned char *)p)) { ------------------ | Branch (286:16): [True: 23.9k, False: 19.2k] ------------------ 287| 23.9k| p++; 288| 23.9k| } 289| 19.2k| return (void *)p; 290| 346k| } _ZN3uWS10HttpParser29isFieldNameByteFastLowercasedERh: 249| 43.2k| static inline bool isFieldNameByteFastLowercased(unsigned char &in) { 250| | /* Most common is lowercase alpha and hyphen */ 251| 43.2k| if (((in >= 97) & (in <= 122)) | (in == '-')) [[likely]] { ------------------ | Branch (251:13): [True: 8.63k, False: 34.5k] ------------------ 252| 8.63k| return true; 253| | /* Second is upper case alpha */ 254| 34.5k| } else if ((in >= 65) & (in <= 90)) [[unlikely]] { ------------------ | Branch (254:20): [True: 3.50k, False: 31.0k] ------------------ 255| 3.50k| in |= 32; 256| 3.50k| return true; 257| | /* These are rarely used but still valid */ 258| 31.0k| } else if (isUnlikelyFieldNameByte(in)) [[unlikely]] { ------------------ | Branch (258:20): [True: 11.7k, False: 19.2k] ------------------ 259| 11.7k| return true; 260| 11.7k| } 261| 19.2k| return false; 262| 43.2k| } _ZN3uWS10HttpParser23isUnlikelyFieldNameByteEh: 243| 31.0k| { 244| | /* Digits and 14 of the 15 non-alphanum characters (lacking hyphen) */ 245| 31.0k| return ((c == '~') | (c == '|') | (c == '`') | (c == '_') | (c == '^') | (c == '.') | (c == '+') ------------------ | Branch (245:16): [True: 1.19k, False: 29.8k] ------------------ 246| 31.0k| | (c == '*') | (c == '!')) || ((c >= 48) & (c <= 57)) || ((c <= 39) & (c >= 35)); ------------------ | Branch (246:43): [True: 9.99k, False: 19.8k] | Branch (246:70): [True: 607, False: 19.2k] ------------------ 247| 31.0k| } _ZN3uWS10HttpParser20tryConsumeFieldValueEPc: 325| 329k| static inline void *tryConsumeFieldValue(char *p) { 326| 842k| for (; true; p += 8) { ------------------ | Branch (326:16): [Folded - Ignored] ------------------ 327| 842k| uint64_t word; 328| 842k| memcpy(&word, p, sizeof(uint64_t)); 329| 842k| if (hasLess(word, 32)) { ------------------ | Branch (329:17): [True: 329k, False: 513k] ------------------ 330| 1.04M| while (*(unsigned char *)p > 31) p++; ------------------ | Branch (330:24): [True: 712k, False: 329k] ------------------ 331| 329k| return (void *)p; 332| 329k| } 333| 842k| } 334| 329k| } _ZN3uWS11HttpRequest9getHeaderENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE: 115| 1.05M| std::string_view getHeader(std::string_view lowerCasedHeader) { 116| 1.05M| if (bf.mightHave(lowerCasedHeader)) { ------------------ | Branch (116:13): [True: 253k, False: 805k] ------------------ 117| 413k| for (Header *h = headers; (++h)->key.length(); ) { ------------------ | Branch (117:39): [True: 412k, False: 1.08k] ------------------ 118| 412k| if (h->key.length() == lowerCasedHeader.length() && !strncmp(h->key.data(), lowerCasedHeader.data(), lowerCasedHeader.length())) { ------------------ | Branch (118:21): [True: 253k, False: 159k] | Branch (118:69): [True: 252k, False: 817] ------------------ 119| 252k| return h->value; 120| 252k| } 121| 412k| } 122| 253k| } 123| 806k| return std::string_view(nullptr, 0); 124| 1.05M| } _ZN3uWS10HttpParser17toUnsignedIntegerENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE: 203| 2.92k| static uint64_t toUnsignedInteger(std::string_view str) { 204| | /* We assume at least 64-bit integer giving us safely 999999999999999999 (18 number of 9s) */ 205| 2.92k| if (str.length() > 18) { ------------------ | Branch (205:13): [True: 405, False: 2.52k] ------------------ 206| 405| return UINT64_MAX; 207| 405| } 208| | 209| 2.52k| uint64_t unsignedIntegerValue = 0; 210| 13.2k| for (char c : str) { ------------------ | Branch (210:21): [True: 13.2k, False: 2.06k] ------------------ 211| | /* As long as the letter is 0-9 we cannot overflow. */ 212| 13.2k| if (c < '0' || c > '9') { ------------------ | Branch (212:17): [True: 27, False: 13.1k] | Branch (212:28): [True: 430, False: 12.7k] ------------------ 213| 457| return UINT64_MAX; 214| 457| } 215| 12.7k| unsignedIntegerValue = unsignedIntegerValue * 10ull + ((unsigned int) c - (unsigned int) '0'); 216| 12.7k| } 217| 2.06k| return unsignedIntegerValue; 218| 2.52k| } _ZN3uWS10HttpParser25fenceAndConsumePostPaddedILi0EEENSt3__14pairIjPvEEPcjS4_S4_PNS_11HttpRequestERN5ofats13any_invocableIFS4_S4_S8_EEERNSA_IFS4_S4_NS2_17basic_string_viewIcNS2_11char_traitsIcEEEEbEEE: 448| 641k| 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| 641k| unsigned int consumedTotal = 0; 452| 641k| 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| 641k| data[length] = '\r'; 457| 641k| data[length + 1] = 'a'; /* Anything that is not \n, to trigger "invalid request" */ 458| | 459| 657k| for (unsigned int consumed; length && (consumed = getHeaders(data, data + length, req->headers, reserved, err)); ) { ------------------ | Branch (459:37): [True: 652k, False: 5.52k] | Branch (459:47): [True: 123k, False: 529k] ------------------ 460| 123k| data += consumed; 461| 123k| length -= consumed; 462| 123k| consumedTotal += consumed; 463| | 464| | /* Even if we could parse it, check for length here as well */ 465| 123k| if (consumed > MAX_FALLBACK_SIZE) { ------------------ | Branch (465:17): [True: 0, False: 123k] ------------------ 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| 123k| req->ancientHttp = false; 471| | 472| | /* Add all headers to bloom filter */ 473| 123k| req->bf.reset(); 474| 382k| for (HttpRequest::Header *h = req->headers; (++h)->key.length(); ) { ------------------ | Branch (474:57): [True: 258k, False: 123k] ------------------ 475| 258k| req->bf.add(h->key); 476| 258k| } 477| | 478| | /* Break if no host header (but we can have empty string which is different from nullptr) */ 479| 123k| if (!req->getHeader("host").data()) { ------------------ | Branch (479:17): [True: 1.46k, False: 121k] ------------------ 480| 1.46k| return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR}; 481| 1.46k| } 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| 121k| std::string_view transferEncodingString = req->getHeader("transfer-encoding"); 489| 121k| std::string_view contentLengthString = req->getHeader("content-length"); 490| 121k| if (transferEncodingString.length() && contentLengthString.length()) { ------------------ | Branch (490:17): [True: 2.52k, False: 119k] | Branch (490:52): [True: 243, False: 2.27k] ------------------ 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| 243| return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR}; 495| 243| } 496| | 497| | /* Parse query */ 498| 121k| const char *querySeparatorPtr = (const char *) memchr(req->headers->value.data(), '?', req->headers->value.length()); 499| 121k| req->querySeparator = (unsigned int) ((querySeparatorPtr ? querySeparatorPtr : req->headers->value.data() + req->headers->value.length()) - req->headers->value.data()); ------------------ | Branch (499:52): [True: 422, False: 121k] ------------------ 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| 121k| void *returnedUser = requestHandler(user, req); 505| 121k| if (returnedUser != user) { ------------------ | Branch (505:17): [True: 104k, False: 17.0k] ------------------ 506| | /* We are upgraded to WebSocket or otherwise broken */ 507| 104k| return {consumedTotal, returnedUser}; 508| 104k| } 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| 17.0k| if (transferEncodingString.length()) { ------------------ | Branch (519:17): [True: 2.27k, False: 14.7k] ------------------ 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| 2.27k| 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| 2.27k| 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| 2.27k| std::string_view dataToConsume(data, length); 538| 2.27k| for (auto chunk : uWS::ChunkIterator(&dataToConsume, &remainingStreamingBytes)) { ------------------ | Branch (538:37): [True: 1.40k, False: 2.27k] ------------------ 539| 1.40k| dataHandler(user, chunk, chunk.length() == 0); 540| 1.40k| } 541| 2.27k| if (isParsingInvalidChunkedEncoding(remainingStreamingBytes)) { ------------------ | Branch (541:25): [True: 495, False: 1.78k] ------------------ 542| 495| return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR}; 543| 495| } 544| 1.78k| unsigned int consumed = (length - (unsigned int) dataToConsume.length()); 545| 1.78k| data = (char *) dataToConsume.data(); 546| 1.78k| length = (unsigned int) dataToConsume.length(); 547| 1.78k| consumedTotal += consumed; 548| 1.78k| } 549| 14.7k| } else if (contentLengthString.length()) { ------------------ | Branch (549:24): [True: 2.01k, False: 12.7k] ------------------ 550| 2.01k| remainingStreamingBytes = toUnsignedInteger(contentLengthString); 551| 2.01k| if (remainingStreamingBytes == UINT64_MAX) { ------------------ | Branch (551:21): [True: 448, False: 1.56k] ------------------ 552| | /* Parser error */ 553| 448| return {HTTP_ERROR_400_BAD_REQUEST, FULLPTR}; 554| 448| } 555| | 556| 1.56k| if (!CONSUME_MINIMALLY) { ------------------ | Branch (556:21): [Folded - Ignored] ------------------ 557| 1.56k| unsigned int emittable = (unsigned int) std::min(remainingStreamingBytes, length); 558| 1.56k| dataHandler(user, std::string_view(data, emittable), emittable == remainingStreamingBytes); 559| 1.56k| remainingStreamingBytes -= emittable; 560| | 561| 1.56k| data += emittable; 562| 1.56k| length -= emittable; 563| 1.56k| consumedTotal += emittable; 564| 1.56k| } 565| 12.7k| } else { 566| | /* If we came here without a body; emit an empty data chunk to signal no data */ 567| 12.7k| dataHandler(user, {}, true); 568| 12.7k| } 569| | 570| | /* Consume minimally should break as easrly as possible */ 571| 16.0k| if (CONSUME_MINIMALLY) { ------------------ | Branch (571:17): [Folded - Ignored] ------------------ 572| 0| break; 573| 0| } 574| 16.0k| } 575| | /* Whenever we return FULLPTR, the interpretation of "consumed" should be the HttpError enum. */ 576| 534k| if (err) { ------------------ | Branch (576:13): [True: 514k, False: 20.3k] ------------------ 577| 514k| return {err, FULLPTR}; 578| 514k| } 579| 20.3k| return {consumedTotal, user}; 580| 534k| } _ZN3uWS11HttpRequest9isAncientEv: 72| 124k| bool isAncient() { 73| 124k| return ancientHttp; 74| 124k| } _ZN3uWS11HttpRequest22getCaseSensitiveMethodEv: 135| 124k| std::string_view getCaseSensitiveMethod() { 136| 124k| return std::string_view(headers->key.data(), headers->key.length()); 137| 124k| } _ZN3uWS11HttpRequest6getUrlEv: 126| 124k| std::string_view getUrl() { 127| 124k| return std::string_view(headers->value.data(), querySeparator); 128| 124k| } _ZN3uWS11HttpRequest8setYieldEb: 111| 133k| void setYield(bool yield) { 112| 133k| didYield = yield; 113| 133k| } _ZN3uWS11HttpRequest13setParametersENSt3__14pairIiPNS1_17basic_string_viewIcNS1_11char_traitsIcEEEEEE: 166| 129k| void setParameters(std::pair parameters) { 167| 129k| currentParameters = parameters; 168| 129k| } _ZN3uWS11HttpRequest19setParameterOffsetsEPNSt3__13mapINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEtNS1_4lessIvEENS6_INS1_4pairIKS8_tEEEEEE: 170| 129k| void setParameterOffsets(std::map> *offsets) { 171| 129k| currentParameterOffsets = offsets; 172| 129k| } _ZN3uWS11HttpRequest8getYieldEv: 76| 129k| bool getYield() { 77| 129k| return didYield; 78| 129k| } _ZN3uWS12HttpResponseILb1EE12hasRespondedEv: 490| 39.1k| bool hasResponded() { 491| 39.1k| HttpResponseData *httpResponseData = getHttpResponseData(); 492| | 493| 39.1k| return !(httpResponseData->state & HttpResponseData::HTTP_RESPONSE_PENDING); 494| 39.1k| } _ZN3uWS12HttpResponseILb1EE19getHttpResponseDataEv: 52| 1.19M| HttpResponseData *getHttpResponseData() { 53| 1.19M| return (HttpResponseData *) Super::getAsyncSocketData(); 54| 1.19M| } _ZN3uWS12HttpResponseILb1EE13writeContinueEv: 377| 194| HttpResponse *writeContinue() { 378| 194| Super::write("HTTP/1.1 100 Continue\r\n\r\n", 25); 379| 194| return this; 380| 194| } _ZN3uWS12HttpResponseILb1EE11writeStatusENSt3__117basic_string_viewIcNS2_11char_traitsIcEEEE: 383| 816k| HttpResponse *writeStatus(std::string_view status) { 384| 816k| HttpResponseData *httpResponseData = getHttpResponseData(); 385| | 386| | /* Do not allow writing more than one status */ 387| 816k| if (httpResponseData->state & HttpResponseData::HTTP_STATUS_CALLED) { ------------------ | Branch (387:13): [True: 691k, False: 124k] ------------------ 388| 691k| return this; 389| 691k| } 390| | 391| | /* Update status */ 392| 124k| httpResponseData->state |= HttpResponseData::HTTP_STATUS_CALLED; 393| | 394| 124k| Super::write("HTTP/1.1 ", 9); 395| 124k| Super::write(status.data(), (int) status.length()); 396| 124k| Super::write("\r\n", 2); 397| 124k| return this; 398| 816k| } _ZN3uWS12HttpResponseILb1EE3endENSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEb: 432| 19.5k| void end(std::string_view data = {}, bool closeConnection = false) { 433| 19.5k| internalEnd(data, data.length(), false, true, closeConnection); 434| 19.5k| } _ZN3uWS12HttpResponseILb1EE11internalEndENSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEmbbb: 92| 124k| 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| 124k| writeStatus(HTTP_200_OK); 95| | 96| | /* If no total size given then assume this chunk is everything */ 97| 124k| if (!totalSize) { ------------------ | Branch (97:13): [True: 105k, False: 19.5k] ------------------ 98| 105k| totalSize = data.length(); 99| 105k| } 100| | 101| 124k| HttpResponseData *httpResponseData = getHttpResponseData(); 102| | 103| | /* In some cases, such as when refusing huge data we want to close the connection when drained */ 104| 124k| if (closeConnection) { ------------------ | Branch (104:13): [True: 0, False: 124k] ------------------ 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| 124k| if (httpResponseData->state & HttpResponseData::HTTP_WRITE_CALLED) { ------------------ | Branch (118:13): [True: 0, False: 124k] ------------------ 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| 124k| } else { 156| | /* Write content-length on first call */ 157| 124k| if (!(httpResponseData->state & HttpResponseData::HTTP_END_CALLED)) { ------------------ | Branch (157:17): [True: 124k, False: 0] ------------------ 158| | /* Write mark, this propagates to WebSockets too */ 159| 124k| writeMark(); 160| | 161| | /* WebSocket upgrades does not allow content-length */ 162| 124k| if (allowContentLength) { ------------------ | Branch (162:21): [True: 19.5k, False: 105k] ------------------ 163| | /* Even zero is a valid content-length */ 164| 19.5k| Super::write("Content-Length: ", 16); 165| 19.5k| writeUnsigned64(totalSize); 166| 19.5k| Super::write("\r\n\r\n", 4); 167| 105k| } else { 168| 105k| Super::write("\r\n", 2); 169| 105k| } 170| | 171| | /* Mark end called */ 172| 124k| httpResponseData->state |= HttpResponseData::HTTP_END_CALLED; 173| 124k| } 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| 124k| size_t written = 0; 180| 124k| bool failed = false; 181| 144k| while (written < data.length() && !failed) { ------------------ | Branch (181:20): [True: 19.5k, False: 124k] | Branch (181:47): [True: 19.5k, False: 0] ------------------ 182| | /* uSockets only deals with int sizes, so pass chunks of max signed int size */ 183| 19.5k| auto writtenFailed = Super::write(data.data() + written, (int) std::min(data.length() - written, INT_MAX), optional); 184| | 185| 19.5k| written += (size_t) writtenFailed.first; 186| 19.5k| failed = writtenFailed.second; 187| 19.5k| } 188| | 189| 124k| httpResponseData->offset += written; 190| | 191| | /* Success is when we wrote the entire thing without any failures */ 192| 124k| bool success = written == data.length() && !failed; ------------------ | Branch (192:28): [True: 124k, False: 0] | Branch (192:56): [True: 124k, False: 207] ------------------ 193| | 194| | /* If we are now at the end, start a timeout. Also start a timeout if we failed. */ 195| 124k| if (!success || httpResponseData->offset == totalSize) { ------------------ | Branch (195:17): [True: 207, False: 124k] | Branch (195:29): [True: 124k, False: 0] ------------------ 196| 124k| Super::timeout(HTTP_TIMEOUT_S); 197| 124k| } 198| | 199| | /* Remove onAborted function if we reach the end */ 200| 124k| if (httpResponseData->offset == totalSize) { ------------------ | Branch (200:17): [True: 124k, False: 0] ------------------ 201| 124k| httpResponseData->markDone(); 202| | 203| | /* We need to check if we should close this socket here now */ 204| 124k| if (!Super::isCorked()) { ------------------ | Branch (204:21): [True: 0, False: 124k] ------------------ 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| 124k| } 217| | 218| 124k| return success; 219| 124k| } 220| 124k| } _ZN3uWS12HttpResponseILb1EE11writeHeaderENSt3__117basic_string_viewIcNS2_11char_traitsIcEEEES6_: 401| 566k| HttpResponse *writeHeader(std::string_view key, std::string_view value) { 402| 566k| writeStatus(HTTP_200_OK); 403| | 404| 566k| Super::write(key.data(), (int) key.length()); 405| 566k| Super::write(": ", 2); 406| 566k| Super::write(value.data(), (int) value.length()); 407| 566k| Super::write("\r\n", 2); 408| 566k| return this; 409| 566k| } _ZN3uWS12HttpResponseILb1EE9writeMarkEv: 77| 124k| void writeMark() { 78| | /* Date is always written */ 79| 124k| 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| 124k|#ifndef UWS_HTTPRESPONSE_NO_WRITEMARK 83| 124k| if (!Super::getLoopData()->noMark) { ------------------ | Branch (83:13): [True: 124k, False: 0] ------------------ 84| | /* We only expose major version */ 85| 124k| writeHeader("uWebSockets", "20"); 86| 124k| } 87| 124k|#endif 88| 124k| } _ZN3uWS12HttpResponseILb1EE15writeUnsigned64Em: 68| 19.5k| void writeUnsigned64(uint64_t value) { 69| 19.5k| char buf[20]; 70| 19.5k| int length = utils::u64toa(value, buf); 71| | 72| | /* For now we do this copy */ 73| 19.5k| Super::write(buf, length); 74| 19.5k| } EpollEchoServerPubSub.cpp:_ZN3uWS12HttpResponseILb1EE7upgradeIZ4testvE13PerSocketDataEEvOT_NSt3__117basic_string_viewIcNS6_11char_traitsIcEEEESA_SA_P19us_socket_context_t: 239| 105k| struct us_socket_context_t *webSocketContext) { 240| | 241| | /* Extract needed parameters from WebSocketContextData */ 242| 105k| WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, webSocketContext); 243| | 244| | /* Note: OpenSSL can be used here to speed this up somewhat */ 245| 105k| char secWebSocketAccept[29] = {}; 246| 105k| WebSocketHandshake::generate(secWebSocketKey.data(), secWebSocketAccept); 247| | 248| 105k| writeStatus("101 Switching Protocols") 249| 105k| ->writeHeader("Upgrade", "websocket") 250| 105k| ->writeHeader("Connection", "Upgrade") 251| 105k| ->writeHeader("Sec-WebSocket-Accept", secWebSocketAccept); 252| | 253| | /* Select first subprotocol if present */ 254| 105k| if (secWebSocketProtocol.length()) { ------------------ | Branch (254:13): [True: 578, False: 104k] ------------------ 255| 578| writeHeader("Sec-WebSocket-Protocol", secWebSocketProtocol.substr(0, secWebSocketProtocol.find(','))); 256| 578| } 257| | 258| | /* Negotiate compression */ 259| 105k| bool perMessageDeflate = false; 260| 105k| CompressOptions compressOptions = CompressOptions::DISABLED; 261| 105k| if (secWebSocketExtensions.length() && webSocketContextData->compression != DISABLED) { ------------------ | Branch (261:13): [True: 195, False: 105k] | Branch (261:48): [True: 0, False: 195] ------------------ 262| | 263| | /* Make sure to map SHARED_DECOMPRESSOR to windowBits = 0, not 1 */ 264| 0| int wantedInflationWindow = 0; 265| 0| if ((webSocketContextData->compression & CompressOptions::_DECOMPRESSOR_MASK) != CompressOptions::SHARED_DECOMPRESSOR) { ------------------ | Branch (265:17): [True: 0, False: 0] ------------------ 266| 0| wantedInflationWindow = (webSocketContextData->compression & CompressOptions::_DECOMPRESSOR_MASK) >> 8; 267| 0| } 268| | 269| | /* Map from selected compressor (this automatically maps SHARED_COMPRESSOR to windowBits 0, not 1) */ 270| 0| int wantedCompressionWindow = (webSocketContextData->compression & CompressOptions::_COMPRESSOR_MASK) >> 4; 271| | 272| 0| auto [negCompression, negCompressionWindow, negInflationWindow, negResponse] = 273| 0| negotiateCompression(true, wantedCompressionWindow, wantedInflationWindow, 274| 0| secWebSocketExtensions); 275| | 276| 0| if (negCompression) { ------------------ | Branch (276:17): [True: 0, False: 0] ------------------ 277| 0| perMessageDeflate = true; 278| | 279| | /* Map from negotiated windowBits to compressor and decompressor */ 280| 0| if (negCompressionWindow == 0) { ------------------ | Branch (280:21): [True: 0, False: 0] ------------------ 281| 0| compressOptions = CompressOptions::SHARED_COMPRESSOR; 282| 0| } else { 283| 0| compressOptions = (CompressOptions) ((uint32_t) (negCompressionWindow << 4) 284| 0| | (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| 0| if (webSocketContextData->compression & DEDICATED_COMPRESSOR_3KB) { ------------------ | Branch (288:25): [True: 0, False: 0] ------------------ 289| 0| compressOptions = DEDICATED_COMPRESSOR_3KB; 290| 0| } 291| 0| } 292| | 293| | /* Here we modify the above compression with negotiated decompressor */ 294| 0| if (negInflationWindow == 0) { ------------------ | Branch (294:21): [True: 0, False: 0] ------------------ 295| 0| compressOptions = CompressOptions(compressOptions | CompressOptions::SHARED_DECOMPRESSOR); 296| 0| } else { 297| 0| compressOptions = CompressOptions(compressOptions | (negInflationWindow << 8)); 298| 0| } 299| | 300| 0| writeHeader("Sec-WebSocket-Extensions", negResponse); 301| 0| } 302| 0| } 303| | 304| 105k| internalEnd({nullptr, 0}, 0, false, false); 305| | 306| | /* Grab the httpContext from res */ 307| 105k| HttpContext *httpContext = (HttpContext *) us_socket_context(SSL, (struct us_socket_t *) this); 308| | 309| | /* Move any backpressure out of HttpResponse */ 310| 105k| BackPressure backpressure(std::move(((AsyncSocketData *) getHttpResponseData())->buffer)); 311| | 312| | /* Destroy HttpResponseData */ 313| 105k| getHttpResponseData()->~HttpResponseData(); 314| | 315| | /* Before we adopt and potentially change socket, check if we are corked */ 316| 105k| bool wasCorked = Super::isCorked(); 317| | 318| | /* Adopting a socket invalidates it, do not rely on it directly to carry any data */ 319| 105k| WebSocket *webSocket = (WebSocket *) us_socket_context_adopt_socket(SSL, 320| 105k| (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| 105k| if (wasCorked) { ------------------ | Branch (323:13): [True: 105k, False: 0] ------------------ 324| 105k| webSocket->AsyncSocket::corkUnchecked(); 325| 105k| } 326| | 327| | /* Initialize websocket with any moved backpressure intact */ 328| 105k| 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| 105k| HttpContextData *httpContextData = httpContext->getSocketContextData(); 332| 105k| if (httpContextData->isParsingHttp) { ------------------ | Branch (332:13): [True: 105k, False: 0] ------------------ 333| | /* We need to tell the Http parser that we changed socket */ 334| 105k| httpContextData->upgradedWebSocket = webSocket; 335| 105k| } 336| | 337| | /* Arm maxLifetime timeout */ 338| 105k| us_socket_long_timeout(SSL, (us_socket_t *) webSocket, webSocketContextData->maxLifetime); 339| | 340| | /* Arm idleTimeout */ 341| 105k| us_socket_timeout(SSL, (us_socket_t *) webSocket, webSocketContextData->idleTimeoutComponents.first); 342| | 343| | /* Move construct the UserData right before calling open handler */ 344| 105k| new (webSocket->getUserData()) UserData(std::move(userData)); 345| | 346| | /* Emit open event and start the timeout */ 347| 105k| if (webSocketContextData->openHandler) { ------------------ | Branch (347:13): [True: 105k, False: 0] ------------------ 348| 105k| webSocketContextData->openHandler(webSocket); 349| 105k| } 350| 105k| } _ZN3uWS16HttpResponseDataILb1EE8markDoneEv: 37| 124k| void markDone() { 38| 124k| onAborted = nullptr; 39| | /* Also remove onWritable so that we do not emit when draining behind the scenes. */ 40| 124k| onWritable = nullptr; 41| | 42| | /* We are done with this request */ 43| 124k| state &= ~HttpResponseData::HTTP_RESPONSE_PENDING; 44| 124k| } _ZN3uWS10HttpRouterINS_15HttpContextDataILb1EE10RouterDataEEC2Ev: 243| 5.39k| HttpRouter() { 244| | /* Always have ANY route */ 245| 5.39k| getNode(&root, std::string(ANY_METHOD_TOKEN.data(), ANY_METHOD_TOKEN.length()), false); 246| 5.39k| } _ZN3uWS10HttpRouterINS_15HttpContextDataILb1EE10RouterDataEE4NodeC2ENSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEE: 63| 26.9k| Node(std::string name) : name(name) {} _ZN3uWS10HttpRouterINS_15HttpContextDataILb1EE10RouterDataEE7getNodeEPNS4_4NodeENSt3__112basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEb: 81| 26.9k| Node *getNode(Node *parent, std::string child, bool isHighPriority) { 82| 26.9k| for (std::unique_ptr &node : parent->children) { ------------------ | Branch (82:42): [True: 10.7k, False: 21.5k] ------------------ 83| 10.7k| if (node->name == child && node->isHighPriority == isHighPriority) { ------------------ | Branch (83:17): [True: 5.39k, False: 5.39k] | Branch (83:40): [True: 5.39k, False: 0] ------------------ 84| 5.39k| return node.get(); 85| 5.39k| } 86| 10.7k| } 87| | 88| | /* Insert sorted, but keep order if parent is root (we sort methods by priority elsewhere) */ 89| 21.5k| std::unique_ptr newNode(new Node(child)); 90| 21.5k| newNode->isHighPriority = isHighPriority; 91| 21.5k| return parent->children.emplace(std::upper_bound(parent->children.begin(), parent->children.end(), newNode, [parent, this](auto &a, auto &b) { 92| | 93| 21.5k| if (a->isHighPriority != b->isHighPriority) { 94| 21.5k| return a->isHighPriority; 95| 21.5k| } 96| | 97| 21.5k| return b->name.length() && (parent != &root) && (lexicalOrder(b->name) < lexicalOrder(a->name)); 98| 21.5k| }), std::move(newNode))->get(); 99| 26.9k| } _ZZN3uWS10HttpRouterINS_15HttpContextDataILb1EE10RouterDataEE7getNodeEPNS4_4NodeENSt3__112basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEEbENKUlRT_RT0_E_clIKNS7_10unique_ptrIS5_NS7_14default_deleteIS5_EEEESN_EEDaSF_SH_: 91| 5.39k| return parent->children.emplace(std::upper_bound(parent->children.begin(), parent->children.end(), newNode, [parent, this](auto &a, auto &b) { 92| | 93| 5.39k| if (a->isHighPriority != b->isHighPriority) { ------------------ | Branch (93:17): [True: 0, False: 5.39k] ------------------ 94| 0| return a->isHighPriority; 95| 0| } 96| | 97| 5.39k| return b->name.length() && (parent != &root) && (lexicalOrder(b->name) < lexicalOrder(a->name)); ------------------ | Branch (97:20): [True: 5.39k, False: 0] | Branch (97:40): [True: 0, False: 5.39k] | Branch (97:61): [True: 0, False: 0] ------------------ 98| 5.39k| }), std::move(newNode))->get(); _ZN3uWS10HttpRouterINS_15HttpContextDataILb1EE10RouterDataEE11getUserDataEv: 252| 254k| USERDATA &getUserData() { 253| 254k| return userData; 254| 254k| } _ZN3uWS10HttpRouterINS_15HttpContextDataILb1EE10RouterDataEE5routeENSt3__117basic_string_viewIcNS5_11char_traitsIcEEEES9_: 257| 124k| bool route(std::string_view method, std::string_view url) { 258| | /* Reset url parsing cache */ 259| 124k| setUrl(url); 260| 124k| routeParameters.reset(); 261| | 262| | /* Begin by finding the method node */ 263| 140k| for (auto &p : root.children) { ------------------ | Branch (263:22): [True: 140k, False: 15.0k] ------------------ 264| 140k| if (p->name == method) { ------------------ | Branch (264:17): [True: 109k, False: 30.2k] ------------------ 265| | /* Then route the url */ 266| 109k| if (executeHandlers(p.get(), 0, userData)) { ------------------ | Branch (266:21): [True: 105k, False: 4.40k] ------------------ 267| 105k| return true; 268| 105k| } else { 269| 4.40k| break; 270| 4.40k| } 271| 109k| } 272| 140k| } 273| | 274| | /* Always test any route last */ 275| 19.4k| return executeHandlers(root.children.back().get(), 0, userData); 276| 124k| } _ZN3uWS10HttpRouterINS_15HttpContextDataILb1EE10RouterDataEE6setUrlENSt3__117basic_string_viewIcNS5_11char_traitsIcEEEE: 124| 141k| 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| 141k| currentUrl = url; 130| 141k| urlSegmentTop = -1; 131| 141k| } _ZN3uWS10HttpRouterINS_15HttpContextDataILb1EE10RouterDataEE15RouteParameters5resetEv: 108| 124k| void reset() { 109| 124k| paramsTop = -1; 110| 124k| } _ZN3uWS10HttpRouterINS_15HttpContextDataILb1EE10RouterDataEE15executeHandlersEPNS4_4NodeEiRS3_: 168| 129k| bool executeHandlers(Node *parent, int urlSegment, USERDATA &userData) { 169| | 170| 129k| auto [segment, isStop] = getUrlSegment(urlSegment); 171| | 172| | /* If we are on STOP, return where we may stand */ 173| 129k| if (isStop) { ------------------ | Branch (173:13): [True: 0, False: 129k] ------------------ 174| | /* We have reached accross the entire URL with no stoppage, execute */ 175| 0| for (uint32_t handler : parent->handlers) { ------------------ | Branch (175:35): [True: 0, False: 0] ------------------ 176| 0| if (handlers[handler & HANDLER_MASK](this)) { ------------------ | Branch (176:21): [True: 0, False: 0] ------------------ 177| 0| return true; 178| 0| } 179| 0| } 180| | /* We reached the end, so go back */ 181| 0| return false; 182| 0| } 183| | 184| 129k| for (auto &p : parent->children) { ------------------ | Branch (184:22): [True: 129k, False: 4.40k] ------------------ 185| 129k| if (p->name.length() && p->name[0] == '*') { ------------------ | Branch (185:17): [True: 129k, False: 0] | Branch (185:37): [True: 129k, False: 0] ------------------ 186| | /* Wildcard match (can be seen as a shortcut) */ 187| 129k| for (uint32_t handler : p->handlers) { ------------------ | Branch (187:39): [True: 129k, False: 4.40k] ------------------ 188| 129k| if (handlers[handler & HANDLER_MASK](this)) { ------------------ | Branch (188:25): [True: 124k, False: 4.40k] ------------------ 189| 124k| return true; 190| 124k| } 191| 129k| } 192| 129k| } else if (p->name.length() && p->name[0] == ':' && segment.length()) { ------------------ | Branch (192:24): [True: 0, False: 0] | Branch (192:44): [True: 0, False: 0] | 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| 0| } else if (p->name == segment) { ------------------ | Branch (199:24): [True: 0, False: 0] ------------------ 200| | /* Static match */ 201| 0| if (executeHandlers(p.get(), urlSegment + 1, userData)) { ------------------ | Branch (201:21): [True: 0, False: 0] ------------------ 202| 0| return true; 203| 0| } 204| 0| } 205| 129k| } 206| 4.40k| return false; 207| 129k| } _ZN3uWS10HttpRouterINS_15HttpContextDataILb1EE10RouterDataEE13getUrlSegmentEi: 134| 172k| inline std::pair getUrlSegment(int urlSegment) { 135| 172k| if (urlSegment > urlSegmentTop) { ------------------ | Branch (135:13): [True: 151k, False: 20.5k] ------------------ 136| | /* Signal as STOP when we have no more URL or stack space */ 137| 151k| if (!currentUrl.length() || urlSegment > int(MAX_URL_SEGMENTS - 1)) { ------------------ | Branch (137:17): [True: 10.7k, False: 141k] | Branch (137:41): [True: 0, False: 141k] ------------------ 138| 10.7k| return {{}, true}; 139| 10.7k| } 140| | 141| | /* We always stand on a slash here, so step over it */ 142| 141k| currentUrl.remove_prefix(1); 143| | 144| 141k| auto segmentLength = currentUrl.find('/'); 145| 141k| if (segmentLength == std::string::npos) { ------------------ | Branch (145:17): [True: 140k, False: 805] ------------------ 146| 140k| segmentLength = currentUrl.length(); 147| | 148| | /* Push to url segment vector */ 149| 140k| urlSegmentVector[urlSegment] = currentUrl.substr(0, segmentLength); 150| 140k| urlSegmentTop++; 151| | 152| | /* Update currentUrl */ 153| 140k| currentUrl = currentUrl.substr(segmentLength); 154| 140k| } else { 155| | /* Push to url segment vector */ 156| 805| urlSegmentVector[urlSegment] = currentUrl.substr(0, segmentLength); 157| 805| urlSegmentTop++; 158| | 159| | /* Update currentUrl */ 160| 805| currentUrl = currentUrl.substr(segmentLength); 161| 805| } 162| 141k| } 163| | /* In any case we return it */ 164| 161k| return {urlSegmentVector[urlSegment], false}; 165| 172k| } _ZN3uWS10HttpRouterINS_15HttpContextDataILb1EE10RouterDataEE6removeENSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEESB_j: 360| 10.7k| void remove(std::string method, std::string pattern, uint32_t priority) { 361| 10.7k| uint32_t handler = findHandler(method, pattern, priority); 362| 10.7k| if (handler == UINT32_MAX) { ------------------ | Branch (362:13): [True: 10.7k, False: 0] ------------------ 363| | /* Not found or already removed, do nothing */ 364| 10.7k| return; 365| 10.7k| } 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_15HttpContextDataILb1EE10RouterDataEE11findHandlerENSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEESB_j: 210| 10.7k| uint32_t findHandler(std::string method, std::string pattern, uint32_t priority) { 211| 10.7k| for (std::unique_ptr &node : root.children) { ------------------ | Branch (211:42): [True: 10.7k, False: 5.39k] ------------------ 212| 10.7k| if (method == node->name) { ------------------ | Branch (212:17): [True: 5.39k, False: 5.39k] ------------------ 213| 5.39k| setUrl(pattern); 214| 5.39k| Node *n = node.get(); 215| 5.39k| for (int i = 0; !getUrlSegment(i).second; i++) { ------------------ | Branch (215:33): [True: 5.39k, False: 0] ------------------ 216| | /* Go to next segment or quit */ 217| 5.39k| std::string segment = std::string(getUrlSegment(i).first); 218| 5.39k| Node *next = nullptr; 219| 5.39k| for (std::unique_ptr &child : n->children) { ------------------ | Branch (219:55): [True: 0, False: 5.39k] ------------------ 220| 0| if (child->name == segment && child->isHighPriority == (priority == HIGH_PRIORITY)) { ------------------ | Branch (220:29): [True: 0, False: 0] | Branch (220:55): [True: 0, False: 0] ------------------ 221| 0| next = child.get(); 222| 0| break; 223| 0| } 224| 0| } 225| 5.39k| if (!next) { ------------------ | Branch (225:25): [True: 5.39k, False: 0] ------------------ 226| 5.39k| return UINT32_MAX; 227| 5.39k| } 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| 10.7k| } 239| 5.39k| return UINT32_MAX; 240| 10.7k| } _ZN3uWS10HttpRouterINS_15HttpContextDataILb1EE10RouterDataEE3addENSt3__16vectorINS5_12basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEENSA_ISC_EEEESC_ON5ofats13any_invocableIFbPS4_EEEj: 279| 10.7k| void add(std::vector methods, std::string pattern, MoveOnlyFunction &&handler, uint32_t priority = MEDIUM_PRIORITY) { 280| | /* First remove existing handler */ 281| 10.7k| remove(methods[0], pattern, priority); 282| | 283| 10.7k| for (std::string method : methods) { ------------------ | Branch (283:33): [True: 10.7k, False: 10.7k] ------------------ 284| | /* Lookup method */ 285| 10.7k| Node *node = getNode(&root, method, false); 286| | /* Iterate over all segments */ 287| 10.7k| setUrl(pattern); 288| 21.5k| for (int i = 0; !getUrlSegment(i).second; i++) { ------------------ | Branch (288:29): [True: 10.7k, False: 10.7k] ------------------ 289| 10.7k| std::string strippedSegment(getUrlSegment(i).first); 290| 10.7k| if (strippedSegment.length() && strippedSegment[0] == ':') { ------------------ | Branch (290:21): [True: 10.7k, False: 0] | Branch (290:49): [True: 0, False: 10.7k] ------------------ 291| | /* Parameter routes must be named only : */ 292| 0| strippedSegment = ":"; 293| 0| } 294| 10.7k| node = getNode(node, strippedSegment, priority == HIGH_PRIORITY); 295| 10.7k| } 296| | /* Insert handler in order sorted by priority (most significant 1 byte) */ 297| 10.7k| node->handlers.insert(std::upper_bound(node->handlers.begin(), node->handlers.end(), (uint32_t) (priority | handlers.size())), (uint32_t) (priority | handlers.size())); 298| 10.7k| } 299| | 300| | /* Alloate this handler */ 301| 10.7k| handlers.emplace_back(std::move(handler)); 302| | 303| | /* ANY method must be last, GET must be first */ 304| 10.7k| 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| 10.7k| if (a->name == "GET") { 307| 10.7k| return true; 308| 10.7k| } else if (b->name == "GET") { 309| 10.7k| return false; 310| 10.7k| } else if (a->name == ANY_METHOD_TOKEN) { 311| 10.7k| return false; 312| 10.7k| } else if (b->name == ANY_METHOD_TOKEN) { 313| 10.7k| return true; 314| 10.7k| } else { 315| 10.7k| return a->name < b->name; 316| 10.7k| } 317| 10.7k| }); 318| 10.7k| } _ZZN3uWS10HttpRouterINS_15HttpContextDataILb1EE10RouterDataEE3addENSt3__16vectorINS5_12basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEENSA_ISC_EEEESC_ON5ofats13any_invocableIFbPS4_EEEjENKUlRKT_RKT0_E_clINS5_10unique_ptrINS4_4NodeENS5_14default_deleteISU_EEEESX_EEDaSN_SQ_: 304| 5.39k| 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| 5.39k| if (a->name == "GET") { ------------------ | Branch (306:17): [True: 5.39k, False: 0] ------------------ 307| 5.39k| return true; 308| 5.39k| } else if (b->name == "GET") { ------------------ | Branch (308:24): [True: 0, False: 0] ------------------ 309| 0| return false; 310| 0| } 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| 5.39k| }); _ZN3uWS10HttpRouterINS_15HttpContextDataILb1EE10RouterDataEE13getParametersEv: 248| 129k| std::pair getParameters() { 249| 129k| return {routeParameters.paramsTop, routeParameters.params}; 250| 129k| } _ZN3uWS4Loop3getEPv: 111| 43.1k| static Loop *get(void *existingNativeLoop = nullptr) { 112| 43.1k| if (!getLazyLoop().loop) { ------------------ | Branch (112:13): [True: 5.39k, False: 37.7k] ------------------ 113| | /* If we are given a native loop pointer we pass that to uSockets and let it deal with it */ 114| 5.39k| if (existingNativeLoop) { ------------------ | Branch (114:17): [True: 0, False: 5.39k] ------------------ 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.39k| } else { 119| 5.39k| getLazyLoop().loop = create(nullptr); 120| 5.39k| getLazyLoop().cleanMe = true; 121| 5.39k| } 122| 5.39k| } 123| | 124| 43.1k| return getLazyLoop().loop; 125| 43.1k| } _ZN3uWS4Loop11getLazyLoopEv: 103| 102k| static LoopCleaner &getLazyLoop() { 104| 102k| static thread_local LoopCleaner lazyLoop; 105| 102k| return lazyLoop; 106| 102k| } _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.39k| static Loop *create(void *hint) { 77| 5.39k| 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.39k| LoopData *loopData = (LoopData *) us_loop_ext((struct us_loop_t *) loop); 81| 5.39k| loopData->dateTimer = us_create_timer((struct us_loop_t *) loop, 1, sizeof(LoopData *)); 82| 5.39k| memcpy(us_timer_ext(loopData->dateTimer), &loopData, sizeof(LoopData *)); 83| 5.39k| us_timer_set(loopData->dateTimer, [](struct us_timer_t *t) { 84| 5.39k| LoopData *loopData; 85| 5.39k| memcpy(&loopData, us_timer_ext(t), sizeof(LoopData *)); 86| 5.39k| loopData->updateDate(); 87| 5.39k| }, 1000, 1000); 88| | 89| 5.39k| return loop; 90| 5.39k| } _ZN3uWS4Loop8wakeupCbEP9us_loop_t: 30| 1.06M| static void wakeupCb(us_loop_t *loop) { 31| 1.06M| LoopData *loopData = (LoopData *) us_loop_ext(loop); 32| | 33| | /* Swap current deferQueue */ 34| 1.06M| loopData->deferMutex.lock(); 35| 1.06M| int oldDeferQueue = loopData->currentDeferQueue; 36| 1.06M| loopData->currentDeferQueue = (loopData->currentDeferQueue + 1) % 2; 37| 1.06M| loopData->deferMutex.unlock(); 38| | 39| | /* Drain the queue */ 40| 1.06M| for (auto &x : loopData->deferQueues[oldDeferQueue]) { ------------------ | Branch (40:22): [True: 0, False: 1.06M] ------------------ 41| 0| x(); 42| 0| } 43| 1.06M| loopData->deferQueues[oldDeferQueue].clear(); 44| 1.06M| } _ZN3uWS4Loop5preCbEP9us_loop_t: 46| 1.29M| static void preCb(us_loop_t *loop) { 47| 1.29M| LoopData *loopData = (LoopData *) us_loop_ext(loop); 48| | 49| 1.29M| for (auto &p : loopData->preHandlers) { ------------------ | Branch (49:22): [True: 1.29M, False: 1.29M] ------------------ 50| 1.29M| p.second((Loop *) loop); 51| 1.29M| } 52| 1.29M| } _ZN3uWS4Loop6postCbEP9us_loop_t: 54| 1.29M| static void postCb(us_loop_t *loop) { 55| 1.29M| LoopData *loopData = (LoopData *) us_loop_ext(loop); 56| | 57| 1.29M| for (auto &p : loopData->postHandlers) { ------------------ | Branch (57:22): [True: 1.29M, False: 1.29M] ------------------ 58| 1.29M| p.second((Loop *) loop); 59| 1.29M| } 60| | 61| | /* After every event loop iteration, we must not hold the cork buffer */ 62| 1.29M| if (loopData->corkedSocket) { ------------------ | Branch (62:13): [True: 0, False: 1.29M] ------------------ 63| 0| std::cerr << "Error: Cork buffer must not be held across event loop iterations!" << std::endl; 64| 0| std::terminate(); 65| 0| } 66| 1.29M| } _ZN3uWS4Loop4initEv: 71| 5.39k| Loop *init() { 72| 5.39k| new (us_loop_ext((us_loop_t *) this)) LoopData; 73| 5.39k| return this; 74| 5.39k| } _ZZN3uWS4Loop6createEPvENKUlP10us_timer_tE_clES3_: 83| 930k| us_timer_set(loopData->dateTimer, [](struct us_timer_t *t) { 84| 930k| LoopData *loopData; 85| 930k| memcpy(&loopData, us_timer_ext(t), sizeof(LoopData *)); 86| 930k| loopData->updateDate(); 87| 930k| }, 1000, 1000); _ZN3uWS4Loop4freeEv: 128| 5.39k| void free() { 129| 5.39k| LoopData *loopData = (LoopData *) us_loop_ext((us_loop_t *) this); 130| | 131| | /* Stop and free dateTimer first */ 132| 5.39k| us_timer_close(loopData->dateTimer); 133| | 134| 5.39k| loopData->~LoopData(); 135| | /* uSockets will track whether this loop is owned by us or a borrowed alien loop */ 136| 5.39k| us_loop_free((us_loop_t *) this); 137| | 138| | /* Reset lazyLoop */ 139| 5.39k| getLazyLoop().loop = nullptr; 140| 5.39k| } _ZN3uWS4Loop14addPostHandlerEPvON5ofats13any_invocableIFvPS0_EEE: 142| 5.39k| void addPostHandler(void *key, MoveOnlyFunction &&handler) { 143| 5.39k| LoopData *loopData = (LoopData *) us_loop_ext((us_loop_t *) this); 144| | 145| 5.39k| loopData->postHandlers.emplace(key, std::move(handler)); 146| 5.39k| } _ZN3uWS4Loop13addPreHandlerEPvON5ofats13any_invocableIFvPS0_EEE: 155| 5.39k| void addPreHandler(void *key, MoveOnlyFunction &&handler) { 156| 5.39k| LoopData *loopData = (LoopData *) us_loop_ext((us_loop_t *) this); 157| | 158| 5.39k| loopData->preHandlers.emplace(key, std::move(handler)); 159| 5.39k| } _ZN3uWS3runEv: 198| 5.39k|inline void run() { 199| 5.39k| Loop::get()->run(); 200| 5.39k|} _ZN3uWS4Loop3runEv: 181| 5.39k| void run() { 182| 5.39k| us_loop_run((us_loop_t *) this); 183| 5.39k| } _ZN3uWS4Loop17removePostHandlerEPv: 149| 5.39k| void removePostHandler(void *key) { 150| 5.39k| LoopData *loopData = (LoopData *) us_loop_ext((us_loop_t *) this); 151| | 152| 5.39k| loopData->postHandlers.erase(key); 153| 5.39k| } _ZN3uWS4Loop16removePreHandlerEPv: 162| 5.39k| void removePreHandler(void *key) { 163| 5.39k| LoopData *loopData = (LoopData *) us_loop_ext((us_loop_t *) this); 164| | 165| 5.39k| loopData->preHandlers.erase(key); 166| 5.39k| } _ZN3uWS8LoopDataC2Ev: 49| 5.39k| LoopData() { 50| 5.39k| updateDate(); 51| 5.39k| } _ZN3uWS8LoopData10updateDateEv: 63| 935k| void updateDate() { 64| 935k| time_t now = time(0); 65| 935k| struct tm tstruct = {}; 66| |#ifdef _WIN32 67| | /* Micro, fucking soft never follows spec. */ 68| | gmtime_s(&tstruct, &now); 69| |#else 70| 935k| gmtime_r(&now, &tstruct); 71| 935k|#endif 72| 935k| static const char wday_name[][4] = { 73| 935k| "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 74| 935k| }; 75| 935k| static const char mon_name[][4] = { 76| 935k| "Jan", "Feb", "Mar", "Apr", "May", "Jun", 77| 935k| "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 78| 935k| }; 79| 935k| snprintf(date, 32, "%.3s, %.2u %.3s %.4u %.2u:%.2u:%.2u GMT", 80| 935k| wday_name[tstruct.tm_wday], 81| 935k| tstruct.tm_mday % 99, 82| 935k| mon_name[tstruct.tm_mon], 83| 935k| (1900 + tstruct.tm_year) % 9999, 84| 935k| tstruct.tm_hour % 99, 85| 935k| tstruct.tm_min % 99, 86| 935k| tstruct.tm_sec % 99); 87| 935k| } _ZN3uWS8LoopDataD2Ev: 53| 5.39k| ~LoopData() { 54| | /* If we have had App.ws called with compression we need to clear this */ 55| 5.39k| if (zlibContext) { ------------------ | Branch (55:13): [True: 0, False: 5.39k] ------------------ 56| 0| delete zlibContext; 57| 0| delete inflationStream; 58| 0| delete deflationStream; 59| 0| } 60| 5.39k| delete [] corkBuffer; 61| 5.39k| } _ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb1EEEPNS2_11HttpRequestEP19us_socket_context_tEEC2EDn: 187| 5.39k| any_invocable_impl(std::nullptr_t) noexcept {} EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEEC2EDn: 187| 16.1k| any_invocable_impl(std::nullptr_t) noexcept {} EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEiiEEC2EDn: 187| 10.7k| any_invocable_impl(std::nullptr_t) noexcept {} _ZN5ofats10any_detail18any_invocable_implIvLb0EJP18us_listen_socket_tEED2Ev: 206| 5.39k| ~any_invocable_impl() { destroy(); } _ZN5ofats10any_detail18any_invocable_implIvLb0EJP18us_listen_socket_tEE7destroyEv: 239| 5.39k| void destroy() noexcept { 240| 5.39k| if (handle_) { ------------------ | Branch (240:9): [True: 5.39k, False: 0] ------------------ 241| 5.39k| handle_(action::destroy, &storage_, nullptr); 242| 5.39k| handle_ = nullptr; 243| 5.39k| } 244| 5.39k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEED2Ev: 206| 37.7k| ~any_invocable_impl() { destroy(); } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE7destroyEv: 239| 37.7k| void destroy() noexcept { 240| 37.7k| if (handle_) { ------------------ | Branch (240:9): [True: 10.7k, False: 26.9k] ------------------ 241| 10.7k| handle_(action::destroy, &storage_, nullptr); 242| 10.7k| handle_ = nullptr; 243| 10.7k| } 244| 37.7k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEiiEED2Ev: 206| 26.9k| ~any_invocable_impl() { destroy(); } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEiiEE7destroyEv: 239| 26.9k| void destroy() noexcept { 240| 26.9k| if (handle_) { ------------------ | Branch (240:9): [True: 0, False: 26.9k] ------------------ 241| 0| handle_(action::destroy, &storage_, nullptr); 242| 0| handle_ = nullptr; 243| 0| } 244| 26.9k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEED2Ev: 206| 53.9k| ~any_invocable_impl() { destroy(); } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE7destroyEv: 239| 53.9k| void destroy() noexcept { 240| 53.9k| if (handle_) { ------------------ | Branch (240:9): [True: 10.7k, False: 43.1k] ------------------ 241| 10.7k| handle_(action::destroy, &storage_, nullptr); 242| 10.7k| handle_ = nullptr; 243| 10.7k| } 244| 53.9k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEEED2Ev: 206| 53.9k| ~any_invocable_impl() { destroy(); } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEEE7destroyEv: 239| 53.9k| void destroy() noexcept { 240| 53.9k| if (handle_) { ------------------ | Branch (240:9): [True: 10.7k, False: 43.1k] ------------------ 241| 10.7k| handle_(action::destroy, &storage_, nullptr); 242| 10.7k| handle_ = nullptr; 243| 10.7k| } 244| 53.9k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEED2Ev: 206| 53.9k| ~any_invocable_impl() { destroy(); } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEE7destroyEv: 239| 53.9k| void destroy() noexcept { 240| 53.9k| if (handle_) { ------------------ | Branch (240:9): [True: 5.39k, False: 48.5k] ------------------ 241| 5.39k| handle_(action::destroy, &storage_, nullptr); 242| 5.39k| handle_ = nullptr; 243| 5.39k| } 244| 53.9k| } _ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb1EEEPNS2_11HttpRequestEP19us_socket_context_tEED2Ev: 206| 16.1k| ~any_invocable_impl() { destroy(); } _ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb1EEEPNS2_11HttpRequestEP19us_socket_context_tEE7destroyEv: 239| 16.1k| void destroy() noexcept { 240| 16.1k| if (handle_) { ------------------ | Branch (240:9): [True: 0, False: 16.1k] ------------------ 241| 0| handle_(action::destroy, &storage_, nullptr); 242| 0| handle_ = nullptr; 243| 0| } 244| 16.1k| } _ZN5ofats13any_invocableIFvvEEclEv: 345| 5.39k| R operator()(ArgTypes... args) cv ref noexcept(noex) { \ 346| 5.39k| return base_type::call(std::forward(args)...); \ 347| 5.39k| } \ _ZN5ofats10any_detail18any_invocable_implIvLb0EJEE4callEv: 246| 5.39k| R call(ArgTypes... args) noexcept(is_noexcept) { 247| 5.39k| return call_(storage_, std::forward(args)...); 248| 5.39k| } _ZN5ofats10any_detail18any_invocable_implIvLb0EJEED2Ev: 206| 1.35M| ~any_invocable_impl() { destroy(); } _ZN5ofats10any_detail18any_invocable_implIvLb0EJEE7destroyEv: 239| 1.35M| void destroy() noexcept { 240| 1.35M| if (handle_) { ------------------ | Branch (240:9): [True: 5.39k, False: 1.35M] ------------------ 241| 5.39k| handle_(action::destroy, &storage_, nullptr); 242| 5.39k| handle_ = nullptr; 243| 5.39k| } 244| 1.35M| } _ZN5ofats13any_invocableIFvPN3uWS4LoopEEEclES3_: 345| 2.59M| R operator()(ArgTypes... args) cv ref noexcept(noex) { \ 346| 2.59M| return base_type::call(std::forward(args)...); \ 347| 2.59M| } \ _ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS4LoopEEE4callES4_: 246| 2.59M| R call(ArgTypes... args) noexcept(is_noexcept) { 247| 2.59M| return call_(storage_, std::forward(args)...); 248| 2.59M| } _ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS4LoopEEED2Ev: 206| 21.5k| ~any_invocable_impl() { destroy(); } _ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS4LoopEEE7destroyEv: 239| 21.5k| void destroy() noexcept { 240| 21.5k| if (handle_) { ------------------ | Branch (240:9): [True: 10.7k, False: 10.7k] ------------------ 241| 10.7k| handle_(action::destroy, &storage_, nullptr); 242| 10.7k| handle_ = nullptr; 243| 10.7k| } 244| 21.5k| } _ZN5ofats10any_detail18any_invocable_implIvLb0EJPKcEEC2Ev: 186| 5.39k| any_invocable_impl() noexcept = default; _ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterINS2_15HttpContextDataILb1EE10RouterDataEEEEED2Ev: 206| 26.9k| ~any_invocable_impl() { destroy(); } _ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterINS2_15HttpContextDataILb1EE10RouterDataEEEEE7destroyEv: 239| 26.9k| void destroy() noexcept { 240| 26.9k| if (handle_) { ------------------ | Branch (240:9): [True: 10.7k, False: 16.1k] ------------------ 241| 10.7k| handle_(action::destroy, &storage_, nullptr); 242| 10.7k| handle_ = nullptr; 243| 10.7k| } 244| 26.9k| } _ZN5ofats10any_detail18any_invocable_implIvLb0EJPKcEED2Ev: 206| 5.39k| ~any_invocable_impl() { destroy(); } _ZN5ofats10any_detail18any_invocable_implIvLb0EJPKcEE7destroyEv: 239| 5.39k| void destroy() noexcept { 240| 5.39k| if (handle_) { ------------------ | Branch (240:9): [True: 0, False: 5.39k] ------------------ 241| 0| handle_(action::destroy, &storage_, nullptr); 242| 0| handle_ = nullptr; 243| 0| } 244| 5.39k| } _ZN5ofats10any_detail18any_invocable_implIbLb0EJmEEC2Ev: 186| 1.22M| any_invocable_impl() noexcept = default; _ZN5ofats10any_detail18any_invocable_implIvLb0EJEEC2Ev: 186| 1.22M| any_invocable_impl() noexcept = default; _ZN5ofats10any_detail18any_invocable_implIvLb0EJNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEbEEC2Ev: 186| 1.22M| any_invocable_impl() noexcept = default; _ZNK5ofats10any_detail18any_invocable_implIvLb0EJEEcvbEv: 228| 1.11M| explicit operator bool() const noexcept { return handle_ != nullptr; } _ZN5ofats10any_detail18any_invocable_implIvLb0EJNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEbEED2Ev: 206| 1.22M| ~any_invocable_impl() { destroy(); } _ZN5ofats10any_detail18any_invocable_implIvLb0EJNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEbEE7destroyEv: 239| 1.22M| void destroy() noexcept { 240| 1.22M| if (handle_) { ------------------ | Branch (240:9): [True: 0, False: 1.22M] ------------------ 241| 0| handle_(action::destroy, &storage_, nullptr); 242| 0| handle_ = nullptr; 243| 0| } 244| 1.22M| } _ZN5ofats10any_detail18any_invocable_implIbLb0EJmEED2Ev: 206| 1.34M| ~any_invocable_impl() { destroy(); } _ZN5ofats10any_detail18any_invocable_implIbLb0EJmEE7destroyEv: 239| 1.34M| void destroy() noexcept { 240| 1.34M| if (handle_) { ------------------ | Branch (240:9): [True: 0, False: 1.34M] ------------------ 241| 0| handle_(action::destroy, &storage_, nullptr); 242| 0| handle_ = nullptr; 243| 0| } 244| 1.34M| } _ZN5ofats13any_invocableIFPvS1_NSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEbEEclES1_S6_b: 345| 18.8k| R operator()(ArgTypes... args) cv ref noexcept(noex) { \ 346| 18.8k| return base_type::call(std::forward(args)...); \ 347| 18.8k| } \ _ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE4callES2_S7_b: 246| 18.8k| R call(ArgTypes... args) noexcept(is_noexcept) { 247| 18.8k| return call_(storage_, std::forward(args)...); 248| 18.8k| } _ZN5ofats13any_invocableIFPvS1_PN3uWS11HttpRequestEEEclES1_S4_: 345| 124k| R operator()(ArgTypes... args) cv ref noexcept(noex) { \ 346| 124k| return base_type::call(std::forward(args)...); \ 347| 124k| } \ _ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_PN3uWS11HttpRequestEEE4callES2_S5_: 246| 124k| R call(ArgTypes... args) noexcept(is_noexcept) { 247| 124k| return call_(storage_, std::forward(args)...); 248| 124k| } _ZN5ofats13any_invocableIFPvS1_PN3uWS11HttpRequestEEEC2IZZNS2_11HttpContextILb1EE4initEvENKUlP11us_socket_tPciE_clESB_SC_iEUlS1_S4_E_vEEOT_: 303| 660k| any_invocable(F&& f) { \ 304| 660k| base_type::template create>(std::forward(f)); \ 305| 660k| } \ _ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_PN3uWS11HttpRequestEEEC2Ev: 186| 660k| any_invocable_impl() noexcept = default; _ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_PN3uWS11HttpRequestEEE6createIZZNS3_11HttpContextILb1EE4initEvENKUlP11us_socket_tPciE_clESB_SC_iEUlS2_S5_E_JSE_EEEvDpOT0_: 232| 660k| void create(Args&&... args) { 233| 660k| using hdl = handler; 234| 660k| hdl::create(storage_, std::forward(args)...); 235| 660k| handle_ = &hdl::handle; 236| 660k| call_ = &hdl::call; 237| 660k| } _ZN5ofats10any_detail14handler_traitsIPvJS2_PN3uWS11HttpRequestEEE13small_handlerIZZNS3_11HttpContextILb1EE4initEvENKUlP11us_socket_tPciE_clESB_SC_iEUlS2_S5_E_E6createIJSE_EEEvRNS0_7storageEDpOT_: 118| 660k| static void create(storage& s, Args&&... args) { 119| 660k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 660k| } _ZN5ofats10any_detail14handler_traitsIPvJS2_PN3uWS11HttpRequestEEE12handler_baseINS6_13small_handlerIZZNS3_11HttpContextILb1EE4initEvENKUlP11us_socket_tPciE_clESC_SD_iEUlS2_S5_E_EEE6handleENS0_6actionEPNS0_7storageESK_: 103| 660k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 660k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 660k] ------------------ 105| 660k| case (action::destroy): ------------------ | Branch (105:9): [True: 660k, False: 0] ------------------ 106| 660k| Derived::destroy(*current); 107| 660k| break; 108| 0| case (action::move): ------------------ | Branch (108:9): [True: 0, False: 660k] ------------------ 109| 0| Derived::move(*current, *other); 110| 0| break; 111| 660k| } 112| 660k| } _ZN5ofats10any_detail14handler_traitsIPvJS2_PN3uWS11HttpRequestEEE13small_handlerIZZNS3_11HttpContextILb1EE4initEvENKUlP11us_socket_tPciE_clESB_SC_iEUlS2_S5_E_E7destroyERNS0_7storageE: 122| 660k| static void destroy(storage& s) noexcept { 123| 660k| T& value = *static_cast(static_cast(&s.buf_)); 124| 660k| value.~T(); 125| 660k| } _ZN5ofats10any_detail14handler_traitsIPvJS2_PN3uWS11HttpRequestEEE13small_handlerIZZNS3_11HttpContextILb1EE4initEvENKUlP11us_socket_tPciE_clESB_SC_iEUlS2_S5_E_E4callERNS0_7storageES2_S5_: 132| 124k| static R call(storage& s, ArgTypes... args) { 133| 124k| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 124k| std::forward(args)...); 135| 124k| } _ZN5ofats13any_invocableIFbPN3uWS10HttpRouterINS1_15HttpContextDataILb1EE10RouterDataEEEEEclES7_: 345| 129k| R operator()(ArgTypes... args) cv ref noexcept(noex) { \ 346| 129k| return base_type::call(std::forward(args)...); \ 347| 129k| } \ _ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterINS2_15HttpContextDataILb1EE10RouterDataEEEEE4callES8_: 246| 129k| R call(ArgTypes... args) noexcept(is_noexcept) { 247| 129k| return call_(storage_, std::forward(args)...); 248| 129k| } _ZNK5ofats10any_detail18any_invocable_implIvLb0EJNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEbEEcvbEv: 228| 18.8k| explicit operator bool() const noexcept { return handle_ != nullptr; } _ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_PN3uWS11HttpRequestEEED2Ev: 206| 660k| ~any_invocable_impl() { destroy(); } _ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_PN3uWS11HttpRequestEEE7destroyEv: 239| 660k| void destroy() noexcept { 240| 660k| if (handle_) { ------------------ | Branch (240:9): [True: 660k, False: 0] ------------------ 241| 660k| handle_(action::destroy, &storage_, nullptr); 242| 660k| handle_ = nullptr; 243| 660k| } 244| 660k| } _ZN5ofats13any_invocableIFPvS1_NSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEbEEC2IZZN3uWS11HttpContextILb1EE4initEvENKUlP11us_socket_tPciE_clESE_SF_iEUlS1_S6_bE_vEEOT_: 303| 660k| any_invocable(F&& f) { \ 304| 660k| base_type::template create>(std::forward(f)); \ 305| 660k| } \ _ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEEC2Ev: 186| 660k| any_invocable_impl() noexcept = default; _ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE6createIZZN3uWS11HttpContextILb1EE4initEvENKUlP11us_socket_tPciE_clESE_SF_iEUlS2_S7_bE_JSH_EEEvDpOT0_: 232| 660k| void create(Args&&... args) { 233| 660k| using hdl = handler; 234| 660k| hdl::create(storage_, std::forward(args)...); 235| 660k| handle_ = &hdl::handle; 236| 660k| call_ = &hdl::call; 237| 660k| } _ZN5ofats10any_detail14handler_traitsIPvJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE13small_handlerIZZN3uWS11HttpContextILb1EE4initEvENKUlP11us_socket_tPciE_clESE_SF_iEUlS2_S7_bE_E6createIJSH_EEEvRNS0_7storageEDpOT_: 118| 660k| static void create(storage& s, Args&&... args) { 119| 660k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 660k| } _ZN5ofats10any_detail14handler_traitsIPvJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE12handler_baseINS8_13small_handlerIZZN3uWS11HttpContextILb1EE4initEvENKUlP11us_socket_tPciE_clESF_SG_iEUlS2_S7_bE_EEE6handleENS0_6actionEPNS0_7storageESN_: 103| 660k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 660k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 660k] ------------------ 105| 660k| case (action::destroy): ------------------ | Branch (105:9): [True: 660k, False: 0] ------------------ 106| 660k| Derived::destroy(*current); 107| 660k| break; 108| 0| case (action::move): ------------------ | Branch (108:9): [True: 0, False: 660k] ------------------ 109| 0| Derived::move(*current, *other); 110| 0| break; 111| 660k| } 112| 660k| } _ZN5ofats10any_detail14handler_traitsIPvJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE13small_handlerIZZN3uWS11HttpContextILb1EE4initEvENKUlP11us_socket_tPciE_clESE_SF_iEUlS2_S7_bE_E7destroyERNS0_7storageE: 122| 660k| static void destroy(storage& s) noexcept { 123| 660k| T& value = *static_cast(static_cast(&s.buf_)); 124| 660k| value.~T(); 125| 660k| } _ZN5ofats10any_detail14handler_traitsIPvJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE13small_handlerIZZN3uWS11HttpContextILb1EE4initEvENKUlP11us_socket_tPciE_clESE_SF_iEUlS2_S7_bE_E4callERNS0_7storageES2_S7_b: 132| 18.8k| static R call(storage& s, ArgTypes... args) { 133| 18.8k| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 18.8k| std::forward(args)...); 135| 18.8k| } _ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEED2Ev: 206| 660k| ~any_invocable_impl() { destroy(); } _ZN5ofats10any_detail18any_invocable_implIPvLb0EJS2_NSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEbEE7destroyEv: 239| 660k| void destroy() noexcept { 240| 660k| if (handle_) { ------------------ | Branch (240:9): [True: 660k, False: 0] ------------------ 241| 660k| handle_(action::destroy, &storage_, nullptr); 242| 660k| handle_ = nullptr; 243| 660k| } 244| 660k| } _ZNK5ofats10any_detail18any_invocable_implIbLb0EJmEEcvbEv: 228| 2.40k| explicit operator bool() const noexcept { return handle_ != nullptr; } _ZN5ofats10any_detail18any_invocable_implIbLb0EJmEE4swapERS2_: 208| 124k| void swap(any_invocable_impl& rhs) noexcept { 209| 124k| if (handle_) { ------------------ | Branch (209:9): [True: 0, False: 124k] ------------------ 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| 124k| } else if (rhs.handle_) { ------------------ | Branch (220:16): [True: 0, False: 124k] ------------------ 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| 124k| } _ZNK5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb1EEEPNS2_11HttpRequestEEEcvbEv: 228| 10.7k| explicit operator bool() const noexcept { return handle_ != nullptr; } _ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterINS2_15HttpContextDataILb1EE10RouterDataEEEEEC2EOS9_: 188| 16.1k| any_invocable_impl(any_invocable_impl&& rhs) noexcept { 189| 16.1k| if (rhs.handle_) { ------------------ | Branch (189:9): [True: 16.1k, False: 0] ------------------ 190| 16.1k| handle_ = rhs.handle_; 191| 16.1k| handle_(action::move, &storage_, &rhs.storage_); 192| 16.1k| call_ = rhs.call_; 193| 16.1k| rhs.handle_ = nullptr; 194| 16.1k| } 195| 16.1k| } _ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb1EEEPNS2_11HttpRequestEEEC2EOS8_: 188| 21.5k| any_invocable_impl(any_invocable_impl&& rhs) noexcept { 189| 21.5k| if (rhs.handle_) { ------------------ | Branch (189:9): [True: 21.5k, False: 0] ------------------ 190| 21.5k| handle_ = rhs.handle_; 191| 21.5k| handle_(action::move, &storage_, &rhs.storage_); 192| 21.5k| call_ = rhs.call_; 193| 21.5k| rhs.handle_ = nullptr; 194| 21.5k| } 195| 21.5k| } _ZN5ofats13any_invocableIFbPN3uWS10HttpRouterINS1_15HttpContextDataILb1EE10RouterDataEEEEEC2IZNS1_11HttpContextILb1EE6onHttpENSt3__112basic_stringIcNSD_11char_traitsIcEENSD_9allocatorIcEEEESJ_ONS0_IFvPNS1_12HttpResponseILb1EEEPNS1_11HttpRequestEEEEbEUlPT_E_vEEOSS_: 303| 10.7k| any_invocable(F&& f) { \ 304| 10.7k| base_type::template create>(std::forward(f)); \ 305| 10.7k| } \ _ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterINS2_15HttpContextDataILb1EE10RouterDataEEEEEC2Ev: 186| 10.7k| any_invocable_impl() noexcept = default; _ZN5ofats10any_detail18any_invocable_implIbLb0EJPN3uWS10HttpRouterINS2_15HttpContextDataILb1EE10RouterDataEEEEE6createIZNS2_11HttpContextILb1EE6onHttpENSt3__112basic_stringIcNSD_11char_traitsIcEENSD_9allocatorIcEEEESJ_ONS_13any_invocableIFvPNS2_12HttpResponseILb1EEEPNS2_11HttpRequestEEEEbEUlPT_E_JSV_EEEvDpOT0_: 232| 10.7k| void create(Args&&... args) { 233| 10.7k| using hdl = handler; 234| 10.7k| hdl::create(storage_, std::forward(args)...); 235| 10.7k| handle_ = &hdl::handle; 236| 10.7k| call_ = &hdl::call; 237| 10.7k| } _ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterINS2_15HttpContextDataILb1EE10RouterDataEEEEE13large_handlerIZNS2_11HttpContextILb1EE6onHttpENSt3__112basic_stringIcNSD_11char_traitsIcEENSD_9allocatorIcEEEESJ_ONS_13any_invocableIFvPNS2_12HttpResponseILb1EEEPNS2_11HttpRequestEEEEbEUlPT_E_E6createIJSV_EEEvRNS0_7storageEDpOT_: 141| 10.7k| static void create(storage& s, Args&&... args) { 142| 10.7k| s.ptr_ = new T(std::forward(args)...); 143| 10.7k| } _ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterINS2_15HttpContextDataILb1EE10RouterDataEEEEE12handler_baseINS9_13large_handlerIZNS2_11HttpContextILb1EE6onHttpENSt3__112basic_stringIcNSE_11char_traitsIcEENSE_9allocatorIcEEEESK_ONS_13any_invocableIFvPNS2_12HttpResponseILb1EEEPNS2_11HttpRequestEEEEbEUlPT_E_EEE6handleENS0_6actionEPNS0_7storageES11_: 103| 26.9k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 26.9k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 26.9k] ------------------ 105| 10.7k| case (action::destroy): ------------------ | Branch (105:9): [True: 10.7k, False: 16.1k] ------------------ 106| 10.7k| Derived::destroy(*current); 107| 10.7k| break; 108| 16.1k| case (action::move): ------------------ | Branch (108:9): [True: 16.1k, False: 10.7k] ------------------ 109| 16.1k| Derived::move(*current, *other); 110| 16.1k| break; 111| 26.9k| } 112| 26.9k| } _ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterINS2_15HttpContextDataILb1EE10RouterDataEEEEE13large_handlerIZNS2_11HttpContextILb1EE6onHttpENSt3__112basic_stringIcNSD_11char_traitsIcEENSD_9allocatorIcEEEESJ_ONS_13any_invocableIFvPNS2_12HttpResponseILb1EEEPNS2_11HttpRequestEEEEbEUlPT_E_E7destroyERNS0_7storageE: 145| 10.7k| static void destroy(storage& s) noexcept { delete static_cast(s.ptr_); } _ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterINS2_15HttpContextDataILb1EE10RouterDataEEEEE13large_handlerIZNS2_11HttpContextILb1EE6onHttpENSt3__112basic_stringIcNSD_11char_traitsIcEENSD_9allocatorIcEEEESJ_ONS_13any_invocableIFvPNS2_12HttpResponseILb1EEEPNS2_11HttpRequestEEEEbEUlPT_E_E4moveERNS0_7storageESY_: 147| 16.1k| static void move(storage& dst, storage& src) noexcept { 148| 16.1k| dst.ptr_ = src.ptr_; 149| 16.1k| } _ZN5ofats10any_detail14handler_traitsIbJPN3uWS10HttpRouterINS2_15HttpContextDataILb1EE10RouterDataEEEEE13large_handlerIZNS2_11HttpContextILb1EE6onHttpENSt3__112basic_stringIcNSD_11char_traitsIcEENSD_9allocatorIcEEEESJ_ONS_13any_invocableIFvPNS2_12HttpResponseILb1EEEPNS2_11HttpRequestEEEEbEUlPT_E_E4callERNS0_7storageES8_: 151| 129k| static R call(storage& s, ArgTypes... args) { 152| 129k| return std::invoke(*static_cast(s.ptr_), 153| 129k| std::forward(args)...); 154| 129k| } _ZN5ofats13any_invocableIFvPN3uWS12HttpResponseILb1EEEPNS1_11HttpRequestEEEclES4_S6_: 345| 129k| R operator()(ArgTypes... args) cv ref noexcept(noex) { \ 346| 129k| return base_type::call(std::forward(args)...); \ 347| 129k| } \ _ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb1EEEPNS2_11HttpRequestEEE4callES5_S7_: 246| 129k| R call(ArgTypes... args) noexcept(is_noexcept) { 247| 129k| return call_(storage_, std::forward(args)...); 248| 129k| } _ZN5ofats13any_invocableIFvPN3uWS12HttpResponseILb1EEEPNS1_11HttpRequestEEEC2IZNS1_12TemplatedAppILb1EEC1ENS1_20SocketContextOptionsEEUlPT_PT0_E_vEEOSD_: 303| 5.39k| any_invocable(F&& f) { \ 304| 5.39k| base_type::template create>(std::forward(f)); \ 305| 5.39k| } \ _ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb1EEEPNS2_11HttpRequestEEEC2Ev: 186| 10.7k| any_invocable_impl() noexcept = default; _ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb1EEEPNS2_11HttpRequestEEE6createIZNS2_12TemplatedAppILb1EEC1ENS2_20SocketContextOptionsEEUlPT_PT0_E_JSH_EEEvDpOT0_: 232| 5.39k| void create(Args&&... args) { 233| 5.39k| using hdl = handler; 234| 5.39k| hdl::create(storage_, std::forward(args)...); 235| 5.39k| handle_ = &hdl::handle; 236| 5.39k| call_ = &hdl::call; 237| 5.39k| } _ZN5ofats10any_detail14handler_traitsIvJPN3uWS12HttpResponseILb1EEEPNS2_11HttpRequestEEE13small_handlerIZNS2_12TemplatedAppILb1EEC1ENS2_20SocketContextOptionsEEUlPT_PT0_E_E6createIJSH_EEEvRNS0_7storageEDpOT_: 118| 16.1k| static void create(storage& s, Args&&... args) { 119| 16.1k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 16.1k| } _ZN5ofats10any_detail14handler_traitsIvJPN3uWS12HttpResponseILb1EEEPNS2_11HttpRequestEEE12handler_baseINS8_13small_handlerIZNS2_12TemplatedAppILb1EEC1ENS2_20SocketContextOptionsEEUlPT_PT0_E_EEE6handleENS0_6actionEPNS0_7storageESN_: 103| 16.1k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 16.1k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 16.1k] ------------------ 105| 5.39k| case (action::destroy): ------------------ | Branch (105:9): [True: 5.39k, False: 10.7k] ------------------ 106| 5.39k| Derived::destroy(*current); 107| 5.39k| break; 108| 10.7k| case (action::move): ------------------ | Branch (108:9): [True: 10.7k, False: 5.39k] ------------------ 109| 10.7k| Derived::move(*current, *other); 110| 10.7k| break; 111| 16.1k| } 112| 16.1k| } _ZN5ofats10any_detail14handler_traitsIvJPN3uWS12HttpResponseILb1EEEPNS2_11HttpRequestEEE13small_handlerIZNS2_12TemplatedAppILb1EEC1ENS2_20SocketContextOptionsEEUlPT_PT0_E_E7destroyERNS0_7storageE: 122| 16.1k| static void destroy(storage& s) noexcept { 123| 16.1k| T& value = *static_cast(static_cast(&s.buf_)); 124| 16.1k| value.~T(); 125| 16.1k| } _ZN5ofats10any_detail14handler_traitsIvJPN3uWS12HttpResponseILb1EEEPNS2_11HttpRequestEEE13small_handlerIZNS2_12TemplatedAppILb1EEC1ENS2_20SocketContextOptionsEEUlPT_PT0_E_E4moveERNS0_7storageESK_: 127| 10.7k| static void move(storage& dst, storage& src) noexcept { 128| 10.7k| create(dst, std::move(*static_cast(static_cast(&src.buf_)))); 129| 10.7k| destroy(src); 130| 10.7k| } _ZN5ofats10any_detail14handler_traitsIvJPN3uWS12HttpResponseILb1EEEPNS2_11HttpRequestEEE13small_handlerIZNS2_12TemplatedAppILb1EEC1ENS2_20SocketContextOptionsEEUlPT_PT0_E_E4callERNS0_7storageES5_S7_: 132| 19.5k| static R call(storage& s, ArgTypes... args) { 133| 19.5k| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 19.5k| std::forward(args)...); 135| 19.5k| } _ZN5ofats13any_invocableIFvvEEaSIDnDnEENSt3__19enable_ifIXaantsr3stdE9is_same_vIT0_S2_Esr3stdE23is_move_constructible_vIS6_EERS2_E4typeEOT_: 335| 124k| operator=(F&& f) { \ 336| 124k| any_invocable{std::forward(f)}.swap(*this); \ 337| 124k| return *this; \ 338| 124k| } \ _ZN5ofats10any_detail18any_invocable_implIvLb0EJEEC2EDn: 187| 124k| any_invocable_impl(std::nullptr_t) noexcept {} _ZN5ofats10any_detail18any_invocable_implIvLb0EJEE4swapERS2_: 208| 124k| void swap(any_invocable_impl& rhs) noexcept { 209| 124k| if (handle_) { ------------------ | Branch (209:9): [True: 0, False: 124k] ------------------ 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| 124k| } else if (rhs.handle_) { ------------------ | Branch (220:16): [True: 0, False: 124k] ------------------ 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| 124k| } _ZN5ofats13any_invocableIFbmEEaSIDnDnEENSt3__19enable_ifIXaantsr3stdE9is_same_vIT0_S2_Esr3stdE23is_move_constructible_vIS6_EERS2_E4typeEOT_: 335| 124k| operator=(F&& f) { \ 336| 124k| any_invocable{std::forward(f)}.swap(*this); \ 337| 124k| return *this; \ 338| 124k| } \ _ZN5ofats10any_detail18any_invocable_implIbLb0EJmEEC2EDn: 187| 124k| any_invocable_impl(std::nullptr_t) noexcept {} _ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb1EEEPNS2_11HttpRequestEEED2Ev: 206| 32.3k| ~any_invocable_impl() { destroy(); } _ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb1EEEPNS2_11HttpRequestEEE7destroyEv: 239| 32.3k| void destroy() noexcept { 240| 32.3k| if (handle_) { ------------------ | Branch (240:9): [True: 10.7k, False: 21.5k] ------------------ 241| 10.7k| handle_(action::destroy, &storage_, nullptr); 242| 10.7k| handle_ = nullptr; 243| 10.7k| } 244| 32.3k| } _ZNK5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EiEENSt3__117basic_string_viewIcNS6_11char_traitsIcEEEENS2_6OpCodeEEEcvbEv: 228| 495| explicit operator bool() const noexcept { return handle_ != nullptr; } _ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS4LoopEEEC2EOS5_: 188| 10.7k| any_invocable_impl(any_invocable_impl&& rhs) noexcept { 189| 10.7k| if (rhs.handle_) { ------------------ | Branch (189:9): [True: 10.7k, False: 0] ------------------ 190| 10.7k| handle_ = rhs.handle_; 191| 10.7k| handle_(action::move, &storage_, &rhs.storage_); 192| 10.7k| call_ = rhs.call_; 193| 10.7k| rhs.handle_ = nullptr; 194| 10.7k| } 195| 10.7k| } EpollEchoServerPubSub.cpp:_ZN5ofats13any_invocableIFvPN3uWS4LoopEEEC2IZNS1_12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOS8_NSt3__112basic_stringIcNSC_11char_traitsIcEENSC_9allocatorIcEEEEONS8_17WebSocketBehaviorIT_EEEUlS3_E_vEEOSK_: 303| 5.39k| any_invocable(F&& f) { \ 304| 5.39k| base_type::template create>(std::forward(f)); \ 305| 5.39k| } \ _ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS4LoopEEEC2Ev: 186| 10.7k| any_invocable_impl() noexcept = default; EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS4LoopEEE6createIZNS2_12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOS8_NSt3__112basic_stringIcNSC_11char_traitsIcEENSC_9allocatorIcEEEEONS8_17WebSocketBehaviorIT_EEEUlS4_E_JSN_EEEvDpOT0_: 232| 5.39k| void create(Args&&... args) { 233| 5.39k| using hdl = handler; 234| 5.39k| hdl::create(storage_, std::forward(args)...); 235| 5.39k| handle_ = &hdl::handle; 236| 5.39k| call_ = &hdl::call; 237| 5.39k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS4LoopEEE13small_handlerIZNS2_12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOS8_NSt3__112basic_stringIcNSC_11char_traitsIcEENSC_9allocatorIcEEEEONS8_17WebSocketBehaviorIT_EEEUlS4_E_E6createIJSN_EEEvRNS0_7storageEDpOT_: 118| 10.7k| static void create(storage& s, Args&&... args) { 119| 10.7k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 10.7k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS4LoopEEE12handler_baseINS5_13small_handlerIZNS2_12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOS9_NSt3__112basic_stringIcNSD_11char_traitsIcEENSD_9allocatorIcEEEEONS9_17WebSocketBehaviorIT_EEEUlS4_E_EEE6handleENS0_6actionEPNS0_7storageEST_: 103| 10.7k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 10.7k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 10.7k] ------------------ 105| 5.39k| case (action::destroy): ------------------ | Branch (105:9): [True: 5.39k, False: 5.39k] ------------------ 106| 5.39k| Derived::destroy(*current); 107| 5.39k| break; 108| 5.39k| case (action::move): ------------------ | Branch (108:9): [True: 5.39k, False: 5.39k] ------------------ 109| 5.39k| Derived::move(*current, *other); 110| 5.39k| break; 111| 10.7k| } 112| 10.7k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS4LoopEEE13small_handlerIZNS2_12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOS8_NSt3__112basic_stringIcNSC_11char_traitsIcEENSC_9allocatorIcEEEEONS8_17WebSocketBehaviorIT_EEEUlS4_E_E7destroyERNS0_7storageE: 122| 10.7k| static void destroy(storage& s) noexcept { 123| 10.7k| T& value = *static_cast(static_cast(&s.buf_)); 124| 10.7k| value.~T(); 125| 10.7k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS4LoopEEE13small_handlerIZNS2_12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOS8_NSt3__112basic_stringIcNSC_11char_traitsIcEENSC_9allocatorIcEEEEONS8_17WebSocketBehaviorIT_EEEUlS4_E_E4moveERNS0_7storageESQ_: 127| 5.39k| static void move(storage& dst, storage& src) noexcept { 128| 5.39k| create(dst, std::move(*static_cast(static_cast(&src.buf_)))); 129| 5.39k| destroy(src); 130| 5.39k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS4LoopEEE13small_handlerIZNS2_12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOS8_NSt3__112basic_stringIcNSC_11char_traitsIcEENSC_9allocatorIcEEEEONS8_17WebSocketBehaviorIT_EEEUlS4_E_E4callERNS0_7storageES4_: 132| 1.29M| static R call(storage& s, ArgTypes... args) { 133| 1.29M| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 1.29M| std::forward(args)...); 135| 1.29M| } EpollEchoServerPubSub.cpp:_ZN5ofats13any_invocableIFvPN3uWS4LoopEEEC2IZNS1_12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOS8_NSt3__112basic_stringIcNSC_11char_traitsIcEENSC_9allocatorIcEEEEONS8_17WebSocketBehaviorIT_EEEUlS3_E0_vEEOSK_: 303| 5.39k| any_invocable(F&& f) { \ 304| 5.39k| base_type::template create>(std::forward(f)); \ 305| 5.39k| } \ EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS4LoopEEE6createIZNS2_12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOS8_NSt3__112basic_stringIcNSC_11char_traitsIcEENSC_9allocatorIcEEEEONS8_17WebSocketBehaviorIT_EEEUlS4_E0_JSN_EEEvDpOT0_: 232| 5.39k| void create(Args&&... args) { 233| 5.39k| using hdl = handler; 234| 5.39k| hdl::create(storage_, std::forward(args)...); 235| 5.39k| handle_ = &hdl::handle; 236| 5.39k| call_ = &hdl::call; 237| 5.39k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS4LoopEEE13small_handlerIZNS2_12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOS8_NSt3__112basic_stringIcNSC_11char_traitsIcEENSC_9allocatorIcEEEEONS8_17WebSocketBehaviorIT_EEEUlS4_E0_E6createIJSN_EEEvRNS0_7storageEDpOT_: 118| 10.7k| static void create(storage& s, Args&&... args) { 119| 10.7k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 10.7k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS4LoopEEE12handler_baseINS5_13small_handlerIZNS2_12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOS9_NSt3__112basic_stringIcNSD_11char_traitsIcEENSD_9allocatorIcEEEEONS9_17WebSocketBehaviorIT_EEEUlS4_E0_EEE6handleENS0_6actionEPNS0_7storageEST_: 103| 10.7k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 10.7k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 10.7k] ------------------ 105| 5.39k| case (action::destroy): ------------------ | Branch (105:9): [True: 5.39k, False: 5.39k] ------------------ 106| 5.39k| Derived::destroy(*current); 107| 5.39k| break; 108| 5.39k| case (action::move): ------------------ | Branch (108:9): [True: 5.39k, False: 5.39k] ------------------ 109| 5.39k| Derived::move(*current, *other); 110| 5.39k| break; 111| 10.7k| } 112| 10.7k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS4LoopEEE13small_handlerIZNS2_12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOS8_NSt3__112basic_stringIcNSC_11char_traitsIcEENSC_9allocatorIcEEEEONS8_17WebSocketBehaviorIT_EEEUlS4_E0_E7destroyERNS0_7storageE: 122| 10.7k| static void destroy(storage& s) noexcept { 123| 10.7k| T& value = *static_cast(static_cast(&s.buf_)); 124| 10.7k| value.~T(); 125| 10.7k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS4LoopEEE13small_handlerIZNS2_12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOS8_NSt3__112basic_stringIcNSC_11char_traitsIcEENSC_9allocatorIcEEEEONS8_17WebSocketBehaviorIT_EEEUlS4_E0_E4moveERNS0_7storageESQ_: 127| 5.39k| static void move(storage& dst, storage& src) noexcept { 128| 5.39k| create(dst, std::move(*static_cast(static_cast(&src.buf_)))); 129| 5.39k| destroy(src); 130| 5.39k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS4LoopEEE13small_handlerIZNS2_12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOS8_NSt3__112basic_stringIcNSC_11char_traitsIcEENSC_9allocatorIcEEEEONS8_17WebSocketBehaviorIT_EEEUlS4_E0_E4callERNS0_7storageES4_: 132| 1.29M| static R call(storage& s, ArgTypes... args) { 133| 1.29M| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 1.29M| std::forward(args)...); 135| 1.29M| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEEEC2EDn: 187| 10.7k| any_invocable_impl(std::nullptr_t) noexcept {} EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEEC2EDn: 187| 5.39k| any_invocable_impl(std::nullptr_t) noexcept {} EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEEC2EDn: 187| 10.7k| any_invocable_impl(std::nullptr_t) noexcept {} EpollEchoServerPubSub.cpp:_ZNK5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEiiEEcvbEv: 228| 10.6M| explicit operator bool() const noexcept { return handle_ != nullptr; } EpollEchoServerPubSub.cpp:_ZNK5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEEcvbEv: 228| 210k| explicit operator bool() const noexcept { return handle_ != nullptr; } EpollEchoServerPubSub.cpp:_ZN5ofats13any_invocableIFvPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS6_11char_traitsIcEEEEEEclES5_iSA_: 345| 210k| R operator()(ArgTypes... args) cv ref noexcept(noex) { \ 346| 210k| return base_type::call(std::forward(args)...); \ 347| 210k| } \ EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE4callES6_iSB_: 246| 210k| R call(ArgTypes... args) noexcept(is_noexcept) { 247| 210k| return call_(storage_, std::forward(args)...); 248| 210k| } EpollEchoServerPubSub.cpp:_ZNK5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEEcvbEv: 228| 1.07M| explicit operator bool() const noexcept { return handle_ != nullptr; } EpollEchoServerPubSub.cpp:_ZN5ofats13any_invocableIFvPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS6_11char_traitsIcEEEENS1_6OpCodeEEEclES5_SA_SB_: 345| 1.07M| R operator()(ArgTypes... args) cv ref noexcept(noex) { \ 346| 1.07M| return base_type::call(std::forward(args)...); \ 347| 1.07M| } \ EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEE4callES6_SB_SC_: 246| 1.07M| R call(ArgTypes... args) noexcept(is_noexcept) { 247| 1.07M| return call_(storage_, std::forward(args)...); 248| 1.07M| } EpollEchoServerPubSub.cpp:_ZNK5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEEcvbEv: 228| 5.73k| explicit operator bool() const noexcept { return handle_ != nullptr; } EpollEchoServerPubSub.cpp:_ZN5ofats13any_invocableIFvPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS6_11char_traitsIcEEEEEEclES5_SA_: 345| 5.73k| R operator()(ArgTypes... args) cv ref noexcept(noex) { \ 346| 5.73k| return base_type::call(std::forward(args)...); \ 347| 5.73k| } \ EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE4callES6_SB_: 246| 5.73k| R call(ArgTypes... args) noexcept(is_noexcept) { 247| 5.73k| return call_(storage_, std::forward(args)...); 248| 5.73k| } EpollEchoServerPubSub.cpp:_ZNK5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEEEcvbEv: 228| 115k| explicit operator bool() const noexcept { return handle_ != nullptr; } EpollEchoServerPubSub.cpp:_ZN5ofats13any_invocableIFvPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEEEclES5_: 345| 115k| R operator()(ArgTypes... args) cv ref noexcept(noex) { \ 346| 115k| return base_type::call(std::forward(args)...); \ 347| 115k| } \ EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEEE4callES6_: 246| 115k| R call(ArgTypes... args) noexcept(is_noexcept) { 247| 115k| return call_(storage_, std::forward(args)...); 248| 115k| } _ZN5ofats10any_detail18any_invocable_implIvLb0EJEEC2EOS2_: 188| 5.39k| any_invocable_impl(any_invocable_impl&& rhs) noexcept { 189| 5.39k| if (rhs.handle_) { ------------------ | Branch (189:9): [True: 5.39k, False: 0] ------------------ 190| 5.39k| handle_ = rhs.handle_; 191| 5.39k| handle_(action::move, &storage_, &rhs.storage_); 192| 5.39k| call_ = rhs.call_; 193| 5.39k| rhs.handle_ = nullptr; 194| 5.39k| } 195| 5.39k| } EpollEchoServerPubSub.cpp:_ZN5ofats13any_invocableIFvvEEC2IZN3uWS12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOS6_NSt3__112basic_stringIcNSA_11char_traitsIcEENSA_9allocatorIcEEEEONS6_17WebSocketBehaviorIT_EEEUlvE_vEEOSI_: 303| 5.39k| any_invocable(F&& f) { \ 304| 5.39k| base_type::template create>(std::forward(f)); \ 305| 5.39k| } \ EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJEE6createIZN3uWS12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOS6_NSt3__112basic_stringIcNSA_11char_traitsIcEENSA_9allocatorIcEEEEONS6_17WebSocketBehaviorIT_EEEUlvE_JSL_EEEvDpOT0_: 232| 5.39k| void create(Args&&... args) { 233| 5.39k| using hdl = handler; 234| 5.39k| hdl::create(storage_, std::forward(args)...); 235| 5.39k| handle_ = &hdl::handle; 236| 5.39k| call_ = &hdl::call; 237| 5.39k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJEE13small_handlerIZN3uWS12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOS6_NSt3__112basic_stringIcNSA_11char_traitsIcEENSA_9allocatorIcEEEEONS6_17WebSocketBehaviorIT_EEEUlvE_E6createIJSL_EEEvRNS0_7storageEDpOT_: 118| 10.7k| static void create(storage& s, Args&&... args) { 119| 10.7k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 10.7k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJEE12handler_baseINS2_13small_handlerIZN3uWS12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOS7_NSt3__112basic_stringIcNSB_11char_traitsIcEENSB_9allocatorIcEEEEONS7_17WebSocketBehaviorIT_EEEUlvE_EEE6handleENS0_6actionEPNS0_7storageESR_: 103| 10.7k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 10.7k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 10.7k] ------------------ 105| 5.39k| case (action::destroy): ------------------ | Branch (105:9): [True: 5.39k, False: 5.39k] ------------------ 106| 5.39k| Derived::destroy(*current); 107| 5.39k| break; 108| 5.39k| case (action::move): ------------------ | Branch (108:9): [True: 5.39k, False: 5.39k] ------------------ 109| 5.39k| Derived::move(*current, *other); 110| 5.39k| break; 111| 10.7k| } 112| 10.7k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJEE13small_handlerIZN3uWS12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOS6_NSt3__112basic_stringIcNSA_11char_traitsIcEENSA_9allocatorIcEEEEONS6_17WebSocketBehaviorIT_EEEUlvE_E7destroyERNS0_7storageE: 122| 10.7k| static void destroy(storage& s) noexcept { 123| 10.7k| T& value = *static_cast(static_cast(&s.buf_)); 124| 10.7k| value.~T(); 125| 10.7k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJEE13small_handlerIZN3uWS12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOS6_NSt3__112basic_stringIcNSA_11char_traitsIcEENSA_9allocatorIcEEEEONS6_17WebSocketBehaviorIT_EEEUlvE_E4moveERNS0_7storageESO_: 127| 5.39k| static void move(storage& dst, storage& src) noexcept { 128| 5.39k| create(dst, std::move(*static_cast(static_cast(&src.buf_)))); 129| 5.39k| destroy(src); 130| 5.39k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJEE13small_handlerIZN3uWS12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOS6_NSt3__112basic_stringIcNSA_11char_traitsIcEENSA_9allocatorIcEEEEONS6_17WebSocketBehaviorIT_EEEUlvE_E4callERNS0_7storageE: 132| 5.39k| static R call(storage& s, ArgTypes... args) { 133| 5.39k| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 5.39k| std::forward(args)...); 135| 5.39k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEEEaSEOS7_: 197| 10.7k| any_invocable_impl& operator=(any_invocable_impl&& rhs) noexcept { 198| 10.7k| any_invocable_impl{std::move(rhs)}.swap(*this); 199| 10.7k| return *this; 200| 10.7k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEEEC2EOS7_: 188| 32.3k| any_invocable_impl(any_invocable_impl&& rhs) noexcept { 189| 32.3k| if (rhs.handle_) { ------------------ | Branch (189:9): [True: 10.7k, False: 21.5k] ------------------ 190| 10.7k| handle_ = rhs.handle_; 191| 10.7k| handle_(action::move, &storage_, &rhs.storage_); 192| 10.7k| call_ = rhs.call_; 193| 10.7k| rhs.handle_ = nullptr; 194| 10.7k| } 195| 32.3k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEEE4swapERS7_: 208| 21.5k| void swap(any_invocable_impl& rhs) noexcept { 209| 21.5k| if (handle_) { ------------------ | Branch (209:9): [True: 10.7k, False: 10.7k] ------------------ 210| 10.7k| if (rhs.handle_) { ------------------ | Branch (210:11): [True: 0, False: 10.7k] ------------------ 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| 10.7k| } else { 218| 10.7k| rhs.swap(*this); 219| 10.7k| } 220| 10.7k| } else if (rhs.handle_) { ------------------ | Branch (220:16): [True: 10.7k, False: 0] ------------------ 221| 10.7k| rhs.handle_(action::move, &storage_, &rhs.storage_); 222| 10.7k| handle_ = rhs.handle_; 223| 10.7k| call_ = rhs.call_; 224| 10.7k| rhs.handle_ = nullptr; 225| 10.7k| } 226| 21.5k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEEaSEOSD_: 197| 10.7k| any_invocable_impl& operator=(any_invocable_impl&& rhs) noexcept { 198| 10.7k| any_invocable_impl{std::move(rhs)}.swap(*this); 199| 10.7k| return *this; 200| 10.7k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEEC2EOSD_: 188| 32.3k| any_invocable_impl(any_invocable_impl&& rhs) noexcept { 189| 32.3k| if (rhs.handle_) { ------------------ | Branch (189:9): [True: 5.39k, False: 26.9k] ------------------ 190| 5.39k| handle_ = rhs.handle_; 191| 5.39k| handle_(action::move, &storage_, &rhs.storage_); 192| 5.39k| call_ = rhs.call_; 193| 5.39k| rhs.handle_ = nullptr; 194| 5.39k| } 195| 32.3k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEE4swapERSD_: 208| 16.1k| void swap(any_invocable_impl& rhs) noexcept { 209| 16.1k| if (handle_) { ------------------ | Branch (209:9): [True: 5.39k, False: 10.7k] ------------------ 210| 5.39k| if (rhs.handle_) { ------------------ | Branch (210:11): [True: 0, False: 5.39k] ------------------ 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| 5.39k| } else { 218| 5.39k| rhs.swap(*this); 219| 5.39k| } 220| 10.7k| } else if (rhs.handle_) { ------------------ | Branch (220:16): [True: 5.39k, False: 5.39k] ------------------ 221| 5.39k| rhs.handle_(action::move, &storage_, &rhs.storage_); 222| 5.39k| handle_ = rhs.handle_; 223| 5.39k| call_ = rhs.call_; 224| 5.39k| rhs.handle_ = nullptr; 225| 5.39k| } 226| 16.1k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEiiEEaSEOSC_: 197| 5.39k| any_invocable_impl& operator=(any_invocable_impl&& rhs) noexcept { 198| 5.39k| any_invocable_impl{std::move(rhs)}.swap(*this); 199| 5.39k| return *this; 200| 5.39k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEiiEEC2EOSC_: 188| 16.1k| any_invocable_impl(any_invocable_impl&& rhs) noexcept { 189| 16.1k| if (rhs.handle_) { ------------------ | Branch (189:9): [True: 0, False: 16.1k] ------------------ 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| 16.1k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEiiEE4swapERSC_: 208| 5.39k| void swap(any_invocable_impl& rhs) noexcept { 209| 5.39k| if (handle_) { ------------------ | Branch (209:9): [True: 0, False: 5.39k] ------------------ 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| 5.39k| } else if (rhs.handle_) { ------------------ | Branch (220:16): [True: 0, False: 5.39k] ------------------ 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| 5.39k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEEC2EOSC_: 188| 21.5k| any_invocable_impl(any_invocable_impl&& rhs) noexcept { 189| 21.5k| if (rhs.handle_) { ------------------ | Branch (189:9): [True: 10.7k, False: 10.7k] ------------------ 190| 10.7k| handle_ = rhs.handle_; 191| 10.7k| handle_(action::move, &storage_, &rhs.storage_); 192| 10.7k| call_ = rhs.call_; 193| 10.7k| rhs.handle_ = nullptr; 194| 10.7k| } 195| 21.5k| } EpollEchoServerPubSub.cpp:_ZN5ofats13any_invocableIFvPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS6_11char_traitsIcEEEEEEaSIZNS1_12TemplatedAppILb1EE2wsIS3_EEOSF_NS6_12basic_stringIcS9_NS6_9allocatorIcEEEEONSF_17WebSocketBehaviorIT_EEEUlS5_iSA_E_SQ_EENS6_9enable_ifIXaantsr3stdE9is_same_vIT0_SC_Esr3stdE23is_move_constructible_vISS_EERSC_E4typeEOSN_: 335| 5.39k| operator=(F&& f) { \ 336| 5.39k| any_invocable{std::forward(f)}.swap(*this); \ 337| 5.39k| return *this; \ 338| 5.39k| } \ EpollEchoServerPubSub.cpp:_ZN5ofats13any_invocableIFvPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS6_11char_traitsIcEEEEEEC2IZNS1_12TemplatedAppILb1EE2wsIS3_EEOSF_NS6_12basic_stringIcS9_NS6_9allocatorIcEEEEONSF_17WebSocketBehaviorIT_EEEUlS5_iSA_E_vEEOSN_: 303| 5.39k| any_invocable(F&& f) { \ 304| 5.39k| base_type::template create>(std::forward(f)); \ 305| 5.39k| } \ EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEEC2Ev: 186| 10.7k| any_invocable_impl() noexcept = default; EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE6createIZNS2_12TemplatedAppILb1EE2wsIS4_EEOSF_NS7_12basic_stringIcSA_NS7_9allocatorIcEEEEONSF_17WebSocketBehaviorIT_EEEUlS6_iSB_E_JSQ_EEEvDpOT0_: 232| 5.39k| void create(Args&&... args) { 233| 5.39k| using hdl = handler; 234| 5.39k| hdl::create(storage_, std::forward(args)...); 235| 5.39k| handle_ = &hdl::handle; 236| 5.39k| call_ = &hdl::call; 237| 5.39k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13large_handlerIZNS2_12TemplatedAppILb1EE2wsIS4_EEOSF_NS7_12basic_stringIcSA_NS7_9allocatorIcEEEEONSF_17WebSocketBehaviorIT_EEEUlS6_iSB_E_E6createIJSQ_EEEvRNS0_7storageEDpOT_: 141| 5.39k| static void create(storage& s, Args&&... args) { 142| 5.39k| s.ptr_ = new T(std::forward(args)...); 143| 5.39k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE12handler_baseINSC_13large_handlerIZNS2_12TemplatedAppILb1EE2wsIS4_EEOSG_NS7_12basic_stringIcSA_NS7_9allocatorIcEEEEONSG_17WebSocketBehaviorIT_EEEUlS6_iSB_E_EEE6handleENS0_6actionEPNS0_7storageESW_: 103| 10.7k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 10.7k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 10.7k] ------------------ 105| 5.39k| case (action::destroy): ------------------ | Branch (105:9): [True: 5.39k, False: 5.39k] ------------------ 106| 5.39k| Derived::destroy(*current); 107| 5.39k| break; 108| 5.39k| case (action::move): ------------------ | Branch (108:9): [True: 5.39k, False: 5.39k] ------------------ 109| 5.39k| Derived::move(*current, *other); 110| 5.39k| break; 111| 10.7k| } 112| 10.7k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13large_handlerIZNS2_12TemplatedAppILb1EE2wsIS4_EEOSF_NS7_12basic_stringIcSA_NS7_9allocatorIcEEEEONSF_17WebSocketBehaviorIT_EEEUlS6_iSB_E_E7destroyERNS0_7storageE: 145| 5.39k| static void destroy(storage& s) noexcept { delete static_cast(s.ptr_); } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13large_handlerIZNS2_12TemplatedAppILb1EE2wsIS4_EEOSF_NS7_12basic_stringIcSA_NS7_9allocatorIcEEEEONSF_17WebSocketBehaviorIT_EEEUlS6_iSB_E_E4moveERNS0_7storageEST_: 147| 5.39k| static void move(storage& dst, storage& src) noexcept { 148| 5.39k| dst.ptr_ = src.ptr_; 149| 5.39k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13large_handlerIZNS2_12TemplatedAppILb1EE2wsIS4_EEOSF_NS7_12basic_stringIcSA_NS7_9allocatorIcEEEEONSF_17WebSocketBehaviorIT_EEEUlS6_iSB_E_E4callERNS0_7storageES6_iSB_: 151| 105k| static R call(storage& s, ArgTypes... args) { 152| 105k| return std::invoke(*static_cast(s.ptr_), 153| 105k| std::forward(args)...); 154| 105k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE4swapERSC_: 208| 10.7k| void swap(any_invocable_impl& rhs) noexcept { 209| 10.7k| if (handle_) { ------------------ | Branch (209:9): [True: 5.39k, False: 5.39k] ------------------ 210| 5.39k| if (rhs.handle_) { ------------------ | Branch (210:11): [True: 0, False: 5.39k] ------------------ 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| 5.39k| } else { 218| 5.39k| rhs.swap(*this); 219| 5.39k| } 220| 5.39k| } else if (rhs.handle_) { ------------------ | Branch (220:16): [True: 5.39k, False: 0] ------------------ 221| 5.39k| rhs.handle_(action::move, &storage_, &rhs.storage_); 222| 5.39k| handle_ = rhs.handle_; 223| 5.39k| call_ = rhs.call_; 224| 5.39k| rhs.handle_ = nullptr; 225| 5.39k| } 226| 10.7k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEEaSEOSC_: 197| 10.7k| any_invocable_impl& operator=(any_invocable_impl&& rhs) noexcept { 198| 10.7k| any_invocable_impl{std::move(rhs)}.swap(*this); 199| 10.7k| return *this; 200| 10.7k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEEC2EOSC_: 188| 32.3k| any_invocable_impl(any_invocable_impl&& rhs) noexcept { 189| 32.3k| if (rhs.handle_) { ------------------ | Branch (189:9): [True: 10.7k, False: 21.5k] ------------------ 190| 10.7k| handle_ = rhs.handle_; 191| 10.7k| handle_(action::move, &storage_, &rhs.storage_); 192| 10.7k| call_ = rhs.call_; 193| 10.7k| rhs.handle_ = nullptr; 194| 10.7k| } 195| 32.3k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE4swapERSC_: 208| 21.5k| void swap(any_invocable_impl& rhs) noexcept { 209| 21.5k| if (handle_) { ------------------ | Branch (209:9): [True: 10.7k, False: 10.7k] ------------------ 210| 10.7k| if (rhs.handle_) { ------------------ | Branch (210:11): [True: 0, False: 10.7k] ------------------ 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| 10.7k| } else { 218| 10.7k| rhs.swap(*this); 219| 10.7k| } 220| 10.7k| } else if (rhs.handle_) { ------------------ | Branch (220:16): [True: 10.7k, False: 0] ------------------ 221| 10.7k| rhs.handle_(action::move, &storage_, &rhs.storage_); 222| 10.7k| handle_ = rhs.handle_; 223| 10.7k| call_ = rhs.call_; 224| 10.7k| rhs.handle_ = nullptr; 225| 10.7k| } 226| 21.5k| } _ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb1EEEPNS2_11HttpRequestEP19us_socket_context_tEEC2EOSA_: 188| 10.7k| any_invocable_impl(any_invocable_impl&& rhs) noexcept { 189| 10.7k| if (rhs.handle_) { ------------------ | Branch (189:9): [True: 0, False: 10.7k] ------------------ 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| 10.7k| } EpollEchoServerPubSub.cpp:_ZN5ofats13any_invocableIFvPN3uWS12HttpResponseILb1EEEPNS1_11HttpRequestEEEC2IZNS1_12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOSB_NSt3__112basic_stringIcNSF_11char_traitsIcEENSF_9allocatorIcEEEEONSB_17WebSocketBehaviorIT_EEEUlPSN_PT0_E_vEEOSN_: 303| 5.39k| any_invocable(F&& f) { \ 304| 5.39k| base_type::template create>(std::forward(f)); \ 305| 5.39k| } \ EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb1EEEPNS2_11HttpRequestEEE6createIZNS2_12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOSB_NSt3__112basic_stringIcNSF_11char_traitsIcEENSF_9allocatorIcEEEEONSB_17WebSocketBehaviorIT_EEEUlPSN_PT0_E_JST_EEEvDpOT0_: 232| 5.39k| void create(Args&&... args) { 233| 5.39k| using hdl = handler; 234| 5.39k| hdl::create(storage_, std::forward(args)...); 235| 5.39k| handle_ = &hdl::handle; 236| 5.39k| call_ = &hdl::call; 237| 5.39k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS12HttpResponseILb1EEEPNS2_11HttpRequestEEE13large_handlerIZNS2_12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOSB_NSt3__112basic_stringIcNSF_11char_traitsIcEENSF_9allocatorIcEEEEONSB_17WebSocketBehaviorIT_EEEUlPSN_PT0_E_E6createIJST_EEEvRNS0_7storageEDpOT_: 141| 5.39k| static void create(storage& s, Args&&... args) { 142| 5.39k| s.ptr_ = new T(std::forward(args)...); 143| 5.39k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS12HttpResponseILb1EEEPNS2_11HttpRequestEEE12handler_baseINS8_13large_handlerIZNS2_12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOSC_NSt3__112basic_stringIcNSG_11char_traitsIcEENSG_9allocatorIcEEEEONSC_17WebSocketBehaviorIT_EEEUlPSO_PT0_E_EEE6handleENS0_6actionEPNS0_7storageESZ_: 103| 16.1k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 16.1k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 16.1k] ------------------ 105| 5.39k| case (action::destroy): ------------------ | Branch (105:9): [True: 5.39k, False: 10.7k] ------------------ 106| 5.39k| Derived::destroy(*current); 107| 5.39k| break; 108| 10.7k| case (action::move): ------------------ | Branch (108:9): [True: 10.7k, False: 5.39k] ------------------ 109| 10.7k| Derived::move(*current, *other); 110| 10.7k| break; 111| 16.1k| } 112| 16.1k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS12HttpResponseILb1EEEPNS2_11HttpRequestEEE13large_handlerIZNS2_12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOSB_NSt3__112basic_stringIcNSF_11char_traitsIcEENSF_9allocatorIcEEEEONSB_17WebSocketBehaviorIT_EEEUlPSN_PT0_E_E7destroyERNS0_7storageE: 145| 5.39k| static void destroy(storage& s) noexcept { delete static_cast(s.ptr_); } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS12HttpResponseILb1EEEPNS2_11HttpRequestEEE13large_handlerIZNS2_12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOSB_NSt3__112basic_stringIcNSF_11char_traitsIcEENSF_9allocatorIcEEEEONSB_17WebSocketBehaviorIT_EEEUlPSN_PT0_E_E4moveERNS0_7storageESW_: 147| 10.7k| static void move(storage& dst, storage& src) noexcept { 148| 10.7k| dst.ptr_ = src.ptr_; 149| 10.7k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS12HttpResponseILb1EEEPNS2_11HttpRequestEEE13large_handlerIZNS2_12TemplatedAppILb1EE2wsIZ4testvE13PerSocketDataEEOSB_NSt3__112basic_stringIcNSF_11char_traitsIcEENSF_9allocatorIcEEEEONSB_17WebSocketBehaviorIT_EEEUlPSN_PT0_E_E4callERNS0_7storageES5_S7_: 151| 109k| static R call(storage& s, ArgTypes... args) { 152| 109k| return std::invoke(*static_cast(s.ptr_), 153| 109k| std::forward(args)...); 154| 109k| } _ZNK5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS12HttpResponseILb1EEEPNS2_11HttpRequestEP19us_socket_context_tEEcvbEv: 228| 105k| explicit operator bool() const noexcept { return handle_ != nullptr; } EpollEchoServerPubSub.cpp:_ZN5ofats13any_invocableIFvPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEEEC2IZ4testvE3$_0vEEOT_: 303| 5.39k| any_invocable(F&& f) { \ 304| 5.39k| base_type::template create>(std::forward(f)); \ 305| 5.39k| } \ EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEEEC2Ev: 186| 10.7k| any_invocable_impl() noexcept = default; EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEEE6createIZ4testvE3$_0JS9_EEEvDpOT0_: 232| 5.39k| void create(Args&&... args) { 233| 5.39k| using hdl = handler; 234| 5.39k| hdl::create(storage_, std::forward(args)...); 235| 5.39k| handle_ = &hdl::handle; 236| 5.39k| call_ = &hdl::call; 237| 5.39k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEEE13small_handlerIZ4testvE3$_0E6createIJS9_EEEvRNS0_7storageEDpOT_: 118| 16.1k| static void create(storage& s, Args&&... args) { 119| 16.1k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 16.1k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEEE12handler_baseINS7_13small_handlerIZ4testvE3$_0EEE6handleENS0_6actionEPNS0_7storageESF_: 103| 16.1k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 16.1k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 16.1k] ------------------ 105| 5.39k| case (action::destroy): ------------------ | Branch (105:9): [True: 5.39k, False: 10.7k] ------------------ 106| 5.39k| Derived::destroy(*current); 107| 5.39k| break; 108| 10.7k| case (action::move): ------------------ | Branch (108:9): [True: 10.7k, False: 5.39k] ------------------ 109| 10.7k| Derived::move(*current, *other); 110| 10.7k| break; 111| 16.1k| } 112| 16.1k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEEE13small_handlerIZ4testvE3$_0E7destroyERNS0_7storageE: 122| 16.1k| static void destroy(storage& s) noexcept { 123| 16.1k| T& value = *static_cast(static_cast(&s.buf_)); 124| 16.1k| value.~T(); 125| 16.1k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEEE13small_handlerIZ4testvE3$_0E4moveERNS0_7storageESC_: 127| 10.7k| static void move(storage& dst, storage& src) noexcept { 128| 10.7k| create(dst, std::move(*static_cast(static_cast(&src.buf_)))); 129| 10.7k| destroy(src); 130| 10.7k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEEE13small_handlerIZ4testvE3$_0E4callERNS0_7storageES6_: 132| 105k| static R call(storage& s, ArgTypes... args) { 133| 105k| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 105k| std::forward(args)...); 135| 105k| } EpollEchoServerPubSub.cpp:_ZN5ofats13any_invocableIFvPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS6_11char_traitsIcEEEENS1_6OpCodeEEEC2IZ4testvE3$_1vEEOT_: 303| 5.39k| any_invocable(F&& f) { \ 304| 5.39k| base_type::template create>(std::forward(f)); \ 305| 5.39k| } \ EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEEC2Ev: 186| 5.39k| any_invocable_impl() noexcept = default; EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEE6createIZ4testvE3$_1JSF_EEEvDpOT0_: 232| 5.39k| void create(Args&&... args) { 233| 5.39k| using hdl = handler; 234| 5.39k| hdl::create(storage_, std::forward(args)...); 235| 5.39k| handle_ = &hdl::handle; 236| 5.39k| call_ = &hdl::call; 237| 5.39k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEE13small_handlerIZ4testvE3$_1E6createIJSF_EEEvRNS0_7storageEDpOT_: 118| 16.1k| static void create(storage& s, Args&&... args) { 119| 16.1k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 16.1k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEE12handler_baseINSD_13small_handlerIZ4testvE3$_1EEE6handleENS0_6actionEPNS0_7storageESL_: 103| 16.1k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 16.1k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 16.1k] ------------------ 105| 5.39k| case (action::destroy): ------------------ | Branch (105:9): [True: 5.39k, False: 10.7k] ------------------ 106| 5.39k| Derived::destroy(*current); 107| 5.39k| break; 108| 10.7k| case (action::move): ------------------ | Branch (108:9): [True: 10.7k, False: 5.39k] ------------------ 109| 10.7k| Derived::move(*current, *other); 110| 10.7k| break; 111| 16.1k| } 112| 16.1k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEE13small_handlerIZ4testvE3$_1E7destroyERNS0_7storageE: 122| 16.1k| static void destroy(storage& s) noexcept { 123| 16.1k| T& value = *static_cast(static_cast(&s.buf_)); 124| 16.1k| value.~T(); 125| 16.1k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEE13small_handlerIZ4testvE3$_1E4moveERNS0_7storageESI_: 127| 10.7k| static void move(storage& dst, storage& src) noexcept { 128| 10.7k| create(dst, std::move(*static_cast(static_cast(&src.buf_)))); 129| 10.7k| destroy(src); 130| 10.7k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS2_6OpCodeEEE13small_handlerIZ4testvE3$_1E4callERNS0_7storageES6_SB_SC_: 132| 1.07M| static R call(storage& s, ArgTypes... args) { 133| 1.07M| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 1.07M| std::forward(args)...); 135| 1.07M| } EpollEchoServerPubSub.cpp:_ZN5ofats13any_invocableIFvPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEEEC2IZ4testvE3$_2vEEOT_: 303| 5.39k| any_invocable(F&& f) { \ 304| 5.39k| base_type::template create>(std::forward(f)); \ 305| 5.39k| } \ EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEEE6createIZ4testvE3$_2JS9_EEEvDpOT0_: 232| 5.39k| void create(Args&&... args) { 233| 5.39k| using hdl = handler; 234| 5.39k| hdl::create(storage_, std::forward(args)...); 235| 5.39k| handle_ = &hdl::handle; 236| 5.39k| call_ = &hdl::call; 237| 5.39k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEEE13small_handlerIZ4testvE3$_2E6createIJS9_EEEvRNS0_7storageEDpOT_: 118| 16.1k| static void create(storage& s, Args&&... args) { 119| 16.1k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 16.1k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEEE12handler_baseINS7_13small_handlerIZ4testvE3$_2EEE6handleENS0_6actionEPNS0_7storageESF_: 103| 16.1k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 16.1k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 16.1k] ------------------ 105| 5.39k| case (action::destroy): ------------------ | Branch (105:9): [True: 5.39k, False: 10.7k] ------------------ 106| 5.39k| Derived::destroy(*current); 107| 5.39k| break; 108| 10.7k| case (action::move): ------------------ | Branch (108:9): [True: 10.7k, False: 5.39k] ------------------ 109| 10.7k| Derived::move(*current, *other); 110| 10.7k| break; 111| 16.1k| } 112| 16.1k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEEE13small_handlerIZ4testvE3$_2E7destroyERNS0_7storageE: 122| 16.1k| static void destroy(storage& s) noexcept { 123| 16.1k| T& value = *static_cast(static_cast(&s.buf_)); 124| 16.1k| value.~T(); 125| 16.1k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEEE13small_handlerIZ4testvE3$_2E4moveERNS0_7storageESC_: 127| 10.7k| static void move(storage& dst, storage& src) noexcept { 128| 10.7k| create(dst, std::move(*static_cast(static_cast(&src.buf_)))); 129| 10.7k| destroy(src); 130| 10.7k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEEE13small_handlerIZ4testvE3$_2E4callERNS0_7storageES6_: 132| 10.3k| static R call(storage& s, ArgTypes... args) { 133| 10.3k| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 10.3k| std::forward(args)...); 135| 10.3k| } EpollEchoServerPubSub.cpp:_ZN5ofats13any_invocableIFvPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS6_11char_traitsIcEEEEEEC2IZ4testvE3$_3vEEOT_: 303| 5.39k| any_invocable(F&& f) { \ 304| 5.39k| base_type::template create>(std::forward(f)); \ 305| 5.39k| } \ EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEEC2Ev: 186| 10.7k| any_invocable_impl() noexcept = default; EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE6createIZ4testvE3$_3JSE_EEEvDpOT0_: 232| 5.39k| void create(Args&&... args) { 233| 5.39k| using hdl = handler; 234| 5.39k| hdl::create(storage_, std::forward(args)...); 235| 5.39k| handle_ = &hdl::handle; 236| 5.39k| call_ = &hdl::call; 237| 5.39k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE3$_3E6createIJSE_EEEvRNS0_7storageEDpOT_: 118| 16.1k| static void create(storage& s, Args&&... args) { 119| 16.1k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 16.1k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE12handler_baseINSC_13small_handlerIZ4testvE3$_3EEE6handleENS0_6actionEPNS0_7storageESK_: 103| 16.1k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 16.1k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 16.1k] ------------------ 105| 5.39k| case (action::destroy): ------------------ | Branch (105:9): [True: 5.39k, False: 10.7k] ------------------ 106| 5.39k| Derived::destroy(*current); 107| 5.39k| break; 108| 10.7k| case (action::move): ------------------ | Branch (108:9): [True: 10.7k, False: 5.39k] ------------------ 109| 10.7k| Derived::move(*current, *other); 110| 10.7k| break; 111| 16.1k| } 112| 16.1k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE3$_3E7destroyERNS0_7storageE: 122| 16.1k| static void destroy(storage& s) noexcept { 123| 16.1k| T& value = *static_cast(static_cast(&s.buf_)); 124| 16.1k| value.~T(); 125| 16.1k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE3$_3E4moveERNS0_7storageESH_: 127| 10.7k| static void move(storage& dst, storage& src) noexcept { 128| 10.7k| create(dst, std::move(*static_cast(static_cast(&src.buf_)))); 129| 10.7k| destroy(src); 130| 10.7k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE3$_3E4callERNS0_7storageES6_SB_: 132| 4.94k| static R call(storage& s, ArgTypes... args) { 133| 4.94k| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 4.94k| std::forward(args)...); 135| 4.94k| } EpollEchoServerPubSub.cpp:_ZN5ofats13any_invocableIFvPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS6_11char_traitsIcEEEEEEC2IZ4testvE3$_4vEEOT_: 303| 5.39k| any_invocable(F&& f) { \ 304| 5.39k| base_type::template create>(std::forward(f)); \ 305| 5.39k| } \ EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE6createIZ4testvE3$_4JSE_EEEvDpOT0_: 232| 5.39k| void create(Args&&... args) { 233| 5.39k| using hdl = handler; 234| 5.39k| hdl::create(storage_, std::forward(args)...); 235| 5.39k| handle_ = &hdl::handle; 236| 5.39k| call_ = &hdl::call; 237| 5.39k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE3$_4E6createIJSE_EEEvRNS0_7storageEDpOT_: 118| 16.1k| static void create(storage& s, Args&&... args) { 119| 16.1k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 16.1k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE12handler_baseINSC_13small_handlerIZ4testvE3$_4EEE6handleENS0_6actionEPNS0_7storageESK_: 103| 16.1k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 16.1k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 16.1k] ------------------ 105| 5.39k| case (action::destroy): ------------------ | Branch (105:9): [True: 5.39k, False: 10.7k] ------------------ 106| 5.39k| Derived::destroy(*current); 107| 5.39k| break; 108| 10.7k| case (action::move): ------------------ | Branch (108:9): [True: 10.7k, False: 5.39k] ------------------ 109| 10.7k| Derived::move(*current, *other); 110| 10.7k| break; 111| 16.1k| } 112| 16.1k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE3$_4E7destroyERNS0_7storageE: 122| 16.1k| static void destroy(storage& s) noexcept { 123| 16.1k| T& value = *static_cast(static_cast(&s.buf_)); 124| 16.1k| value.~T(); 125| 16.1k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE3$_4E4moveERNS0_7storageESH_: 127| 10.7k| static void move(storage& dst, storage& src) noexcept { 128| 10.7k| create(dst, std::move(*static_cast(static_cast(&src.buf_)))); 129| 10.7k| destroy(src); 130| 10.7k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE3$_4E4callERNS0_7storageES6_SB_: 132| 788| static R call(storage& s, ArgTypes... args) { 133| 788| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 788| std::forward(args)...); 135| 788| } EpollEchoServerPubSub.cpp:_ZN5ofats13any_invocableIFvPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS6_11char_traitsIcEEEEEEC2IZ4testvE3$_5vEEOT_: 303| 5.39k| any_invocable(F&& f) { \ 304| 5.39k| base_type::template create>(std::forward(f)); \ 305| 5.39k| } \ EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE6createIZ4testvE3$_5JSE_EEEvDpOT0_: 232| 5.39k| void create(Args&&... args) { 233| 5.39k| using hdl = handler; 234| 5.39k| hdl::create(storage_, std::forward(args)...); 235| 5.39k| handle_ = &hdl::handle; 236| 5.39k| call_ = &hdl::call; 237| 5.39k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE3$_5E6createIJSE_EEEvRNS0_7storageEDpOT_: 118| 16.1k| static void create(storage& s, Args&&... args) { 119| 16.1k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 16.1k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE12handler_baseINSC_13small_handlerIZ4testvE3$_5EEE6handleENS0_6actionEPNS0_7storageESK_: 103| 16.1k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 16.1k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 16.1k] ------------------ 105| 5.39k| case (action::destroy): ------------------ | Branch (105:9): [True: 5.39k, False: 10.7k] ------------------ 106| 5.39k| Derived::destroy(*current); 107| 5.39k| break; 108| 10.7k| case (action::move): ------------------ | Branch (108:9): [True: 10.7k, False: 5.39k] ------------------ 109| 10.7k| Derived::move(*current, *other); 110| 10.7k| break; 111| 16.1k| } 112| 16.1k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE3$_5E7destroyERNS0_7storageE: 122| 16.1k| static void destroy(storage& s) noexcept { 123| 16.1k| T& value = *static_cast(static_cast(&s.buf_)); 124| 16.1k| value.~T(); 125| 16.1k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE3$_5E4moveERNS0_7storageESH_: 127| 10.7k| static void move(storage& dst, storage& src) noexcept { 128| 10.7k| create(dst, std::move(*static_cast(static_cast(&src.buf_)))); 129| 10.7k| destroy(src); 130| 10.7k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJPN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEiNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEEE13small_handlerIZ4testvE3$_5E4callERNS0_7storageES6_iSB_: 132| 105k| static R call(storage& s, ArgTypes... args) { 133| 105k| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 105k| std::forward(args)...); 135| 105k| } _ZN5ofats13any_invocableIFvP18us_listen_socket_tEEclES2_: 345| 5.39k| R operator()(ArgTypes... args) cv ref noexcept(noex) { \ 346| 5.39k| return base_type::call(std::forward(args)...); \ 347| 5.39k| } \ _ZN5ofats10any_detail18any_invocable_implIvLb0EJP18us_listen_socket_tEE4callES3_: 246| 5.39k| R call(ArgTypes... args) noexcept(is_noexcept) { 247| 5.39k| return call_(storage_, std::forward(args)...); 248| 5.39k| } EpollEchoServerPubSub.cpp:_ZN5ofats13any_invocableIFvP18us_listen_socket_tEEC2IZ4testvE3$_6vEEOT_: 303| 5.39k| any_invocable(F&& f) { \ 304| 5.39k| base_type::template create>(std::forward(f)); \ 305| 5.39k| } \ _ZN5ofats10any_detail18any_invocable_implIvLb0EJP18us_listen_socket_tEEC2Ev: 186| 5.39k| any_invocable_impl() noexcept = default; EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail18any_invocable_implIvLb0EJP18us_listen_socket_tEE6createIZ4testvE3$_6JS6_EEEvDpOT0_: 232| 5.39k| void create(Args&&... args) { 233| 5.39k| using hdl = handler; 234| 5.39k| hdl::create(storage_, std::forward(args)...); 235| 5.39k| handle_ = &hdl::handle; 236| 5.39k| call_ = &hdl::call; 237| 5.39k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJP18us_listen_socket_tEE13small_handlerIZ4testvE3$_6E6createIJS6_EEEvRNS0_7storageEDpOT_: 118| 5.39k| static void create(storage& s, Args&&... args) { 119| 5.39k| new (static_cast(&s.buf_)) T(std::forward(args)...); 120| 5.39k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJP18us_listen_socket_tEE12handler_baseINS4_13small_handlerIZ4testvE3$_6EEE6handleENS0_6actionEPNS0_7storageESC_: 103| 5.39k| static void handle(action act, storage* current, storage* other = nullptr) { 104| 5.39k| switch (act) { ------------------ | Branch (104:15): [True: 0, False: 5.39k] ------------------ 105| 5.39k| case (action::destroy): ------------------ | Branch (105:9): [True: 5.39k, False: 0] ------------------ 106| 5.39k| Derived::destroy(*current); 107| 5.39k| break; 108| 0| case (action::move): ------------------ | Branch (108:9): [True: 0, False: 5.39k] ------------------ 109| 0| Derived::move(*current, *other); 110| 0| break; 111| 5.39k| } 112| 5.39k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJP18us_listen_socket_tEE13small_handlerIZ4testvE3$_6E7destroyERNS0_7storageE: 122| 5.39k| static void destroy(storage& s) noexcept { 123| 5.39k| T& value = *static_cast(static_cast(&s.buf_)); 124| 5.39k| value.~T(); 125| 5.39k| } EpollEchoServerPubSub.cpp:_ZN5ofats10any_detail14handler_traitsIvJP18us_listen_socket_tEE13small_handlerIZ4testvE3$_6E4callERNS0_7storageES3_: 132| 5.39k| static R call(storage& s, ArgTypes... args) { 133| 5.39k| return std::invoke(*static_cast(static_cast(&s.buf_)), 134| 5.39k| std::forward(args)...); 135| 5.39k| } _ZN3uWS9TopicTreeINS_16TopicTreeMessageENS_19TopicTreeBigMessageEE5drainEPNS_10SubscriberE: 249| 63.6k| void drain(Subscriber *s) { 250| | /* The list is undefined and cannot be touched unless needsDrainage(). */ 251| 63.6k| if (s->needsDrainage()) { ------------------ | Branch (251:13): [True: 3.51k, False: 60.1k] ------------------ 252| | /* This function differs from drainImpl by properly unlinking 253| | * the subscriber from drainableSubscribers. drainImpl does not. */ 254| 3.51k| 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| 3.51k| drainImpl(s); 259| | 260| | /* If we drained last subscriber, also clear outgoingMessages */ 261| 3.51k| if (!drainableSubscribers) { ------------------ | Branch (261:17): [True: 3.07k, False: 446] ------------------ 262| 3.07k| outgoingMessages.clear(); 263| 3.07k| } 264| 3.51k| } 265| 63.6k| } _ZN3uWS10Subscriber13needsDrainageEv: 73| 169k| bool needsDrainage() { 74| 169k| return numMessageIndices; 75| 169k| } _ZN3uWS9TopicTreeINS_16TopicTreeMessageENS_19TopicTreeBigMessageEE25unlinkDrainableSubscriberEPNS_10SubscriberE: 132| 44.1k| void unlinkDrainableSubscriber(Subscriber *s) { 133| 44.1k| if (s->prev) { ------------------ | Branch (133:13): [True: 0, False: 44.1k] ------------------ 134| 0| s->prev->next = s->next; 135| 0| } 136| 44.1k| if (s->next) { ------------------ | Branch (136:13): [True: 876, False: 43.3k] ------------------ 137| 876| s->next->prev = s->prev; 138| 876| } 139| | /* If we are the head, then we also need to reset the head */ 140| 44.1k| if (drainableSubscribers == s) { ------------------ | Branch (140:13): [True: 44.1k, False: 0] ------------------ 141| 44.1k| drainableSubscribers = s->next; 142| 44.1k| } 143| 44.1k| } _ZN3uWS9TopicTreeINS_16TopicTreeMessageENS_19TopicTreeBigMessageEE9drainImplEPNS_10SubscriberE: 113| 9.71k| 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| 9.71k| int numMessageIndices = s->numMessageIndices; 117| 9.71k| s->numMessageIndices = 0; 118| | 119| | /* Then we emit cb */ 120| 59.4k| for (int i = 0; i < numMessageIndices; i++) { ------------------ | Branch (120:25): [True: 50.2k, False: 9.22k] ------------------ 121| 50.2k| T &outgoingMessage = outgoingMessages[s->messageIndices[i]]; 122| | 123| 50.2k| int flags = (i == numMessageIndices - 1) ? LAST : 0; ------------------ | Branch (123:25): [True: 9.28k, False: 40.9k] ------------------ 124| | 125| | /* Returning true will stop drainage short (such as when backpressure is too high) */ 126| 50.2k| if (cb(s, outgoingMessage, (IteratorFlags)(flags | (i == 0 ? FIRST : 0)))) { ------------------ | Branch (126:17): [True: 495, False: 49.7k] | Branch (126:65): [True: 9.71k, False: 40.5k] ------------------ 127| 495| break; 128| 495| } 129| 50.2k| } 130| 9.71k| } _ZN3uWS9TopicTreeINS_16TopicTreeMessageENS_19TopicTreeBigMessageEEC2ENSt3__18functionIFbPNS_10SubscriberERS1_NS3_13IteratorFlagsEEEE: 147| 5.39k| TopicTree(std::function cb) : cb(cb) { 148| | 149| 5.39k| } _ZN3uWS9TopicTreeINS_16TopicTreeMessageENS_19TopicTreeBigMessageEE5drainEv: 268| 2.59M| void drain() { 269| 2.59M| if (drainableSubscribers) { ------------------ | Branch (269:13): [True: 5.93k, False: 2.58M] ------------------ 270| | /* Drain one socket a time */ 271| 12.1k| for (Subscriber *s = drainableSubscribers; s; s = s->next) { ------------------ | Branch (271:56): [True: 6.20k, False: 5.93k] ------------------ 272| | /* Instead of unlinking every single subscriber, we just leave the list undefined 273| | * and reset drainableSubscribers ptr below. */ 274| 6.20k| drainImpl(s); 275| 6.20k| } 276| | /* Drain always clears drainableSubscribers and outgoingMessages */ 277| 5.93k| drainableSubscribers = nullptr; 278| 5.93k| outgoingMessages.clear(); 279| 5.93k| } 280| 2.59M| } _ZN3uWS9TopicTreeINS_16TopicTreeMessageENS_19TopicTreeBigMessageEE14freeSubscriberEPNS_10SubscriberE: 222| 105k| void freeSubscriber(Subscriber *s) { 223| | 224| | /* I guess we call this one even if we are not subscribers */ 225| 105k| if (!s) { ------------------ | Branch (225:13): [True: 0, False: 105k] ------------------ 226| 0| return; 227| 0| } 228| | 229| | /* For all topics, unsubscribe */ 230| 10.5M| for (Topic *topicPtr : s->topics) { ------------------ | Branch (230:30): [True: 10.5M, False: 105k] ------------------ 231| | /* If we are the last subscriber, simply remove the whole topic */ 232| 10.5M| if (topicPtr->size() == 1) { ------------------ | Branch (232:17): [True: 10.5M, False: 0] ------------------ 233| 10.5M| topics.erase(topicPtr->name); 234| 10.5M| } else { 235| | /* Otherwise just remove us */ 236| 0| topicPtr->erase(s); 237| 0| } 238| 10.5M| } 239| | 240| | /* We also need to unlink us */ 241| 105k| if (s->needsDrainage()) { ------------------ | Branch (241:13): [True: 40.6k, False: 64.7k] ------------------ 242| 40.6k| unlinkDrainableSubscriber(s); 243| 40.6k| } 244| | 245| 105k| delete s; 246| 105k| } _ZN3uWS9TopicTreeINS_16TopicTreeMessageENS_19TopicTreeBigMessageEE16createSubscriberEv: 217| 105k| Subscriber *createSubscriber() { 218| 105k| return new Subscriber(); 219| 105k| } _ZN3uWS10SubscriberC2Ev: 53| 105k| Subscriber() = default; _ZN3uWS9TopicTreeINS_16TopicTreeMessageENS_19TopicTreeBigMessageEE9subscribeEPNS_10SubscriberENSt3__117basic_string_viewIcNS6_11char_traitsIcEEEE: 161| 10.5M| Topic *subscribe(Subscriber *s, std::string_view topic) { 162| | /* Notify user that they are doing something wrong here */ 163| 10.5M| checkIteratingSubscriber(s); 164| | 165| | /* Lookup or create new topic */ 166| 10.5M| Topic *topicPtr = lookupTopic(topic); 167| 10.5M| if (!topicPtr) { ------------------ | Branch (167:13): [True: 10.5M, False: 0] ------------------ 168| 10.5M| Topic *newTopic = new Topic(topic); 169| 10.5M| topics.insert({std::string_view(newTopic->name.data(), newTopic->name.length()), std::unique_ptr(newTopic)}); 170| 10.5M| topicPtr = newTopic; 171| 10.5M| } 172| | 173| | /* Insert us in topic, insert topic in us */ 174| 10.5M| auto [it, inserted] = s->topics.insert(topicPtr); 175| 10.5M| if (!inserted) { ------------------ | Branch (175:13): [True: 0, False: 10.5M] ------------------ 176| 0| return nullptr; 177| 0| } 178| 10.5M| topicPtr->insert(s); 179| | 180| | /* Success */ 181| 10.5M| return topicPtr; 182| 10.5M| } _ZN3uWS9TopicTreeINS_16TopicTreeMessageENS_19TopicTreeBigMessageEE24checkIteratingSubscriberEPNS_10SubscriberE: 104| 10.5M| void checkIteratingSubscriber(Subscriber *s) { 105| | /* Notify user that they are doing something wrong here */ 106| 10.5M| if (iteratingSubscriber == s) { ------------------ | Branch (106:13): [True: 0, False: 10.5M] ------------------ 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| 10.5M| } _ZN3uWS9TopicTreeINS_16TopicTreeMessageENS_19TopicTreeBigMessageEE11lookupTopicENSt3__117basic_string_viewIcNS4_11char_traitsIcEEEE: 152| 10.5M| Topic *lookupTopic(std::string_view topic) { 153| 10.5M| auto it = topics.find(topic); 154| 10.5M| if (it == topics.end()) { ------------------ | Branch (154:13): [True: 10.5M, False: 0] ------------------ 155| 10.5M| return nullptr; 156| 10.5M| } 157| 0| return it->second.get(); 158| 10.5M| } _ZN3uWS5TopicC2ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE: 40| 10.5M| Topic(std::string_view topic) : name(topic) { 41| | 42| 10.5M| } _ZN3uWS9TopicTreeINS_16TopicTreeMessageENS_19TopicTreeBigMessageEE7publishEPNS_10SubscriberENSt3__117basic_string_viewIcNS6_11char_traitsIcEEEEOS1_: 304| 1.07M| bool publish(Subscriber *sender, std::string_view topic, T &&message) { 305| | /* Do we even have this topic? */ 306| 1.07M| auto it = topics.find(topic); 307| 1.07M| if (it == topics.end()) { ------------------ | Branch (307:13): [True: 0, False: 1.07M] ------------------ 308| 0| return false; 309| 0| } 310| | 311| | /* If we have more than 65k messages we need to drain every socket. */ 312| 1.07M| if (outgoingMessages.size() == UINT16_MAX) { ------------------ | Branch (312:13): [True: 4, False: 1.07M] ------------------ 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| 4| drain(); 316| 4| } 317| | 318| | /* If nobody references this message, don't buffer it */ 319| 1.07M| bool referencedMessage = false; 320| | 321| | /* For all subscribers in topic */ 322| 1.07M| for (Subscriber *s : *it->second) { ------------------ | Branch (322:28): [True: 1.07M, False: 1.07M] ------------------ 323| | 324| | /* If we are sender then ignore us */ 325| 1.07M| if (sender != s) { ------------------ | Branch (325:17): [True: 1.07M, False: 0] ------------------ 326| | 327| | /* At least one subscriber wants this message */ 328| 1.07M| referencedMessage = true; 329| | 330| | /* If we already have too many outgoing messages on this subscriber, drain it now */ 331| 1.07M| if (s->numMessageIndices == 32) { ------------------ | Branch (331:21): [True: 485, False: 1.07M] ------------------ 332| | /* This one does not need to check needsDrainage here but still does. */ 333| 485| drain(s); 334| 485| } 335| | 336| | /* Finally we can continue */ 337| 1.07M| s->messageIndices[s->numMessageIndices++] = (uint16_t)outgoingMessages.size(); 338| | /* First message adds subscriber to list of drainable subscribers */ 339| 1.07M| if (s->numMessageIndices == 1) { ------------------ | Branch (339:21): [True: 50.3k, False: 1.02M] ------------------ 340| | /* Insert us in the head of drainable subscribers */ 341| 50.3k| s->next = drainableSubscribers; 342| 50.3k| s->prev = nullptr; 343| 50.3k| if (s->next) { ------------------ | Branch (343:25): [True: 1.14k, False: 49.2k] ------------------ 344| 1.14k| s->next->prev = s; 345| 1.14k| } 346| 50.3k| drainableSubscribers = s; 347| 50.3k| } 348| 1.07M| } 349| 1.07M| } 350| | 351| | /* Push this message and return with success */ 352| 1.07M| if (referencedMessage) { ------------------ | Branch (352:13): [True: 1.07M, False: 0] ------------------ 353| 1.07M| outgoingMessages.emplace_back(message); 354| 1.07M| } 355| | 356| | /* Success if someone wants it */ 357| 1.07M| return referencedMessage; 358| 1.07M| } _ZN3uWS5utils6u64toaEmPc: 46| 19.5k|inline int u64toa(uint64_t value, char *dst) { 47| 19.5k| char temp[20]; 48| 19.5k| char *p = temp; 49| 39.1k| do { 50| 39.1k| *p++ = (char) ((value % 10) + '0'); 51| 39.1k| value /= 10; 52| 39.1k| } while (value > 0); ------------------ | Branch (52:14): [True: 19.5k, False: 19.5k] ------------------ 53| | 54| 19.5k| int ret = (int) (p - temp); 55| | 56| 39.1k| do { 57| 39.1k| *dst++ = *--p; 58| 39.1k| } while (p != temp); ------------------ | Branch (58:14): [True: 19.5k, False: 19.5k] ------------------ 59| | 60| 19.5k| return ret; 61| 19.5k|} _ZN3uWS9WebSocketILb1ELb1EiE4sendENSt3__117basic_string_viewIcNS2_11char_traitsIcEEEENS_6OpCodeEbb: 92| 50.2k| SendStatus send(std::string_view message, OpCode opCode = OpCode::BINARY, bool compress = false, bool fin = true) { 93| 50.2k| WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, 94| 50.2k| (us_socket_context_t *) us_socket_context(SSL, (us_socket_t *) this) 95| 50.2k| ); 96| | 97| | /* Skip sending and report success if we are over the limit of maxBackpressure */ 98| 50.2k| if (webSocketContextData->maxBackpressure && webSocketContextData->maxBackpressure < getBufferedAmount()) { ------------------ | Branch (98:13): [True: 50.2k, False: 0] | Branch (98:54): [True: 495, False: 49.7k] ------------------ 99| | /* Also defer a close if we should */ 100| 495| if (webSocketContextData->closeOnBackpressureLimit) { ------------------ | Branch (100:17): [True: 0, False: 495] ------------------ 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| 495| if (webSocketContextData->droppedHandler) { ------------------ | Branch (105:17): [True: 0, False: 495] ------------------ 106| 0| webSocketContextData->droppedHandler(this, message, opCode); 107| 0| } 108| | 109| 495| return DROPPED; 110| 495| } 111| | 112| | /* If we are subscribers and have messages to drain we need to drain them here to stay synced */ 113| 49.7k| WebSocketData *webSocketData = (WebSocketData *) Super::getAsyncSocketData(); 114| | 115| | /* Special path for long sends of non-compressed, non-SSL messages */ 116| 49.7k| if (message.length() >= 16 * 1024 && !compress && !SSL && !webSocketData->subscriber && getBufferedAmount() == 0 && Super::getLoopData()->corkOffset == 0) { ------------------ | Branch (116:13): [True: 0, False: 49.7k] | 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| 49.7k| } else { 136| | 137| 49.7k| if (webSocketData->subscriber) { ------------------ | Branch (137:17): [True: 49.7k, False: 0] ------------------ 138| | /* This will call back into us, send. */ 139| 49.7k| webSocketContextData->topicTree->drain(webSocketData->subscriber); 140| 49.7k| } 141| | 142| | /* Transform the message to compressed domain if requested */ 143| 49.7k| if (compress) { ------------------ | Branch (143:17): [True: 0, False: 49.7k] ------------------ 144| 0| WebSocketData *webSocketData = (WebSocketData *) Super::getAsyncSocketData(); 145| | 146| | /* Check and correct the compress hint. It is never valid to compress 0 bytes */ 147| 0| if (message.length() && opCode < 3 && webSocketData->compressionStatus == WebSocketData::ENABLED) { ------------------ | Branch (147:21): [True: 0, False: 0] | Branch (147:41): [True: 0, False: 0] | Branch (147:55): [True: 0, False: 0] ------------------ 148| 0| LoopData *loopData = Super::getLoopData(); 149| | /* Compress using either shared or dedicated deflationStream */ 150| 0| if (webSocketData->deflationStream) { ------------------ | Branch (150:25): [True: 0, False: 0] ------------------ 151| 0| message = webSocketData->deflationStream->deflate(loopData->zlibContext, message, false); 152| 0| } else { 153| 0| message = loopData->deflationStream->deflate(loopData->zlibContext, message, true); 154| 0| } 155| 0| } else { 156| 0| compress = false; 157| 0| } 158| 0| } 159| | 160| | /* Get size, allocate size, write if needed */ 161| 49.7k| size_t messageFrameSize = protocol::messageFrameSize(message.length()); 162| 49.7k| auto [sendBuffer, sendBufferAttribute] = Super::getSendBuffer(messageFrameSize); 163| 49.7k| protocol::formatMessage(sendBuffer, message.data(), message.length(), opCode, message.length(), compress, fin); 164| | 165| | /* Depending on size of message we have different paths */ 166| 49.7k| if (sendBufferAttribute == SendBufferAttribute::NEEDS_DRAIN) { ------------------ | Branch (166:17): [True: 42.6k, False: 7.14k] ------------------ 167| | /* This is a drain */ 168| 42.6k| auto[written, failed] = Super::write(nullptr, 0); 169| 42.6k| if (failed) { ------------------ | Branch (169:21): [True: 41.6k, False: 979] ------------------ 170| | /* Return false for failure, skipping to reset the timeout below */ 171| 41.6k| return BACKPRESSURE; 172| 41.6k| } 173| 42.6k| } else if (sendBufferAttribute == SendBufferAttribute::NEEDS_UNCORK) { ------------------ | Branch (173:24): [True: 0, False: 7.14k] ------------------ 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| 49.7k| } 182| | 183| | /* Every successful send resets the timeout */ 184| 8.12k| if (webSocketContextData->resetIdleTimeoutOnSend) { ------------------ | Branch (184:13): [True: 8.12k, False: 0] ------------------ 185| 8.12k| Super::timeout(webSocketContextData->idleTimeoutComponents.first); 186| 8.12k| WebSocketData *webSocketData = (WebSocketData *) Super::getAsyncSocketData(); 187| 8.12k| webSocketData->hasTimedOut = false; 188| 8.12k| } 189| | 190| | /* Return success */ 191| 8.12k| return SUCCESS; 192| 49.7k| } EpollEchoServerPubSub.cpp:_ZN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataE3endEiNSt3__117basic_string_viewIcNS3_11char_traitsIcEEEE: 196| 8.76k| void end(int code = 0, std::string_view message = {}) { 197| | /* Check if we already called this one */ 198| 8.76k| WebSocketData *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) this); 199| 8.76k| if (webSocketData->isShuttingDown) { ------------------ | Branch (199:13): [True: 0, False: 8.76k] ------------------ 200| 0| return; 201| 0| } 202| | 203| | /* We postpone any FIN sending to either drainage or uncorking */ 204| 8.76k| webSocketData->isShuttingDown = true; 205| | 206| | /* Format and send the close frame */ 207| 8.76k| static const int MAX_CLOSE_PAYLOAD = 123; 208| 8.76k| size_t length = std::min(MAX_CLOSE_PAYLOAD, message.length()); 209| 8.76k| char closePayload[MAX_CLOSE_PAYLOAD + 2]; 210| 8.76k| size_t closePayloadLength = protocol::formatClosePayload(closePayload, (uint16_t) code, message.data(), length); 211| 8.76k| bool ok = send(std::string_view(closePayload, closePayloadLength), OpCode::CLOSE); 212| | 213| | /* FIN if we are ok and not corked */ 214| 8.76k| if (!this->isCorked()) { ------------------ | Branch (214:13): [True: 680, False: 8.08k] ------------------ 215| 680| if (ok) { ------------------ | Branch (215:17): [True: 348, False: 332] ------------------ 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| 348| this->shutdown(); 219| 348| } 220| 680| } 221| | 222| 8.76k| WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, 223| 8.76k| (us_socket_context_t *) us_socket_context(SSL, (us_socket_t *) this) 224| 8.76k| ); 225| | 226| | /* Set shorter timeout (use ping-timeout) to avoid long hanging sockets after end() on broken connections */ 227| 8.76k| 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| 8.76k| if (webSocketData->subscriber && webSocketContextData->subscriptionHandler) { ------------------ | Branch (230:13): [True: 8.76k, False: 0] | Branch (230:42): [True: 0, False: 8.76k] ------------------ 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| 8.76k| webSocketContextData->topicTree->freeSubscriber(webSocketData->subscriber); 238| 8.76k| webSocketData->subscriber = nullptr; 239| | 240| | /* Emit close event */ 241| 8.76k| if (webSocketContextData->closeHandler) { ------------------ | Branch (241:13): [True: 8.76k, False: 0] ------------------ 242| 8.76k| webSocketContextData->closeHandler(this, code, message); 243| 8.76k| } 244| 8.76k| } EpollEchoServerPubSub.cpp:_ZN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataE4sendENSt3__117basic_string_viewIcNS3_11char_traitsIcEEEENS_6OpCodeEbb: 92| 13.7k| SendStatus send(std::string_view message, OpCode opCode = OpCode::BINARY, bool compress = false, bool fin = true) { 93| 13.7k| WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, 94| 13.7k| (us_socket_context_t *) us_socket_context(SSL, (us_socket_t *) this) 95| 13.7k| ); 96| | 97| | /* Skip sending and report success if we are over the limit of maxBackpressure */ 98| 13.7k| if (webSocketContextData->maxBackpressure && webSocketContextData->maxBackpressure < getBufferedAmount()) { ------------------ | Branch (98:13): [True: 13.7k, False: 0] | Branch (98:54): [True: 306, False: 13.4k] ------------------ 99| | /* Also defer a close if we should */ 100| 306| if (webSocketContextData->closeOnBackpressureLimit) { ------------------ | Branch (100:17): [True: 0, False: 306] ------------------ 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| 306| if (webSocketContextData->droppedHandler) { ------------------ | Branch (105:17): [True: 0, False: 306] ------------------ 106| 0| webSocketContextData->droppedHandler(this, message, opCode); 107| 0| } 108| | 109| 306| return DROPPED; 110| 306| } 111| | 112| | /* If we are subscribers and have messages to drain we need to drain them here to stay synced */ 113| 13.4k| WebSocketData *webSocketData = (WebSocketData *) Super::getAsyncSocketData(); 114| | 115| | /* Special path for long sends of non-compressed, non-SSL messages */ 116| 13.4k| if (message.length() >= 16 * 1024 && !compress && !SSL && !webSocketData->subscriber && getBufferedAmount() == 0 && Super::getLoopData()->corkOffset == 0) { ------------------ | Branch (116:13): [True: 0, False: 13.4k] | 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| 13.4k| } else { 136| | 137| 13.4k| if (webSocketData->subscriber) { ------------------ | Branch (137:17): [True: 13.4k, False: 0] ------------------ 138| | /* This will call back into us, send. */ 139| 13.4k| webSocketContextData->topicTree->drain(webSocketData->subscriber); 140| 13.4k| } 141| | 142| | /* Transform the message to compressed domain if requested */ 143| 13.4k| if (compress) { ------------------ | Branch (143:17): [True: 0, False: 13.4k] ------------------ 144| 0| WebSocketData *webSocketData = (WebSocketData *) Super::getAsyncSocketData(); 145| | 146| | /* Check and correct the compress hint. It is never valid to compress 0 bytes */ 147| 0| if (message.length() && opCode < 3 && webSocketData->compressionStatus == WebSocketData::ENABLED) { ------------------ | Branch (147:21): [True: 0, False: 0] | Branch (147:41): [True: 0, False: 0] | Branch (147:55): [True: 0, False: 0] ------------------ 148| 0| LoopData *loopData = Super::getLoopData(); 149| | /* Compress using either shared or dedicated deflationStream */ 150| 0| if (webSocketData->deflationStream) { ------------------ | Branch (150:25): [True: 0, False: 0] ------------------ 151| 0| message = webSocketData->deflationStream->deflate(loopData->zlibContext, message, false); 152| 0| } else { 153| 0| message = loopData->deflationStream->deflate(loopData->zlibContext, message, true); 154| 0| } 155| 0| } else { 156| 0| compress = false; 157| 0| } 158| 0| } 159| | 160| | /* Get size, allocate size, write if needed */ 161| 13.4k| size_t messageFrameSize = protocol::messageFrameSize(message.length()); 162| 13.4k| auto [sendBuffer, sendBufferAttribute] = Super::getSendBuffer(messageFrameSize); 163| 13.4k| protocol::formatMessage(sendBuffer, message.data(), message.length(), opCode, message.length(), compress, fin); 164| | 165| | /* Depending on size of message we have different paths */ 166| 13.4k| if (sendBufferAttribute == SendBufferAttribute::NEEDS_DRAIN) { ------------------ | Branch (166:17): [True: 11.8k, False: 1.55k] ------------------ 167| | /* This is a drain */ 168| 11.8k| auto[written, failed] = Super::write(nullptr, 0); 169| 11.8k| if (failed) { ------------------ | Branch (169:21): [True: 10.9k, False: 867] ------------------ 170| | /* Return false for failure, skipping to reset the timeout below */ 171| 10.9k| return BACKPRESSURE; 172| 10.9k| } 173| 11.8k| } else if (sendBufferAttribute == SendBufferAttribute::NEEDS_UNCORK) { ------------------ | Branch (173:24): [True: 1.09k, False: 456] ------------------ 174| | /* Uncork if we came here uncorked */ 175| 1.09k| auto [written, failed] = Super::uncork(); 176| 1.09k| if (failed) { ------------------ | Branch (176:21): [True: 614, False: 485] ------------------ 177| 614| return BACKPRESSURE; 178| 614| } 179| 1.09k| } 180| | 181| 13.4k| } 182| | 183| | /* Every successful send resets the timeout */ 184| 1.80k| if (webSocketContextData->resetIdleTimeoutOnSend) { ------------------ | Branch (184:13): [True: 1.80k, False: 0] ------------------ 185| 1.80k| Super::timeout(webSocketContextData->idleTimeoutComponents.first); 186| 1.80k| WebSocketData *webSocketData = (WebSocketData *) Super::getAsyncSocketData(); 187| 1.80k| webSocketData->hasTimedOut = false; 188| 1.80k| } 189| | 190| | /* Return success */ 191| 1.80k| return SUCCESS; 192| 13.4k| } EpollEchoServerPubSub.cpp:_ZN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataE11getUserDataEv: 44| 1.39M| USERDATA *getUserData() { 45| 1.39M| WebSocketData *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) this); 46| | /* We just have it overallocated by sizeof type */ 47| 1.39M| return (USERDATA *) (webSocketData + 1); 48| 1.39M| } EpollEchoServerPubSub.cpp:_ZN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataE4initEbNS_15CompressOptionsEONS_12BackPressureE: 37| 105k| void *init(bool perMessageDeflate, CompressOptions compressOptions, BackPressure &&backpressure) { 38| 105k| new (us_socket_ext(SSL, (us_socket_t *) this)) WebSocketData(perMessageDeflate, compressOptions, std::move(backpressure)); 39| 105k| return this; 40| 105k| } EpollEchoServerPubSub.cpp:_ZN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataE9subscribeENSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEb: 264| 10.5M| bool subscribe(std::string_view topic, bool = false) { 265| 10.5M| WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, 266| 10.5M| (us_socket_context_t *) us_socket_context(SSL, (us_socket_t *) this) 267| 10.5M| ); 268| | 269| | /* Make us a subscriber if we aren't yet */ 270| 10.5M| WebSocketData *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) this); 271| 10.5M| if (!webSocketData->subscriber) { ------------------ | Branch (271:13): [True: 105k, False: 10.4M] ------------------ 272| 105k| webSocketData->subscriber = webSocketContextData->topicTree->createSubscriber(); 273| 105k| webSocketData->subscriber->user = this; 274| 105k| } 275| | 276| | /* Cannot return numSubscribers as this is only for this particular websocket context */ 277| 10.5M| Topic *topicOrNull = webSocketContextData->topicTree->subscribe(webSocketData->subscriber, topic); 278| 10.5M| if (topicOrNull && webSocketContextData->subscriptionHandler) { ------------------ | Branch (278:13): [True: 10.5M, False: 0] | Branch (278:28): [True: 0, False: 10.5M] ------------------ 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| 10.5M| return true; 285| 10.5M| } EpollEchoServerPubSub.cpp:_ZN3uWS16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataE6createEPNS_4LoopEP19us_socket_context_tPNS_9TopicTreeINS_16TopicTreeMessageENS_19TopicTreeBigMessageEEE: 420| 5.39k| static WebSocketContext *create(Loop */*loop*/, us_socket_context_t *parentSocketContext, TopicTree *topicTree) { 421| 5.39k| WebSocketContext *webSocketContext = (WebSocketContext *) us_create_child_socket_context(SSL, parentSocketContext, sizeof(WebSocketContextData)); 422| 5.39k| if (!webSocketContext) { ------------------ | Branch (422:13): [True: 0, False: 5.39k] ------------------ 423| 0| return nullptr; 424| 0| } 425| | 426| | /* Init socket context data */ 427| 5.39k| new ((WebSocketContextData *) us_socket_context_ext(SSL, (us_socket_context_t *)webSocketContext)) WebSocketContextData(topicTree); 428| 5.39k| return webSocketContext->init(); 429| 5.39k| } EpollEchoServerPubSub.cpp:_ZN3uWS16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataE4initEv: 248| 5.39k| 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| 5.39k| 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| 5.39k| WebSocketData *webSocketData = (WebSocketData *) (us_socket_ext(SSL, s)); 257| 5.39k| if (!webSocketData->isShuttingDown) { 258| | /* Emit close event */ 259| 5.39k| 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| 5.39k| if (webSocketData->subscriber && webSocketContextData->subscriptionHandler) { 263| 5.39k| for (Topic *t : webSocketData->subscriber->topics) { 264| 5.39k| webSocketContextData->subscriptionHandler((WebSocket *) s, t->name, (int) t->size() - 1, (int) t->size()); 265| 5.39k| } 266| 5.39k| } 267| | 268| | /* Make sure to unsubscribe from any pub/sub node at exit */ 269| 5.39k| webSocketContextData->topicTree->freeSubscriber(webSocketData->subscriber); 270| 5.39k| webSocketData->subscriber = nullptr; 271| | 272| 5.39k| if (webSocketContextData->closeHandler) { 273| 5.39k| webSocketContextData->closeHandler((WebSocket *) s, 1006, {(char *) reason, (size_t) code}); 274| 5.39k| } 275| 5.39k| } 276| | 277| | /* Destruct in-placed data struct */ 278| 5.39k| webSocketData->~WebSocketData(); 279| | 280| 5.39k| return s; 281| 5.39k| }); 282| | 283| | /* Handle WebSocket data streams */ 284| 5.39k| us_socket_context_on_data(SSL, getSocketContext(), [](auto *s, char *data, int length) { 285| | 286| | /* We need the websocket data */ 287| 5.39k| 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| 5.39k| if (webSocketData->isShuttingDown) { 292| 5.39k| return s; 293| 5.39k| } 294| | 295| 5.39k| auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); 296| 5.39k| auto *asyncSocket = (AsyncSocket *) s; 297| | 298| | /* Every time we get data and not in shutdown state we simply reset the timeout */ 299| 5.39k| asyncSocket->timeout(webSocketContextData->idleTimeoutComponents.first); 300| 5.39k| webSocketData->hasTimedOut = false; 301| | 302| | /* We always cork on data */ 303| 5.39k| asyncSocket->cork(); 304| | 305| | /* This parser has virtually no overhead */ 306| 5.39k| WebSocketProtocol>::consume(data, (unsigned int) length, (WebSocketState *) webSocketData, s); 307| | 308| | /* Uncorking a closed socekt is fine, in fact it is needed */ 309| 5.39k| asyncSocket->uncork(); 310| | 311| | /* If uncorking was successful and we are in shutdown state then send TCP FIN */ 312| 5.39k| if (asyncSocket->getBufferedAmount() == 0) { 313| | /* We can now be in shutdown state */ 314| 5.39k| if (webSocketData->isShuttingDown) { 315| | /* Shutting down a closed socket is handled by uSockets and just fine */ 316| 5.39k| asyncSocket->shutdown(); 317| 5.39k| } 318| 5.39k| } 319| | 320| 5.39k| return s; 321| 5.39k| }); 322| | 323| | /* Handle HTTP write out (note: SSL_read may trigger this spuriously, the app need to handle spurious calls) */ 324| 5.39k| 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| 5.39k| if (us_socket_is_shut_down(SSL, (us_socket_t *) s)) { 332| 5.39k| return s; 333| 5.39k| } 334| | 335| 5.39k| AsyncSocket *asyncSocket = (AsyncSocket *) s; 336| 5.39k| 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| 5.39k| unsigned int backpressure = asyncSocket->getBufferedAmount(); 341| | 342| | /* Drain as much as possible */ 343| 5.39k| 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| 5.39k| if (!backpressure || backpressure > asyncSocket->getBufferedAmount()) { 348| 5.39k| auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); 349| 5.39k| asyncSocket->timeout(webSocketContextData->idleTimeoutComponents.first); 350| 5.39k| webSocketData->hasTimedOut = false; 351| 5.39k| } 352| | 353| | /* Are we in (WebSocket) shutdown mode? */ 354| 5.39k| if (webSocketData->isShuttingDown) { 355| | /* Check if we just now drained completely */ 356| 5.39k| if (asyncSocket->getBufferedAmount() == 0) { 357| | /* Now perform the actual TCP/TLS shutdown which was postponed due to backpressure */ 358| 5.39k| asyncSocket->shutdown(); 359| 5.39k| } 360| 5.39k| } else if (!backpressure || backpressure > asyncSocket->getBufferedAmount()) { 361| | /* Only call drain if we actually drained backpressure or if we came here with 0 backpressure */ 362| 5.39k| auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); 363| 5.39k| if (webSocketContextData->drainHandler) { 364| 5.39k| webSocketContextData->drainHandler((WebSocket *) s); 365| 5.39k| } 366| | /* No need to check for closed here as we leave the handler immediately*/ 367| 5.39k| } 368| | 369| 5.39k| return s; 370| 5.39k| }); 371| | 372| | /* Handle FIN, HTTP does not support half-closed sockets, so simply close */ 373| 5.39k| us_socket_context_on_end(SSL, getSocketContext(), [](auto *s) { 374| | 375| | /* If we get a fin, we just close I guess */ 376| 5.39k| us_socket_close(SSL, (us_socket_t *) s, 0, nullptr); 377| | 378| 5.39k| return s; 379| 5.39k| }); 380| | 381| 5.39k| us_socket_context_on_long_timeout(SSL, getSocketContext(), [](auto *s) { 382| 5.39k| ((WebSocket *) s)->end(1000, "please reconnect"); 383| | 384| 5.39k| return s; 385| 5.39k| }); 386| | 387| | /* Handle socket timeouts, simply close them so to not confuse client with FIN */ 388| 5.39k| us_socket_context_on_timeout(SSL, getSocketContext(), [](auto *s) { 389| | 390| 5.39k| auto *webSocketData = (WebSocketData *)(us_socket_ext(SSL, s)); 391| 5.39k| auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); 392| | 393| 5.39k| if (webSocketContextData->sendPingsAutomatically && !webSocketData->isShuttingDown && !webSocketData->hasTimedOut) { 394| 5.39k| webSocketData->hasTimedOut = true; 395| 5.39k| us_socket_timeout(SSL, s, webSocketContextData->idleTimeoutComponents.second); 396| | /* Send ping without being corked */ 397| 5.39k| ((AsyncSocket *) s)->write("\x89\x00", 2); 398| 5.39k| return s; 399| 5.39k| } 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| 5.39k| forceClose(nullptr, s, ERR_WEBSOCKET_TIMEOUT); 404| | 405| 5.39k| return s; 406| 5.39k| }); 407| | 408| 5.39k| return this; 409| 5.39k| } EpollEchoServerPubSub.cpp:_ZZN3uWS16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataE4initEvENKUlPT_iPvE_clI11us_socket_tEEDaS4_iS5_: 254| 105k| 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| 105k| WebSocketData *webSocketData = (WebSocketData *) (us_socket_ext(SSL, s)); 257| 105k| if (!webSocketData->isShuttingDown) { ------------------ | Branch (257:17): [True: 96.6k, False: 8.76k] ------------------ 258| | /* Emit close event */ 259| 96.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| 96.6k| if (webSocketData->subscriber && webSocketContextData->subscriptionHandler) { ------------------ | Branch (262:21): [True: 96.6k, False: 0] | Branch (262:50): [True: 0, False: 96.6k] ------------------ 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| 96.6k| webSocketContextData->topicTree->freeSubscriber(webSocketData->subscriber); 270| 96.6k| webSocketData->subscriber = nullptr; 271| | 272| 96.6k| if (webSocketContextData->closeHandler) { ------------------ | Branch (272:21): [True: 96.6k, False: 0] ------------------ 273| 96.6k| webSocketContextData->closeHandler((WebSocket *) s, 1006, {(char *) reason, (size_t) code}); 274| 96.6k| } 275| 96.6k| } 276| | 277| | /* Destruct in-placed data struct */ 278| 105k| webSocketData->~WebSocketData(); 279| | 280| 105k| return s; 281| 105k| }); EpollEchoServerPubSub.cpp:_ZZN3uWS16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataE4initEvENKUlPT_PciE_clI11us_socket_tEEDaS4_S5_i: 284| 96.8k| us_socket_context_on_data(SSL, getSocketContext(), [](auto *s, char *data, int length) { 285| | 286| | /* We need the websocket data */ 287| 96.8k| 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| 96.8k| if (webSocketData->isShuttingDown) { ------------------ | Branch (291:17): [True: 1.17k, False: 95.6k] ------------------ 292| 1.17k| return s; 293| 1.17k| } 294| | 295| 95.6k| auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); 296| 95.6k| auto *asyncSocket = (AsyncSocket *) s; 297| | 298| | /* Every time we get data and not in shutdown state we simply reset the timeout */ 299| 95.6k| asyncSocket->timeout(webSocketContextData->idleTimeoutComponents.first); 300| 95.6k| webSocketData->hasTimedOut = false; 301| | 302| | /* We always cork on data */ 303| 95.6k| asyncSocket->cork(); 304| | 305| | /* This parser has virtually no overhead */ 306| 95.6k| WebSocketProtocol>::consume(data, (unsigned int) length, (WebSocketState *) webSocketData, s); 307| | 308| | /* Uncorking a closed socekt is fine, in fact it is needed */ 309| 95.6k| asyncSocket->uncork(); 310| | 311| | /* If uncorking was successful and we are in shutdown state then send TCP FIN */ 312| 95.6k| if (asyncSocket->getBufferedAmount() == 0) { ------------------ | Branch (312:17): [True: 6.50k, False: 89.1k] ------------------ 313| | /* We can now be in shutdown state */ 314| 6.50k| if (webSocketData->isShuttingDown) { ------------------ | Branch (314:21): [True: 1.58k, False: 4.92k] ------------------ 315| | /* Shutting down a closed socket is handled by uSockets and just fine */ 316| 1.58k| asyncSocket->shutdown(); 317| 1.58k| } 318| 6.50k| } 319| | 320| 95.6k| return s; 321| 96.8k| }); EpollEchoServerPubSub.cpp:_ZN3uWS16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataE13setCompressedEPNS_14WebSocketStateILb1EEEPv: 44| 18.1k| static bool setCompressed(WebSocketState */*wState*/, void *s) { 45| 18.1k| WebSocketData *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) s); 46| | 47| 18.1k| if (webSocketData->compressionStatus == WebSocketData::CompressionStatus::ENABLED) { ------------------ | Branch (47:13): [True: 0, False: 18.1k] ------------------ 48| 0| webSocketData->compressionStatus = WebSocketData::CompressionStatus::COMPRESSED_FRAME; 49| 0| return true; 50| 18.1k| } else { 51| 18.1k| return false; 52| 18.1k| } 53| 18.1k| } EpollEchoServerPubSub.cpp:_ZN3uWS16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataE10forceCloseEPNS_14WebSocketStateILb1EEEPvNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEE: 55| 58.4k| static void forceClose(WebSocketState */*wState*/, void *s, std::string_view reason = {}) { 56| 58.4k| us_socket_close(SSL, (us_socket_t *) s, (int) reason.length(), (void *) reason.data()); 57| 58.4k| } EpollEchoServerPubSub.cpp:_ZN3uWS16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataE19refusePayloadLengthEmPNS_14WebSocketStateILb1EEEPv: 241| 1.15M| static bool refusePayloadLength(uint64_t length, WebSocketState */*wState*/, void *s) { 242| 1.15M| 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| 1.15M| return webSocketContextData->maxPayloadLength < length; 246| 1.15M| } EpollEchoServerPubSub.cpp:_ZN3uWS16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataE14handleFragmentEPcmjibPNS_14WebSocketStateILb1EEEPv: 60| 1.13M| static bool handleFragment(char *data, size_t length, unsigned int remainingBytes, int opCode, bool fin, WebSocketState *webSocketState, void *s) { 61| | /* WebSocketData and WebSocketContextData */ 62| 1.13M| WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); 63| 1.13M| WebSocketData *webSocketData = (WebSocketData *) us_socket_ext(SSL, (us_socket_t *) s); 64| | 65| | /* Is this a non-control frame? */ 66| 1.13M| if (opCode < 3) { ------------------ | Branch (66:13): [True: 1.11M, False: 19.1k] ------------------ 67| | /* Did we get everything in one go? */ 68| 1.11M| if (!remainingBytes && fin && !webSocketData->fragmentBuffer.length()) { ------------------ | Branch (68:17): [True: 1.10M, False: 9.10k] | Branch (68:36): [True: 1.09M, False: 14.9k] | Branch (68:43): [True: 1.08M, False: 2.51k] ------------------ 69| | 70| | /* Handle compressed frame */ 71| 1.08M| if (webSocketData->compressionStatus == WebSocketData::CompressionStatus::COMPRESSED_FRAME) { ------------------ | Branch (71:21): [True: 0, False: 1.08M] ------------------ 72| 0| webSocketData->compressionStatus = WebSocketData::CompressionStatus::ENABLED; 73| | 74| 0| 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| 0| std::optional inflatedFrame; 77| 0| if (webSocketData->inflationStream) { ------------------ | Branch (77:29): [True: 0, False: 0] ------------------ 78| 0| inflatedFrame = webSocketData->inflationStream->inflate(loopData->zlibContext, {data, length}, webSocketContextData->maxPayloadLength, false); 79| 0| } else { 80| 0| inflatedFrame = loopData->inflationStream->inflate(loopData->zlibContext, {data, length}, webSocketContextData->maxPayloadLength, true); 81| 0| } 82| | 83| 0| if (!inflatedFrame.has_value()) { ------------------ | Branch (83:29): [True: 0, False: 0] ------------------ 84| 0| forceClose(webSocketState, s, ERR_TOO_BIG_MESSAGE_INFLATION); 85| 0| return true; 86| 0| } else { 87| 0| data = (char *) inflatedFrame->data(); 88| 0| length = inflatedFrame->length(); 89| 0| } 90| 0| } 91| | 92| | /* Check text messages for Utf-8 validity */ 93| 1.08M| if (opCode == 1 && !protocol::isValidUtf8((unsigned char *) data, length)) { ------------------ | Branch (93:21): [True: 1.07M, False: 7.88k] | Branch (93:36): [True: 14.5k, False: 1.06M] ------------------ 94| 14.5k| forceClose(webSocketState, s, ERR_INVALID_TEXT); 95| 14.5k| return true; 96| 14.5k| } 97| | 98| | /* Emit message event & break if we are closed or shut down when returning */ 99| 1.07M| if (webSocketContextData->messageHandler) { ------------------ | Branch (99:21): [True: 1.07M, False: 0] ------------------ 100| 1.07M| webSocketContextData->messageHandler((WebSocket *) s, std::string_view(data, length), (OpCode) opCode); 101| 1.07M| if (us_socket_is_closed(SSL, (us_socket_t *) s) || webSocketData->isShuttingDown) { ------------------ | Branch (101:25): [True: 0, False: 1.07M] | Branch (101:72): [True: 0, False: 1.07M] ------------------ 102| 0| return true; 103| 0| } 104| 1.07M| } 105| 1.07M| } else { 106| | /* Allocate fragment buffer up front first time */ 107| 26.5k| if (!webSocketData->fragmentBuffer.length()) { ------------------ | Branch (107:21): [True: 17.6k, False: 8.92k] ------------------ 108| 17.6k| webSocketData->fragmentBuffer.reserve(length + remainingBytes); 109| 17.6k| } 110| | /* Fragments forming a big message are not caught until appending them */ 111| 26.5k| if (refusePayloadLength(length + webSocketData->fragmentBuffer.length(), webSocketState, s)) { ------------------ | Branch (111:21): [True: 239, False: 26.3k] ------------------ 112| 239| forceClose(webSocketState, s, ERR_TOO_BIG_MESSAGE); 113| 239| return true; 114| 239| } 115| 26.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| 26.3k| if (!remainingBytes && fin) { ------------------ | Branch (119:21): [True: 17.4k, False: 8.87k] | Branch (119:40): [True: 2.51k, False: 14.9k] ------------------ 120| | 121| | /* Handle compression */ 122| 2.51k| if (webSocketData->compressionStatus == WebSocketData::CompressionStatus::COMPRESSED_FRAME) { ------------------ | Branch (122:25): [True: 0, False: 2.51k] ------------------ 123| 0| webSocketData->compressionStatus = WebSocketData::CompressionStatus::ENABLED; 124| | 125| | /* 9 bytes of padding for libdeflate, 4 for zlib */ 126| 0| webSocketData->fragmentBuffer.append("123456789"); 127| | 128| 0| LoopData *loopData = (LoopData *) us_loop_ext( 129| 0| us_socket_context_loop(SSL, 130| 0| us_socket_context(SSL, (us_socket_t *) s) 131| 0| ) 132| 0| ); 133| | 134| | /* Decompress using shared or dedicated decompressor */ 135| 0| std::optional inflatedFrame; 136| 0| if (webSocketData->inflationStream) { ------------------ | Branch (136:33): [True: 0, False: 0] ------------------ 137| 0| inflatedFrame = webSocketData->inflationStream->inflate(loopData->zlibContext, {webSocketData->fragmentBuffer.data(), webSocketData->fragmentBuffer.length() - 9}, webSocketContextData->maxPayloadLength, false); 138| 0| } else { 139| 0| inflatedFrame = loopData->inflationStream->inflate(loopData->zlibContext, {webSocketData->fragmentBuffer.data(), webSocketData->fragmentBuffer.length() - 9}, webSocketContextData->maxPayloadLength, true); 140| 0| } 141| | 142| 0| if (!inflatedFrame.has_value()) { ------------------ | Branch (142:33): [True: 0, False: 0] ------------------ 143| 0| forceClose(webSocketState, s, ERR_TOO_BIG_MESSAGE_INFLATION); 144| 0| return true; 145| 0| } else { 146| 0| data = (char *) inflatedFrame->data(); 147| 0| length = inflatedFrame->length(); 148| 0| } 149| | 150| | 151| 2.51k| } else { 152| | // reset length and data ptrs 153| 2.51k| length = webSocketData->fragmentBuffer.length(); 154| 2.51k| data = webSocketData->fragmentBuffer.data(); 155| 2.51k| } 156| | 157| | /* Check text messages for Utf-8 validity */ 158| 2.51k| if (opCode == 1 && !protocol::isValidUtf8((unsigned char *) data, length)) { ------------------ | Branch (158:25): [True: 577, False: 1.93k] | Branch (158:40): [True: 291, False: 286] ------------------ 159| 291| forceClose(webSocketState, s, ERR_INVALID_TEXT); 160| 291| return true; 161| 291| } 162| | 163| | /* Emit message and check for shutdown or close */ 164| 2.22k| if (webSocketContextData->messageHandler) { ------------------ | Branch (164:25): [True: 2.22k, False: 0] ------------------ 165| 2.22k| webSocketContextData->messageHandler((WebSocket *) s, std::string_view(data, length), (OpCode) opCode); 166| 2.22k| if (us_socket_is_closed(SSL, (us_socket_t *) s) || webSocketData->isShuttingDown) { ------------------ | Branch (166:29): [True: 0, False: 2.22k] | Branch (166:76): [True: 0, False: 2.22k] ------------------ 167| 0| return true; 168| 0| } 169| 2.22k| } 170| | 171| | /* If we shutdown or closed, this will be taken care of elsewhere */ 172| 2.22k| webSocketData->fragmentBuffer.clear(); 173| 2.22k| } 174| 26.3k| } 175| 1.11M| } else { 176| | /* Control frames need the websocket to send pings, pongs and close */ 177| 19.1k| WebSocket *webSocket = (WebSocket *) s; 178| | 179| 19.1k| if (!remainingBytes && fin && !webSocketData->controlTipLength) { ------------------ | Branch (179:17): [True: 14.4k, False: 4.63k] | Branch (179:36): [True: 14.4k, False: 0] | Branch (179:43): [True: 11.1k, False: 3.39k] ------------------ 180| 11.1k| if (opCode == CLOSE) { ------------------ | Branch (180:21): [True: 6.22k, False: 4.88k] ------------------ 181| 6.22k| auto closeFrame = protocol::parseClosePayload(data, length); 182| 6.22k| webSocket->end(closeFrame.code, std::string_view(closeFrame.message, closeFrame.length)); 183| 6.22k| return true; 184| 6.22k| } else { 185| 4.88k| if (opCode == PING) { ------------------ | Branch (185:25): [True: 4.45k, False: 424] ------------------ 186| 4.45k| webSocket->send(std::string_view(data, length), (OpCode) OpCode::PONG); 187| 4.45k| if (webSocketContextData->pingHandler) { ------------------ | Branch (187:29): [True: 4.45k, False: 0] ------------------ 188| 4.45k| webSocketContextData->pingHandler(webSocket, {data, length}); 189| 4.45k| if (us_socket_is_closed(SSL, (us_socket_t *) s) || webSocketData->isShuttingDown) { ------------------ | Branch (189:33): [True: 0, False: 4.45k] | Branch (189:80): [True: 0, False: 4.45k] ------------------ 190| 0| return true; 191| 0| } 192| 4.45k| } 193| 4.45k| } else if (opCode == PONG) { ------------------ | Branch (193:32): [True: 424, False: 0] ------------------ 194| 424| if (webSocketContextData->pongHandler) { ------------------ | Branch (194:29): [True: 424, False: 0] ------------------ 195| 424| webSocketContextData->pongHandler(webSocket, {data, length}); 196| 424| if (us_socket_is_closed(SSL, (us_socket_t *) s) || webSocketData->isShuttingDown) { ------------------ | Branch (196:33): [True: 0, False: 424] | Branch (196:80): [True: 0, False: 424] ------------------ 197| 0| return true; 198| 0| } 199| 424| } 200| 424| } 201| 4.88k| } 202| 11.1k| } else { 203| | /* Here we never mind any size optimizations as we are in the worst possible path */ 204| 8.02k| webSocketData->fragmentBuffer.append(data, length); 205| 8.02k| webSocketData->controlTipLength += (unsigned int) length; 206| | 207| 8.02k| if (!remainingBytes && fin) { ------------------ | Branch (207:21): [True: 3.39k, False: 4.63k] | Branch (207:40): [True: 3.39k, False: 0] ------------------ 208| 3.39k| char *controlBuffer = (char *) webSocketData->fragmentBuffer.data() + webSocketData->fragmentBuffer.length() - webSocketData->controlTipLength; 209| 3.39k| if (opCode == CLOSE) { ------------------ | Branch (209:25): [True: 2.54k, False: 849] ------------------ 210| 2.54k| protocol::CloseFrame closeFrame = protocol::parseClosePayload(controlBuffer, webSocketData->controlTipLength); 211| 2.54k| webSocket->end(closeFrame.code, std::string_view(closeFrame.message, closeFrame.length)); 212| 2.54k| return true; 213| 2.54k| } else { 214| 849| if (opCode == PING) { ------------------ | Branch (214:29): [True: 485, False: 364] ------------------ 215| 485| webSocket->send(std::string_view(controlBuffer, webSocketData->controlTipLength), (OpCode) OpCode::PONG); 216| 485| if (webSocketContextData->pingHandler) { ------------------ | Branch (216:33): [True: 485, False: 0] ------------------ 217| 485| webSocketContextData->pingHandler(webSocket, std::string_view(controlBuffer, webSocketData->controlTipLength)); 218| 485| if (us_socket_is_closed(SSL, (us_socket_t *) s) || webSocketData->isShuttingDown) { ------------------ | Branch (218:37): [True: 0, False: 485] | Branch (218:84): [True: 0, False: 485] ------------------ 219| 0| return true; 220| 0| } 221| 485| } 222| 485| } else if (opCode == PONG) { ------------------ | Branch (222:36): [True: 364, False: 0] ------------------ 223| 364| if (webSocketContextData->pongHandler) { ------------------ | Branch (223:33): [True: 364, False: 0] ------------------ 224| 364| webSocketContextData->pongHandler(webSocket, std::string_view(controlBuffer, webSocketData->controlTipLength)); 225| 364| if (us_socket_is_closed(SSL, (us_socket_t *) s) || webSocketData->isShuttingDown) { ------------------ | Branch (225:37): [True: 0, False: 364] | Branch (225:84): [True: 0, False: 364] ------------------ 226| 0| return true; 227| 0| } 228| 364| } 229| 364| } 230| 849| } 231| | 232| | /* Same here, we do not care for any particular smart allocation scheme */ 233| 849| webSocketData->fragmentBuffer.resize((unsigned int) webSocketData->fragmentBuffer.length() - webSocketData->controlTipLength); 234| 849| webSocketData->controlTipLength = 0; 235| 849| } 236| 8.02k| } 237| 19.1k| } 238| 1.10M| return false; 239| 1.13M| } EpollEchoServerPubSub.cpp:_ZZN3uWS16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataE4initEvENKUlPT_E_clI11us_socket_tEEDaS4_: 324| 17.7k| 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| 17.7k| if (us_socket_is_shut_down(SSL, (us_socket_t *) s)) { ------------------ | Branch (331:17): [True: 0, False: 17.7k] ------------------ 332| 0| return s; 333| 0| } 334| | 335| 17.7k| AsyncSocket *asyncSocket = (AsyncSocket *) s; 336| 17.7k| 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| 17.7k| unsigned int backpressure = asyncSocket->getBufferedAmount(); 341| | 342| | /* Drain as much as possible */ 343| 17.7k| 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| 17.7k| if (!backpressure || backpressure > asyncSocket->getBufferedAmount()) { ------------------ | Branch (347:17): [True: 361, False: 17.3k] | Branch (347:34): [True: 11.6k, False: 5.72k] ------------------ 348| 12.0k| auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); 349| 12.0k| asyncSocket->timeout(webSocketContextData->idleTimeoutComponents.first); 350| 12.0k| webSocketData->hasTimedOut = false; 351| 12.0k| } 352| | 353| | /* Are we in (WebSocket) shutdown mode? */ 354| 17.7k| if (webSocketData->isShuttingDown) { ------------------ | Branch (354:17): [True: 2.72k, False: 15.0k] ------------------ 355| | /* Check if we just now drained completely */ 356| 2.72k| if (asyncSocket->getBufferedAmount() == 0) { ------------------ | Branch (356:21): [True: 1.02k, False: 1.69k] ------------------ 357| | /* Now perform the actual TCP/TLS shutdown which was postponed due to backpressure */ 358| 1.02k| asyncSocket->shutdown(); 359| 1.02k| } 360| 15.0k| } else if (!backpressure || backpressure > asyncSocket->getBufferedAmount()) { ------------------ | Branch (360:24): [True: 361, False: 14.6k] | Branch (360:41): [True: 10.0k, False: 4.65k] ------------------ 361| | /* Only call drain if we actually drained backpressure or if we came here with 0 backpressure */ 362| 10.3k| auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); 363| 10.3k| if (webSocketContextData->drainHandler) { ------------------ | Branch (363:21): [True: 10.3k, False: 0] ------------------ 364| 10.3k| webSocketContextData->drainHandler((WebSocket *) s); 365| 10.3k| } 366| | /* No need to check for closed here as we leave the handler immediately*/ 367| 10.3k| } 368| | 369| 17.7k| return s; 370| 17.7k| }); EpollEchoServerPubSub.cpp:_ZZN3uWS16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataE4initEvENKUlPT_E0_clI11us_socket_tEEDaS4_: 373| 2.21k| us_socket_context_on_end(SSL, getSocketContext(), [](auto *s) { 374| | 375| | /* If we get a fin, we just close I guess */ 376| 2.21k| us_socket_close(SSL, (us_socket_t *) s, 0, nullptr); 377| | 378| 2.21k| return s; 379| 2.21k| }); EpollEchoServerPubSub.cpp:_ZZN3uWS16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataE4initEvENKUlPT_E2_clI11us_socket_tEEDaS4_: 388| 196| us_socket_context_on_timeout(SSL, getSocketContext(), [](auto *s) { 389| | 390| 196| auto *webSocketData = (WebSocketData *)(us_socket_ext(SSL, s)); 391| 196| auto *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s)); 392| | 393| 196| if (webSocketContextData->sendPingsAutomatically && !webSocketData->isShuttingDown && !webSocketData->hasTimedOut) { ------------------ | Branch (393:17): [True: 0, False: 196] | Branch (393:65): [True: 0, False: 0] | Branch (393:99): [True: 0, False: 0] ------------------ 394| 0| webSocketData->hasTimedOut = true; 395| 0| us_socket_timeout(SSL, s, webSocketContextData->idleTimeoutComponents.second); 396| | /* Send ping without being corked */ 397| 0| ((AsyncSocket *) s)->write("\x89\x00", 2); 398| 0| return s; 399| 0| } 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| 196| forceClose(nullptr, s, ERR_WEBSOCKET_TIMEOUT); 404| | 405| 196| return s; 406| 196| }); EpollEchoServerPubSub.cpp:_ZN3uWS16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataE4freeEv: 411| 5.39k| void free() { 412| 5.39k| WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, (us_socket_context_t *) this); 413| 5.39k| webSocketContextData->~WebSocketContextData(); 414| | 415| 5.39k| us_socket_context_free(SSL, (us_socket_context_t *) this); 416| 5.39k| } EpollEchoServerPubSub.cpp:_ZN3uWS16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataE16getSocketContextEv: 35| 32.3k| us_socket_context_t *getSocketContext() { 36| 32.3k| return (us_socket_context_t *) this; 37| 32.3k| } EpollEchoServerPubSub.cpp:_ZN3uWS16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataE6getExtEv: 39| 86.2k| WebSocketContextData *getExt() { 40| 86.2k| return (WebSocketContextData *) us_socket_context_ext(SSL, (us_socket_context_t *) this); 41| 86.2k| } EpollEchoServerPubSub.cpp:_ZN3uWS20WebSocketContextDataILb1EZ4testvE13PerSocketDataEC2EPNS_9TopicTreeINS_16TopicTreeMessageENS_19TopicTreeBigMessageEEE: 102| 5.39k| WebSocketContextData(TopicTree *topicTree) : topicTree(topicTree) { 103| | 104| 5.39k| } EpollEchoServerPubSub.cpp:_ZN3uWS20WebSocketContextDataILb1EZ4testvE13PerSocketDataED2Ev: 98| 5.39k| ~WebSocketContextData() { 99| | 100| 5.39k| } EpollEchoServerPubSub.cpp:_ZN3uWS20WebSocketContextDataILb1EZ4testvE13PerSocketDataE29calculateIdleTimeoutCompnentsEt: 86| 5.39k| void calculateIdleTimeoutCompnents(unsigned short idleTimeout) { 87| 5.39k| unsigned short margin = 4; 88| | /* 4, 8 or 16 seconds margin based on idleTimeout */ 89| 16.1k| while ((int) idleTimeout - margin * 2 >= margin * 2 && margin < 16) { ------------------ | Branch (89:16): [True: 10.7k, False: 5.39k] | Branch (89:64): [True: 10.7k, False: 0] ------------------ 90| 10.7k| margin = (unsigned short) (margin << 1); 91| 10.7k| } 92| 5.39k| idleTimeoutComponents = { 93| 5.39k| idleTimeout - (sendPingsAutomatically ? margin : 0), /* reduce normal idleTimeout if it is extended by ping-timeout */ ------------------ | Branch (93:28): [True: 0, False: 5.39k] ------------------ 94| 5.39k| margin /* ping-timeout - also used for end() timeout */ 95| 5.39k| }; 96| 5.39k| } _ZN3uWS13WebSocketDataD2Ev: 69| 105k| ~WebSocketData() { 70| 105k| if (deflationStream) { ------------------ | Branch (70:13): [True: 0, False: 105k] ------------------ 71| 0| delete deflationStream; 72| 0| } 73| | 74| 105k| if (inflationStream) { ------------------ | Branch (74:13): [True: 0, False: 105k] ------------------ 75| 0| delete inflationStream; 76| 0| } 77| | 78| 105k| if (subscriber) { ------------------ | Branch (78:13): [True: 0, False: 105k] ------------------ 79| 0| delete subscriber; 80| 0| } 81| 105k| } _ZN3uWS13WebSocketDataC2EbNS_15CompressOptionsEONS_12BackPressureE: 55| 105k| WebSocketData(bool perMessageDeflate, CompressOptions compressOptions, BackPressure &&backpressure) : AsyncSocketData(std::move(backpressure)), WebSocketState() { 56| 105k| compressionStatus = perMessageDeflate ? ENABLED : DISABLED; ------------------ | Branch (56:29): [True: 0, False: 105k] ------------------ 57| | 58| | /* Initialize the dedicated sliding window(s) */ 59| 105k| if (perMessageDeflate) { ------------------ | Branch (59:13): [True: 0, False: 105k] ------------------ 60| 0| if ((compressOptions & CompressOptions::_COMPRESSOR_MASK) != CompressOptions::SHARED_COMPRESSOR) { ------------------ | Branch (60:17): [True: 0, False: 0] ------------------ 61| 0| deflationStream = new DeflationStream(compressOptions); 62| 0| } 63| 0| if ((compressOptions & CompressOptions::_DECOMPRESSOR_MASK) != CompressOptions::SHARED_DECOMPRESSOR) { ------------------ | Branch (63:17): [True: 0, False: 0] ------------------ 64| 0| inflationStream = new InflationStream(compressOptions); 65| 0| } 66| 0| } 67| 105k| } _ZN3uWS18WebSocketHandshake8generateEPKcPc: 116| 105k| static inline void generate(const char input[24], char output[28]) { 117| 105k| uint32_t b_output[5] = { 118| 105k| 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 119| 105k| }; 120| 105k| uint32_t b_input[16] = { 121| 105k| 0, 0, 0, 0, 0, 0, 0x32353845, 0x41464135, 0x2d453931, 0x342d3437, 0x44412d39, 122| 105k| 0x3543412d, 0x43354142, 0x30444338, 0x35423131, 0x80000000 123| 105k| }; 124| | 125| 737k| for (int i = 0; i < 6; i++) { ------------------ | Branch (125:25): [True: 632k, False: 105k] ------------------ 126| 632k| 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| 632k| } 128| 105k| sha1(b_output, b_input); 129| 105k| uint32_t last_b[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 480}; 130| 105k| sha1(b_output, last_b); 131| 632k| for (int i = 0; i < 5; i++) { ------------------ | Branch (131:25): [True: 527k, False: 105k] ------------------ 132| 527k| uint32_t tmp = b_output[i]; 133| 527k| char *bytes = (char *) &b_output[i]; 134| 527k| bytes[3] = (char) (tmp & 0xff); 135| 527k| bytes[2] = (char) ((tmp >> 8) & 0xff); 136| 527k| bytes[1] = (char) ((tmp >> 16) & 0xff); 137| 527k| bytes[0] = (char) ((tmp >> 24) & 0xff); 138| 527k| } 139| 105k| base64((unsigned char *) b_output, output); 140| 105k| } _ZN3uWS18WebSocketHandshake4sha1EPjS1_: 91| 210k| static inline void sha1(uint32_t hash[5], uint32_t b[16]) { 92| 210k| uint32_t a[5] = {hash[4], hash[3], hash[2], hash[1], hash[0]}; 93| 210k| static_for<16, Sha1Loop1>()(a, b); 94| 210k| static_for<4, Sha1Loop2>()(a, b); 95| 210k| static_for<20, Sha1Loop3>()(a, b); 96| 210k| static_for<20, Sha1Loop4>()(a, b); 97| 210k| static_for<20, Sha1Loop5>()(a, b); 98| 210k| static_for<5, Sha1Loop6>()(a, hash); 99| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi16ENS0_9Sha1Loop1EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi15ENS0_9Sha1Loop1EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi14ENS0_9Sha1Loop1EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi13ENS0_9Sha1Loop1EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi12ENS0_9Sha1Loop1EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi11ENS0_9Sha1Loop1EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi10ENS0_9Sha1Loop1EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi9ENS0_9Sha1Loop1EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi8ENS0_9Sha1Loop1EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi7ENS0_9Sha1Loop1EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi6ENS0_9Sha1Loop1EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi5ENS0_9Sha1Loop1EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi4ENS0_9Sha1Loop1EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi3ENS0_9Sha1Loop1EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi2ENS0_9Sha1Loop1EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi1ENS0_9Sha1Loop1EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi0ENS0_9Sha1Loop1EEclEPjS4_: 37| 210k| void operator()(uint32_t */*a*/, uint32_t */*hash*/) {} _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi0EEEvPjS3_: 47| 210k| static inline void f(uint32_t *a, uint32_t *b) { 48| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 210k| } _ZN3uWS18WebSocketHandshake3rolEjm: 40| 47.2M| static inline uint32_t rol(uint32_t value, size_t bits) {return (value << bits) | (value >> (32 - bits));} _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi1EEEvPjS3_: 47| 210k| static inline void f(uint32_t *a, uint32_t *b) { 48| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi2EEEvPjS3_: 47| 210k| static inline void f(uint32_t *a, uint32_t *b) { 48| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi3EEEvPjS3_: 47| 210k| static inline void f(uint32_t *a, uint32_t *b) { 48| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi4EEEvPjS3_: 47| 210k| static inline void f(uint32_t *a, uint32_t *b) { 48| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi5EEEvPjS3_: 47| 210k| static inline void f(uint32_t *a, uint32_t *b) { 48| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi6EEEvPjS3_: 47| 210k| static inline void f(uint32_t *a, uint32_t *b) { 48| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi7EEEvPjS3_: 47| 210k| static inline void f(uint32_t *a, uint32_t *b) { 48| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi8EEEvPjS3_: 47| 210k| static inline void f(uint32_t *a, uint32_t *b) { 48| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi9EEEvPjS3_: 47| 210k| static inline void f(uint32_t *a, uint32_t *b) { 48| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi10EEEvPjS3_: 47| 210k| static inline void f(uint32_t *a, uint32_t *b) { 48| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi11EEEvPjS3_: 47| 210k| static inline void f(uint32_t *a, uint32_t *b) { 48| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi12EEEvPjS3_: 47| 210k| static inline void f(uint32_t *a, uint32_t *b) { 48| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi13EEEvPjS3_: 47| 210k| static inline void f(uint32_t *a, uint32_t *b) { 48| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi14EEEvPjS3_: 47| 210k| static inline void f(uint32_t *a, uint32_t *b) { 48| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop11fILi15EEEvPjS3_: 47| 210k| static inline void f(uint32_t *a, uint32_t *b) { 48| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 50| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi4ENS0_9Sha1Loop2EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi3ENS0_9Sha1Loop2EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi2ENS0_9Sha1Loop2EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi1ENS0_9Sha1Loop2EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi0ENS0_9Sha1Loop2EEclEPjS4_: 37| 210k| void operator()(uint32_t */*a*/, uint32_t */*hash*/) {} _ZN3uWS18WebSocketHandshake9Sha1Loop21fILi0EEEvPjS3_: 54| 210k| static inline void f(uint32_t *a, uint32_t *b) { 55| 210k| b[i] = blk(b, i); 56| 210k| 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| 210k| a[(4 + i) % 5] = rol(a[(4 + i) % 5], 30); 58| 210k| } _ZN3uWS18WebSocketHandshake3blkEPjm: 41| 13.4M| static inline uint32_t blk(uint32_t b[16], size_t i) { 42| 13.4M| return rol(b[(i + 13) & 15] ^ b[(i + 8) & 15] ^ b[(i + 2) & 15] ^ b[i], 1); 43| 13.4M| } _ZN3uWS18WebSocketHandshake9Sha1Loop21fILi1EEEvPjS3_: 54| 210k| static inline void f(uint32_t *a, uint32_t *b) { 55| 210k| b[i] = blk(b, i); 56| 210k| 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| 210k| a[(4 + i) % 5] = rol(a[(4 + i) % 5], 30); 58| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop21fILi2EEEvPjS3_: 54| 210k| static inline void f(uint32_t *a, uint32_t *b) { 55| 210k| b[i] = blk(b, i); 56| 210k| 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| 210k| a[(4 + i) % 5] = rol(a[(4 + i) % 5], 30); 58| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop21fILi3EEEvPjS3_: 54| 210k| static inline void f(uint32_t *a, uint32_t *b) { 55| 210k| b[i] = blk(b, i); 56| 210k| 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| 210k| a[(4 + i) % 5] = rol(a[(4 + i) % 5], 30); 58| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi20ENS0_9Sha1Loop3EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi19ENS0_9Sha1Loop3EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi18ENS0_9Sha1Loop3EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi17ENS0_9Sha1Loop3EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi16ENS0_9Sha1Loop3EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi15ENS0_9Sha1Loop3EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi14ENS0_9Sha1Loop3EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi13ENS0_9Sha1Loop3EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi12ENS0_9Sha1Loop3EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi11ENS0_9Sha1Loop3EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi10ENS0_9Sha1Loop3EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi9ENS0_9Sha1Loop3EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi8ENS0_9Sha1Loop3EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi7ENS0_9Sha1Loop3EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi6ENS0_9Sha1Loop3EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi5ENS0_9Sha1Loop3EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi4ENS0_9Sha1Loop3EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi3ENS0_9Sha1Loop3EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi2ENS0_9Sha1Loop3EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi1ENS0_9Sha1Loop3EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi0ENS0_9Sha1Loop3EEclEPjS4_: 37| 210k| void operator()(uint32_t */*a*/, uint32_t */*hash*/) {} _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi0EEEvPjS3_: 62| 210k| static inline void f(uint32_t *a, uint32_t *b) { 63| 210k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi1EEEvPjS3_: 62| 210k| static inline void f(uint32_t *a, uint32_t *b) { 63| 210k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi2EEEvPjS3_: 62| 210k| static inline void f(uint32_t *a, uint32_t *b) { 63| 210k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi3EEEvPjS3_: 62| 210k| static inline void f(uint32_t *a, uint32_t *b) { 63| 210k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi4EEEvPjS3_: 62| 210k| static inline void f(uint32_t *a, uint32_t *b) { 63| 210k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi5EEEvPjS3_: 62| 210k| static inline void f(uint32_t *a, uint32_t *b) { 63| 210k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi6EEEvPjS3_: 62| 210k| static inline void f(uint32_t *a, uint32_t *b) { 63| 210k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi7EEEvPjS3_: 62| 210k| static inline void f(uint32_t *a, uint32_t *b) { 63| 210k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi8EEEvPjS3_: 62| 210k| static inline void f(uint32_t *a, uint32_t *b) { 63| 210k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi9EEEvPjS3_: 62| 210k| static inline void f(uint32_t *a, uint32_t *b) { 63| 210k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi10EEEvPjS3_: 62| 210k| static inline void f(uint32_t *a, uint32_t *b) { 63| 210k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi11EEEvPjS3_: 62| 210k| static inline void f(uint32_t *a, uint32_t *b) { 63| 210k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi12EEEvPjS3_: 62| 210k| static inline void f(uint32_t *a, uint32_t *b) { 63| 210k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi13EEEvPjS3_: 62| 210k| static inline void f(uint32_t *a, uint32_t *b) { 63| 210k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi14EEEvPjS3_: 62| 210k| static inline void f(uint32_t *a, uint32_t *b) { 63| 210k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi15EEEvPjS3_: 62| 210k| static inline void f(uint32_t *a, uint32_t *b) { 63| 210k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi16EEEvPjS3_: 62| 210k| static inline void f(uint32_t *a, uint32_t *b) { 63| 210k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi17EEEvPjS3_: 62| 210k| static inline void f(uint32_t *a, uint32_t *b) { 63| 210k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi18EEEvPjS3_: 62| 210k| static inline void f(uint32_t *a, uint32_t *b) { 63| 210k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop31fILi19EEEvPjS3_: 62| 210k| static inline void f(uint32_t *a, uint32_t *b) { 63| 210k| b[(i + 4) % 16] = blk(b, (i + 4) % 16); 64| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 66| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi20ENS0_9Sha1Loop4EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi19ENS0_9Sha1Loop4EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi18ENS0_9Sha1Loop4EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi17ENS0_9Sha1Loop4EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi16ENS0_9Sha1Loop4EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi15ENS0_9Sha1Loop4EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi14ENS0_9Sha1Loop4EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi13ENS0_9Sha1Loop4EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi12ENS0_9Sha1Loop4EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi11ENS0_9Sha1Loop4EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi10ENS0_9Sha1Loop4EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi9ENS0_9Sha1Loop4EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi8ENS0_9Sha1Loop4EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi7ENS0_9Sha1Loop4EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi6ENS0_9Sha1Loop4EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi5ENS0_9Sha1Loop4EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi4ENS0_9Sha1Loop4EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi3ENS0_9Sha1Loop4EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi2ENS0_9Sha1Loop4EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi1ENS0_9Sha1Loop4EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi0ENS0_9Sha1Loop4EEclEPjS4_: 37| 210k| void operator()(uint32_t */*a*/, uint32_t */*hash*/) {} _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi0EEEvPjS3_: 70| 210k| static inline void f(uint32_t *a, uint32_t *b) { 71| 210k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi1EEEvPjS3_: 70| 210k| static inline void f(uint32_t *a, uint32_t *b) { 71| 210k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi2EEEvPjS3_: 70| 210k| static inline void f(uint32_t *a, uint32_t *b) { 71| 210k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi3EEEvPjS3_: 70| 210k| static inline void f(uint32_t *a, uint32_t *b) { 71| 210k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi4EEEvPjS3_: 70| 210k| static inline void f(uint32_t *a, uint32_t *b) { 71| 210k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi5EEEvPjS3_: 70| 210k| static inline void f(uint32_t *a, uint32_t *b) { 71| 210k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi6EEEvPjS3_: 70| 210k| static inline void f(uint32_t *a, uint32_t *b) { 71| 210k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi7EEEvPjS3_: 70| 210k| static inline void f(uint32_t *a, uint32_t *b) { 71| 210k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi8EEEvPjS3_: 70| 210k| static inline void f(uint32_t *a, uint32_t *b) { 71| 210k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi9EEEvPjS3_: 70| 210k| static inline void f(uint32_t *a, uint32_t *b) { 71| 210k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi10EEEvPjS3_: 70| 210k| static inline void f(uint32_t *a, uint32_t *b) { 71| 210k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi11EEEvPjS3_: 70| 210k| static inline void f(uint32_t *a, uint32_t *b) { 71| 210k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi12EEEvPjS3_: 70| 210k| static inline void f(uint32_t *a, uint32_t *b) { 71| 210k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi13EEEvPjS3_: 70| 210k| static inline void f(uint32_t *a, uint32_t *b) { 71| 210k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi14EEEvPjS3_: 70| 210k| static inline void f(uint32_t *a, uint32_t *b) { 71| 210k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi15EEEvPjS3_: 70| 210k| static inline void f(uint32_t *a, uint32_t *b) { 71| 210k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi16EEEvPjS3_: 70| 210k| static inline void f(uint32_t *a, uint32_t *b) { 71| 210k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi17EEEvPjS3_: 70| 210k| static inline void f(uint32_t *a, uint32_t *b) { 71| 210k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi18EEEvPjS3_: 70| 210k| static inline void f(uint32_t *a, uint32_t *b) { 71| 210k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop41fILi19EEEvPjS3_: 70| 210k| static inline void f(uint32_t *a, uint32_t *b) { 71| 210k| b[(i + 8) % 16] = blk(b, (i + 8) % 16); 72| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 74| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi20ENS0_9Sha1Loop5EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi19ENS0_9Sha1Loop5EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi18ENS0_9Sha1Loop5EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi17ENS0_9Sha1Loop5EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi16ENS0_9Sha1Loop5EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi15ENS0_9Sha1Loop5EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi14ENS0_9Sha1Loop5EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi13ENS0_9Sha1Loop5EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi12ENS0_9Sha1Loop5EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi11ENS0_9Sha1Loop5EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi10ENS0_9Sha1Loop5EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi9ENS0_9Sha1Loop5EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi8ENS0_9Sha1Loop5EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi7ENS0_9Sha1Loop5EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi6ENS0_9Sha1Loop5EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi5ENS0_9Sha1Loop5EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi4ENS0_9Sha1Loop5EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi3ENS0_9Sha1Loop5EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi2ENS0_9Sha1Loop5EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi1ENS0_9Sha1Loop5EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi0ENS0_9Sha1Loop5EEclEPjS4_: 37| 210k| void operator()(uint32_t */*a*/, uint32_t */*hash*/) {} _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi0EEEvPjS3_: 78| 210k| static inline void f(uint32_t *a, uint32_t *b) { 79| 210k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi1EEEvPjS3_: 78| 210k| static inline void f(uint32_t *a, uint32_t *b) { 79| 210k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi2EEEvPjS3_: 78| 210k| static inline void f(uint32_t *a, uint32_t *b) { 79| 210k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi3EEEvPjS3_: 78| 210k| static inline void f(uint32_t *a, uint32_t *b) { 79| 210k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi4EEEvPjS3_: 78| 210k| static inline void f(uint32_t *a, uint32_t *b) { 79| 210k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi5EEEvPjS3_: 78| 210k| static inline void f(uint32_t *a, uint32_t *b) { 79| 210k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi6EEEvPjS3_: 78| 210k| static inline void f(uint32_t *a, uint32_t *b) { 79| 210k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi7EEEvPjS3_: 78| 210k| static inline void f(uint32_t *a, uint32_t *b) { 79| 210k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi8EEEvPjS3_: 78| 210k| static inline void f(uint32_t *a, uint32_t *b) { 79| 210k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi9EEEvPjS3_: 78| 210k| static inline void f(uint32_t *a, uint32_t *b) { 79| 210k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi10EEEvPjS3_: 78| 210k| static inline void f(uint32_t *a, uint32_t *b) { 79| 210k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi11EEEvPjS3_: 78| 210k| static inline void f(uint32_t *a, uint32_t *b) { 79| 210k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi12EEEvPjS3_: 78| 210k| static inline void f(uint32_t *a, uint32_t *b) { 79| 210k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi13EEEvPjS3_: 78| 210k| static inline void f(uint32_t *a, uint32_t *b) { 79| 210k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi14EEEvPjS3_: 78| 210k| static inline void f(uint32_t *a, uint32_t *b) { 79| 210k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi15EEEvPjS3_: 78| 210k| static inline void f(uint32_t *a, uint32_t *b) { 79| 210k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi16EEEvPjS3_: 78| 210k| static inline void f(uint32_t *a, uint32_t *b) { 79| 210k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi17EEEvPjS3_: 78| 210k| static inline void f(uint32_t *a, uint32_t *b) { 79| 210k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi18EEEvPjS3_: 78| 210k| static inline void f(uint32_t *a, uint32_t *b) { 79| 210k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop51fILi19EEEvPjS3_: 78| 210k| static inline void f(uint32_t *a, uint32_t *b) { 79| 210k| b[(i + 12) % 16] = blk(b, (i + 12) % 16); 80| 210k| 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| 210k| a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); 82| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi5ENS0_9Sha1Loop6EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi4ENS0_9Sha1Loop6EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi3ENS0_9Sha1Loop6EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi2ENS0_9Sha1Loop6EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi1ENS0_9Sha1Loop6EEclEPjS4_: 29| 210k| void operator()(uint32_t *a, uint32_t *b) { 30| 210k| static_for()(a, b); 31| 210k| T::template f(a, b); 32| 210k| } _ZN3uWS18WebSocketHandshake10static_forILi0ENS0_9Sha1Loop6EEclEPjS4_: 37| 210k| void operator()(uint32_t */*a*/, uint32_t */*hash*/) {} _ZN3uWS18WebSocketHandshake9Sha1Loop61fILi0EEEvPjS3_: 86| 210k| static inline void f(uint32_t *a, uint32_t *b) { 87| 210k| b[i] += a[4 - i]; 88| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop61fILi1EEEvPjS3_: 86| 210k| static inline void f(uint32_t *a, uint32_t *b) { 87| 210k| b[i] += a[4 - i]; 88| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop61fILi2EEEvPjS3_: 86| 210k| static inline void f(uint32_t *a, uint32_t *b) { 87| 210k| b[i] += a[4 - i]; 88| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop61fILi3EEEvPjS3_: 86| 210k| static inline void f(uint32_t *a, uint32_t *b) { 87| 210k| b[i] += a[4 - i]; 88| 210k| } _ZN3uWS18WebSocketHandshake9Sha1Loop61fILi4EEEvPjS3_: 86| 210k| static inline void f(uint32_t *a, uint32_t *b) { 87| 210k| b[i] += a[4 - i]; 88| 210k| } _ZN3uWS18WebSocketHandshake6base64EPhPc: 101| 105k| static inline void base64(unsigned char *src, char *dst) { 102| 105k| const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 103| 737k| for (int i = 0; i < 18; i += 3) { ------------------ | Branch (103:25): [True: 632k, False: 105k] ------------------ 104| 632k| *dst++ = b64[(src[i] >> 2) & 63]; 105| 632k| *dst++ = b64[((src[i] & 3) << 4) | ((src[i + 1] & 240) >> 4)]; 106| 632k| *dst++ = b64[((src[i + 1] & 15) << 2) | ((src[i + 2] & 192) >> 6)]; 107| 632k| *dst++ = b64[src[i + 2] & 63]; 108| 632k| } 109| 105k| *dst++ = b64[(src[18] >> 2) & 63]; 110| 105k| *dst++ = b64[((src[18] & 3) << 4) | ((src[19] & 240) >> 4)]; 111| 105k| *dst++ = b64[((src[19] & 15) << 2)]; 112| 105k| *dst++ = '='; 113| 105k| } EpollEchoServerPubSub.cpp:_ZN3uWS8protocolL13formatMessageILb1EEEmPcPKcmNS_6OpCodeEmbb: 209| 63.1k|static inline size_t formatMessage(char *dst, const char *src, size_t length, OpCode opCode, size_t reportedLength, bool compressed, bool fin) { 210| 63.1k| size_t messageLength; 211| 63.1k| size_t headerLength; 212| 63.1k| if (reportedLength < 126) { ------------------ | Branch (212:9): [True: 62.7k, False: 401] ------------------ 213| 62.7k| headerLength = 2; 214| 62.7k| dst[1] = (char) reportedLength; 215| 62.7k| } else if (reportedLength <= UINT16_MAX) { ------------------ | Branch (215:16): [True: 401, False: 0] ------------------ 216| 401| headerLength = 4; 217| 401| dst[1] = 126; 218| 401| uint16_t tmp = cond_byte_swap((uint16_t) reportedLength); 219| 401| memcpy(&dst[2], &tmp, sizeof(uint16_t)); 220| 401| } 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| 63.1k| dst[0] = (char) ((fin ? 128 : 0) | ((compressed && opCode) ? SND_COMPRESSED : 0) | (char) opCode); ------------------ | Branch (227:23): [True: 63.1k, False: 0] | Branch (227:42): [True: 0, False: 63.1k] | Branch (227:56): [True: 0, False: 0] ------------------ 228| | 229| | //printf("%d\n", (int)dst[0]); 230| | 231| 63.1k| char mask[4]; 232| 63.1k| 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| 63.1k| messageLength = headerLength + length; 241| 63.1k| memcpy(dst + headerLength, src, length); 242| | 243| 63.1k| 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| 63.1k| return messageLength; 257| 63.1k|} _ZN3uWS8protocol14cond_byte_swapItEET_S2_: 95| 15.0k|T cond_byte_swap(T value) { 96| 15.0k| uint32_t endian_test = 1; 97| 15.0k| if (*((char *)&endian_test)) { ------------------ | Branch (97:9): [True: 15.0k, False: 0] ------------------ 98| 15.0k| union { 99| 15.0k| T i; 100| 15.0k| uint8_t b[sizeof(T)]; 101| 15.0k| } src = { value }, dst; 102| | 103| 45.1k| for (unsigned int i = 0; i < sizeof(value); i++) { ------------------ | Branch (103:34): [True: 30.1k, False: 15.0k] ------------------ 104| 30.1k| dst.b[i] = src.b[sizeof(value) - 1 - i]; 105| 30.1k| } 106| | 107| 15.0k| return dst.i; 108| 15.0k| } 109| 0| return value; 110| 15.0k|} _ZN3uWS8protocol14cond_byte_swapImEET_S2_: 95| 6.91k|T cond_byte_swap(T value) { 96| 6.91k| uint32_t endian_test = 1; 97| 6.91k| if (*((char *)&endian_test)) { ------------------ | Branch (97:9): [True: 6.91k, False: 0] ------------------ 98| 6.91k| union { 99| 6.91k| T i; 100| 6.91k| uint8_t b[sizeof(T)]; 101| 6.91k| } src = { value }, dst; 102| | 103| 62.2k| for (unsigned int i = 0; i < sizeof(value); i++) { ------------------ | Branch (103:34): [True: 55.3k, False: 6.91k] ------------------ 104| 55.3k| dst.b[i] = src.b[sizeof(value) - 1 - i]; 105| 55.3k| } 106| | 107| 6.91k| return dst.i; 108| 6.91k| } 109| 0| return value; 110| 6.91k|} EpollEchoServerPubSub.cpp:_ZN3uWS8protocolL16messageFrameSizeEm: 193| 63.1k|static inline size_t messageFrameSize(size_t messageSize) { 194| 63.1k| if (messageSize < 126) { ------------------ | Branch (194:9): [True: 62.7k, False: 401] ------------------ 195| 62.7k| return 2 + messageSize; 196| 62.7k| } else if (messageSize <= UINT16_MAX) { ------------------ | Branch (196:16): [True: 401, False: 0] ------------------ 197| 401| return 4 + messageSize; 198| 401| } 199| 0| return 10 + messageSize; 200| 63.1k|} EpollEchoServerPubSub.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataEEE7consumeEPcjPNS_14WebSocketStateILb1EEEPv: 458| 95.6k| static inline void consume(char *src, unsigned int length, WebSocketState *wState, void *user) { 459| 95.6k| if (wState->state.spillLength) { ------------------ | Branch (459:13): [True: 7.89k, False: 87.7k] ------------------ 460| 7.89k| src -= wState->state.spillLength; 461| 7.89k| length += wState->state.spillLength; 462| 7.89k| memcpy(src, wState->state.spill, wState->state.spillLength); 463| 7.89k| } 464| 95.6k| if (wState->state.wantsHead) { ------------------ | Branch (464:13): [True: 86.1k, False: 9.45k] ------------------ 465| 90.2k| parseNext: 466| 1.18M| while (length >= SHORT_MESSAGE_HEADER) { ------------------ | Branch (466:20): [True: 1.16M, False: 14.6k] ------------------ 467| | 468| | // invalid reserved bits / invalid opcodes / invalid control frames / set compressed frame 469| 1.16M| if ((rsv1(src) && !Impl::setCompressed(wState, user)) || rsv23(src) || (getOpCode(src) > 2 && getOpCode(src) < 8) || ------------------ | Branch (469:22): [True: 18.1k, False: 1.14M] | Branch (469:35): [True: 18.1k, False: 0] | Branch (469:74): [True: 15.8k, False: 1.13M] | Branch (469:89): [True: 17.4k, False: 1.11M] | Branch (469:111): [True: 1.29k, False: 16.2k] ------------------ 470| 1.16M| getOpCode(src) > 10 || (getOpCode(src) > 2 && (!isFin(src) || payloadLength(src) > 125))) { ------------------ | Branch (470:21): [True: 650, False: 1.13M] | Branch (470:45): [True: 15.5k, False: 1.11M] | Branch (470:68): [True: 483, False: 15.0k] | Branch (470:83): [True: 305, False: 14.7k] ------------------ 471| 36.7k| Impl::forceClose(wState, user); 472| 36.7k| return; 473| 36.7k| } 474| | 475| 1.13M| if (payloadLength(src) < 126) { ------------------ | Branch (475:21): [True: 1.11M, False: 13.6k] ------------------ 476| 1.11M| if (consumeMessage(payloadLength(src), src, length, wState, user)) { ------------------ | Branch (476:25): [True: 29.9k, False: 1.08M] ------------------ 477| 29.9k| return; 478| 29.9k| } 479| 1.11M| } else if (payloadLength(src) == 126) { ------------------ | Branch (479:28): [True: 6.47k, False: 7.16k] ------------------ 480| 6.47k| if (length < MEDIUM_MESSAGE_HEADER) { ------------------ | Branch (480:25): [True: 213, False: 6.26k] ------------------ 481| 213| break; 482| 6.26k| } else if(consumeMessage(protocol::cond_byte_swap(protocol::bit_cast(src + 2)), src, length, wState, user)) { ------------------ | Branch (482:31): [True: 3.32k, False: 2.93k] ------------------ 483| 3.32k| return; 484| 3.32k| } 485| 7.16k| } else if (length < LONG_MESSAGE_HEADER) { ------------------ | Branch (485:28): [True: 246, False: 6.91k] ------------------ 486| 246| break; 487| 6.91k| } else if (consumeMessage(protocol::cond_byte_swap(protocol::bit_cast(src + 2)), src, length, wState, user)) { ------------------ | Branch (487:28): [True: 5.17k, False: 1.73k] ------------------ 488| 5.17k| return; 489| 5.17k| } 490| 1.13M| } 491| 15.0k| if (length) { ------------------ | Branch (491:17): [True: 12.6k, False: 2.46k] ------------------ 492| 12.6k| memcpy(wState->state.spill, src, length); 493| 12.6k| wState->state.spillLength = length & 0xf; 494| 12.6k| } 495| 15.0k| } else if (consumeContinuation(src, length, wState, user)) { ------------------ | Branch (495:20): [True: 4.09k, False: 5.36k] ------------------ 496| 4.09k| goto parseNext; 497| 4.09k| } 498| 95.6k| } EpollEchoServerPubSub.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataEEE4rsv1EPc: 274| 1.16M| static inline bool rsv1(char *frame) {return *((unsigned char *) frame) & 64;} EpollEchoServerPubSub.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataEEE5rsv23EPc: 273| 1.14M| static inline bool rsv23(char *frame) {return *((unsigned char *) frame) & 48;} EpollEchoServerPubSub.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataEEE9getOpCodeEPc: 271| 5.66M| static inline unsigned char getOpCode(char *frame) {return *((unsigned char *) frame) & 15;} EpollEchoServerPubSub.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataEEE5isFinEPc: 270| 2.26M| static inline bool isFin(char *frame) {return *((unsigned char *) frame) & 128;} EpollEchoServerPubSub.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataEEE13payloadLengthEPc: 272| 2.27M| static inline unsigned char payloadLength(char *frame) {return ((unsigned char *) frame)[1] & 127;} EpollEchoServerPubSub.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataEEE14consumeMessageILj6EhEEbT0_RPcRjPNS_14WebSocketStateILb1EEEPv: 340| 1.11M| static inline bool consumeMessage(T payLength, char *&src, unsigned int &length, WebSocketState *wState, void *user) { 341| 1.11M| if (getOpCode(src)) { ------------------ | Branch (341:13): [True: 1.11M, False: 5.33k] ------------------ 342| 1.11M| if (wState->state.opStack == 1 || (!wState->state.lastFin && getOpCode(src) < 2)) { ------------------ | Branch (342:17): [True: 198, False: 1.11M] | Branch (342:48): [True: 1.78k, False: 1.10M] | Branch (342:74): [True: 646, False: 1.13k] ------------------ 343| 844| Impl::forceClose(wState, user); 344| 844| return true; 345| 844| } 346| 1.11M| wState->state.opCode[++wState->state.opStack] = (OpCode) getOpCode(src); 347| 1.11M| } else if (wState->state.opStack == -1) { ------------------ | Branch (347:20): [True: 428, False: 4.90k] ------------------ 348| 428| Impl::forceClose(wState, user); 349| 428| return true; 350| 428| } 351| 1.11M| wState->state.lastFin = isFin(src); 352| | 353| 1.11M| if (Impl::refusePayloadLength(payLength, wState, user)) { ------------------ | Branch (353:13): [True: 0, False: 1.11M] ------------------ 354| 0| Impl::forceClose(wState, user, ERR_TOO_BIG_MESSAGE); 355| 0| return true; 356| 0| } 357| | 358| 1.11M| if (payLength + MESSAGE_HEADER <= length) { ------------------ | Branch (358:13): [True: 1.10M, False: 8.22k] ------------------ 359| 1.10M| bool fin = isFin(src); 360| 1.10M| 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| 1.10M| unmaskImpreciseCopyMask(src + MESSAGE_HEADER, (unsigned int) payLength); 363| 1.10M| if (Impl::handleFragment(src, payLength, 0, wState->state.opCode[wState->state.opStack], fin, wState, user)) { ------------------ | Branch (363:21): [True: 20.4k, False: 1.08M] ------------------ 364| 20.4k| return true; 365| 20.4k| } 366| 1.10M| } 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| 1.08M| if (fin) { ------------------ | Branch (372:17): [True: 1.07M, False: 11.7k] ------------------ 373| 1.07M| wState->state.opStack--; 374| 1.07M| } 375| | 376| 1.08M| src += payLength + MESSAGE_HEADER; 377| 1.08M| length -= (unsigned int) (payLength + MESSAGE_HEADER); 378| 1.08M| wState->state.spillLength = 0; 379| 1.08M| return false; 380| 1.10M| } else { 381| 8.22k| wState->state.spillLength = 0; 382| 8.22k| wState->state.wantsHead = false; 383| 8.22k| wState->remainingBytes = (unsigned int) (payLength - length + MESSAGE_HEADER); 384| 8.22k| bool fin = isFin(src); 385| 8.22k| if constexpr (isServer) { ------------------ | Branch (385:27): [Folded - Ignored] ------------------ 386| 8.22k| memcpy(wState->mask, src + MESSAGE_HEADER - 4, 4); 387| 8.22k| uint64_t mask; 388| 8.22k| memcpy(&mask, src + MESSAGE_HEADER - 4, 4); 389| 8.22k| memcpy(((char *)&mask) + 4, src + MESSAGE_HEADER - 4, 4); 390| 8.22k| unmaskImprecise8<0>(src + MESSAGE_HEADER, mask, length); 391| 8.22k| rotateMask(4 - (length - MESSAGE_HEADER) % 4, wState->mask); 392| 8.22k| } 393| 8.22k| Impl::handleFragment(src + MESSAGE_HEADER, length - MESSAGE_HEADER, wState->remainingBytes, wState->state.opCode[wState->state.opStack], fin, wState, user); 394| 8.22k| return true; 395| 8.22k| } 396| 1.11M| } EpollEchoServerPubSub.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataEEE23unmaskImpreciseCopyMaskILi6EEEvPcj: 308| 1.10M| static inline void unmaskImpreciseCopyMask(char *src, unsigned int length) { 309| 1.10M| if constexpr (HEADER_SIZE != 6) { ------------------ | Branch (309:23): [Folded - Ignored] ------------------ 310| 1.10M| char mask[8] = {src[-4], src[-3], src[-2], src[-1], src[-4], src[-3], src[-2], src[-1]}; 311| 1.10M| uint64_t maskInt; 312| 1.10M| memcpy(&maskInt, mask, 8); 313| 1.10M| unmaskImprecise8(src, maskInt, length); 314| 1.10M| } else { 315| 1.10M| char mask[4] = {src[-4], src[-3], src[-2], src[-1]}; 316| 1.10M| uint32_t maskInt; 317| 1.10M| memcpy(&maskInt, mask, 4); 318| 1.10M| unmaskImprecise4(src, maskInt, length); 319| 1.10M| } 320| 1.10M| } EpollEchoServerPubSub.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataEEE16unmaskImprecise4ILi6EEEvPcjj: 297| 1.10M| static inline void unmaskImprecise4(char *src, uint32_t mask, unsigned int length) { 298| 2.33M| for (unsigned int n = (length >> 2) + 1; n; n--) { ------------------ | Branch (298:50): [True: 1.22M, False: 1.10M] ------------------ 299| 1.22M| uint32_t loaded; 300| 1.22M| memcpy(&loaded, src, 4); 301| 1.22M| loaded ^= mask; 302| 1.22M| memcpy(src - DESTINATION, &loaded, 4); 303| 1.22M| src += 4; 304| 1.22M| } 305| 1.10M| } EpollEchoServerPubSub.cpp:_ZN3uWS8protocolL11isValidUtf8EPhm: 117| 1.08M|{ 118| 1.17M| for (unsigned char *e = s + length; s != e; ) { ------------------ | Branch (118:41): [True: 1.17M, False: 1.67k] ------------------ 119| 1.17M| if (s + 4 <= e) { ------------------ | Branch (119:13): [True: 93.9k, False: 1.08M] ------------------ 120| 93.9k| uint32_t tmp; 121| 93.9k| memcpy(&tmp, s, 4); 122| 93.9k| if ((tmp & 0x80808080) == 0) { ------------------ | Branch (122:17): [True: 88.3k, False: 5.52k] ------------------ 123| 88.3k| s += 4; 124| 88.3k| continue; 125| 88.3k| } 126| 93.9k| } 127| | 128| 1.09M| while (!(*s & 0x80)) { ------------------ | Branch (128:16): [True: 1.06M, False: 21.2k] ------------------ 129| 1.06M| if (++s == e) { ------------------ | Branch (129:17): [True: 1.06M, False: 4.21k] ------------------ 130| 1.06M| return true; 131| 1.06M| } 132| 1.06M| } 133| | 134| 21.2k| if ((s[0] & 0x60) == 0x40) { ------------------ | Branch (134:13): [True: 1.28k, False: 19.9k] ------------------ 135| 1.28k| if (s + 1 >= e || (s[1] & 0xc0) != 0x80 || (s[0] & 0xfe) == 0xc0) { ------------------ | Branch (135:17): [True: 456, False: 831] | Branch (135:31): [True: 306, False: 525] | Branch (135:56): [True: 204, False: 321] ------------------ 136| 966| return false; 137| 966| } 138| 321| s += 2; 139| 19.9k| } else if ((s[0] & 0xf0) == 0xe0) { ------------------ | Branch (139:20): [True: 3.19k, False: 16.7k] ------------------ 140| 3.19k| if (s + 2 >= e || (s[1] & 0xc0) != 0x80 || (s[2] & 0xc0) != 0x80 || ------------------ | Branch (140:17): [True: 247, False: 2.95k] | Branch (140:31): [True: 522, False: 2.42k] | Branch (140:56): [True: 565, False: 1.86k] ------------------ 141| 3.19k| (s[0] == 0xe0 && (s[1] & 0xe0) == 0x80) || (s[0] == 0xed && (s[1] & 0xe0) == 0xa0)) { ------------------ | Branch (141:22): [True: 467, False: 1.39k] | Branch (141:38): [True: 221, False: 246] | Branch (141:65): [True: 916, False: 727] | Branch (141:81): [True: 721, False: 195] ------------------ 142| 2.27k| return false; 143| 2.27k| } 144| 922| s += 3; 145| 16.7k| } else if ((s[0] & 0xf8) == 0xf0) { ------------------ | Branch (145:20): [True: 15.4k, False: 1.25k] ------------------ 146| 15.4k| if (s + 3 >= e || (s[1] & 0xc0) != 0x80 || (s[2] & 0xc0) != 0x80 || (s[3] & 0xc0) != 0x80 || ------------------ | Branch (146:17): [True: 12.7k, False: 2.73k] | Branch (146:31): [True: 285, False: 2.45k] | Branch (146:56): [True: 217, False: 2.23k] | Branch (146:81): [True: 210, False: 2.02k] ------------------ 147| 15.4k| (s[0] == 0xf0 && (s[1] & 0xf0) == 0x80) || (s[0] == 0xf4 && s[1] > 0x8f) || s[0] > 0xf4) { ------------------ | Branch (147:22): [True: 390, False: 1.63k] | Branch (147:38): [True: 194, False: 196] | Branch (147:65): [True: 1.09k, False: 735] | Branch (147:81): [True: 228, False: 868] | Branch (147:97): [True: 215, False: 1.38k] ------------------ 148| 14.0k| return false; 149| 14.0k| } 150| 1.38k| s += 4; 151| 1.38k| } else { 152| 1.25k| return false; 153| 1.25k| } 154| 21.2k| } 155| 1.67k| return true; 156| 1.08M|} EpollEchoServerPubSub.cpp:_ZN3uWS8protocolL17parseClosePayloadEPcm: 164| 8.76k|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| 8.76k| CloseFrame cf = {1005, nullptr, 0}; 167| 8.76k| if (length >= 2) { ------------------ | Branch (167:9): [True: 7.67k, False: 1.09k] ------------------ 168| 7.67k| memcpy(&cf.code, src, 2); 169| 7.67k| cf = {cond_byte_swap(cf.code), src + 2, length - 2}; 170| 7.67k| if (cf.code < 1000 || cf.code > 4999 || (cf.code > 1011 && cf.code < 4000) || ------------------ | Branch (170:13): [True: 495, False: 7.18k] | Branch (170:31): [True: 1.14k, False: 6.03k] | Branch (170:50): [True: 3.87k, False: 2.16k] | Branch (170:68): [True: 1.18k, False: 2.68k] ------------------ 171| 7.67k| (cf.code >= 1004 && cf.code <= 1006) || !isValidUtf8((unsigned char *) cf.message, cf.length)) { ------------------ | Branch (171:14): [True: 4.36k, False: 490] | Branch (171:33): [True: 392, False: 3.97k] | Branch (171:53): [True: 3.75k, False: 709] ------------------ 172| | /* Even though we got a WebSocket close frame, it in itself is abnormal */ 173| 6.96k| return {1006, nullptr, 0}; 174| 6.96k| } 175| 7.67k| } 176| 1.80k| return cf; 177| 8.76k|} EpollEchoServerPubSub.cpp:_ZN3uWS8protocolL18formatClosePayloadEPctPKcm: 179| 8.76k|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| 8.76k| if (code && code != 1005 && code != 1006) { ------------------ | Branch (181:9): [True: 8.76k, False: 0] | Branch (181:17): [True: 7.67k, False: 1.09k] | Branch (181:33): [True: 709, False: 6.96k] ------------------ 182| 709| code = cond_byte_swap(code); 183| 709| memcpy(dst, &code, 2); 184| | /* It is invalid to pass nullptr to memcpy, even though length is 0 */ 185| 709| if (message) { ------------------ | Branch (185:13): [True: 709, False: 0] ------------------ 186| 709| memcpy(dst + 2, message, length); 187| 709| } 188| 709| return length + 2; 189| 709| } 190| 8.05k| return 0; 191| 8.76k|} EpollEchoServerPubSub.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataEEE16unmaskImprecise8ILi0EEEvPcmj: 285| 11.0k| static inline void unmaskImprecise8(char *src, uint64_t mask, unsigned int length) { 286| 70.0k| for (unsigned int n = (length >> 3) + 1; n; n--) { ------------------ | Branch (286:50): [True: 59.0k, False: 11.0k] ------------------ 287| 59.0k| uint64_t loaded; 288| 59.0k| memcpy(&loaded, src, 8); 289| 59.0k| loaded ^= mask; 290| 59.0k| memcpy(src - DESTINATION, &loaded, 8); 291| 59.0k| src += 8; 292| 59.0k| } 293| 11.0k| } EpollEchoServerPubSub.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataEEE10rotateMaskEjPc: 322| 13.2k| static inline void rotateMask(unsigned int offset, char *mask) { 323| 13.2k| char originalMask[4] = {mask[0], mask[1], mask[2], mask[3]}; 324| 13.2k| mask[(0 + offset) % 4] = originalMask[0]; 325| 13.2k| mask[(1 + offset) % 4] = originalMask[1]; 326| 13.2k| mask[(2 + offset) % 4] = originalMask[2]; 327| 13.2k| mask[(3 + offset) % 4] = originalMask[3]; 328| 13.2k| } EpollEchoServerPubSub.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataEEE14consumeMessageILj8EtEEbT0_RPcRjPNS_14WebSocketStateILb1EEEPv: 340| 6.26k| static inline bool consumeMessage(T payLength, char *&src, unsigned int &length, WebSocketState *wState, void *user) { 341| 6.26k| if (getOpCode(src)) { ------------------ | Branch (341:13): [True: 4.46k, False: 1.80k] ------------------ 342| 4.46k| if (wState->state.opStack == 1 || (!wState->state.lastFin && getOpCode(src) < 2)) { ------------------ | Branch (342:17): [True: 194, False: 4.27k] | Branch (342:48): [True: 1.49k, False: 2.78k] | Branch (342:74): [True: 380, False: 1.11k] ------------------ 343| 574| Impl::forceClose(wState, user); 344| 574| return true; 345| 574| } 346| 3.89k| wState->state.opCode[++wState->state.opStack] = (OpCode) getOpCode(src); 347| 3.89k| } else if (wState->state.opStack == -1) { ------------------ | Branch (347:20): [True: 313, False: 1.48k] ------------------ 348| 313| Impl::forceClose(wState, user); 349| 313| return true; 350| 313| } 351| 5.37k| wState->state.lastFin = isFin(src); 352| | 353| 5.37k| if (Impl::refusePayloadLength(payLength, wState, user)) { ------------------ | Branch (353:13): [True: 376, False: 5.00k] ------------------ 354| 376| Impl::forceClose(wState, user, ERR_TOO_BIG_MESSAGE); 355| 376| return true; 356| 376| } 357| | 358| 5.00k| if (payLength + MESSAGE_HEADER <= length) { ------------------ | Branch (358:13): [True: 3.24k, False: 1.76k] ------------------ 359| 3.24k| bool fin = isFin(src); 360| 3.24k| 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.24k| unmaskImpreciseCopyMask(src + MESSAGE_HEADER, (unsigned int) payLength); 363| 3.24k| if (Impl::handleFragment(src, payLength, 0, wState->state.opCode[wState->state.opStack], fin, wState, user)) { ------------------ | Branch (363:21): [True: 303, False: 2.93k] ------------------ 364| 303| return true; 365| 303| } 366| 3.24k| } 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.93k| if (fin) { ------------------ | Branch (372:17): [True: 1.92k, False: 1.01k] ------------------ 373| 1.92k| wState->state.opStack--; 374| 1.92k| } 375| | 376| 2.93k| src += payLength + MESSAGE_HEADER; 377| 2.93k| length -= (unsigned int) (payLength + MESSAGE_HEADER); 378| 2.93k| wState->state.spillLength = 0; 379| 2.93k| return false; 380| 3.24k| } else { 381| 1.76k| wState->state.spillLength = 0; 382| 1.76k| wState->state.wantsHead = false; 383| 1.76k| wState->remainingBytes = (unsigned int) (payLength - length + MESSAGE_HEADER); 384| 1.76k| bool fin = isFin(src); 385| 1.76k| if constexpr (isServer) { ------------------ | Branch (385:27): [Folded - Ignored] ------------------ 386| 1.76k| memcpy(wState->mask, src + MESSAGE_HEADER - 4, 4); 387| 1.76k| uint64_t mask; 388| 1.76k| memcpy(&mask, src + MESSAGE_HEADER - 4, 4); 389| 1.76k| memcpy(((char *)&mask) + 4, src + MESSAGE_HEADER - 4, 4); 390| 1.76k| unmaskImprecise8<0>(src + MESSAGE_HEADER, mask, length); 391| 1.76k| rotateMask(4 - (length - MESSAGE_HEADER) % 4, wState->mask); 392| 1.76k| } 393| 1.76k| Impl::handleFragment(src + MESSAGE_HEADER, length - MESSAGE_HEADER, wState->remainingBytes, wState->state.opCode[wState->state.opStack], fin, wState, user); 394| 1.76k| return true; 395| 1.76k| } 396| 5.00k| } EpollEchoServerPubSub.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataEEE23unmaskImpreciseCopyMaskILi8EEEvPcj: 308| 3.24k| static inline void unmaskImpreciseCopyMask(char *src, unsigned int length) { 309| 3.24k| if constexpr (HEADER_SIZE != 6) { ------------------ | Branch (309:23): [Folded - Ignored] ------------------ 310| 3.24k| char mask[8] = {src[-4], src[-3], src[-2], src[-1], src[-4], src[-3], src[-2], src[-1]}; 311| 3.24k| uint64_t maskInt; 312| 3.24k| memcpy(&maskInt, mask, 8); 313| 3.24k| unmaskImprecise8(src, maskInt, length); 314| 3.24k| } else { 315| 3.24k| char mask[4] = {src[-4], src[-3], src[-2], src[-1]}; 316| 3.24k| uint32_t maskInt; 317| 3.24k| memcpy(&maskInt, mask, 4); 318| 3.24k| unmaskImprecise4(src, maskInt, length); 319| 3.24k| } 320| 3.24k| } EpollEchoServerPubSub.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataEEE16unmaskImprecise8ILi8EEEvPcmj: 285| 3.24k| static inline void unmaskImprecise8(char *src, uint64_t mask, unsigned int length) { 286| 13.8k| for (unsigned int n = (length >> 3) + 1; n; n--) { ------------------ | Branch (286:50): [True: 10.5k, False: 3.24k] ------------------ 287| 10.5k| uint64_t loaded; 288| 10.5k| memcpy(&loaded, src, 8); 289| 10.5k| loaded ^= mask; 290| 10.5k| memcpy(src - DESTINATION, &loaded, 8); 291| 10.5k| src += 8; 292| 10.5k| } 293| 3.24k| } _ZN3uWS8protocol8bit_castItEET_Pc: 87| 6.26k|T bit_cast(char *c) { 88| 6.26k| T val; 89| 6.26k| memcpy(&val, c, sizeof(T)); 90| 6.26k| return val; 91| 6.26k|} EpollEchoServerPubSub.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataEEE14consumeMessageILj14EmEEbT0_RPcRjPNS_14WebSocketStateILb1EEEPv: 340| 6.91k| static inline bool consumeMessage(T payLength, char *&src, unsigned int &length, WebSocketState *wState, void *user) { 341| 6.91k| if (getOpCode(src)) { ------------------ | Branch (341:13): [True: 5.87k, False: 1.03k] ------------------ 342| 5.87k| if (wState->state.opStack == 1 || (!wState->state.lastFin && getOpCode(src) < 2)) { ------------------ | Branch (342:17): [True: 194, False: 5.68k] | Branch (342:48): [True: 3.36k, False: 2.31k] | Branch (342:74): [True: 3.14k, False: 219] ------------------ 343| 3.34k| Impl::forceClose(wState, user); 344| 3.34k| return true; 345| 3.34k| } 346| 2.53k| wState->state.opCode[++wState->state.opStack] = (OpCode) getOpCode(src); 347| 2.53k| } else if (wState->state.opStack == -1) { ------------------ | Branch (347:20): [True: 195, False: 842] ------------------ 348| 195| Impl::forceClose(wState, user); 349| 195| return true; 350| 195| } 351| 3.37k| wState->state.lastFin = isFin(src); 352| | 353| 3.37k| if (Impl::refusePayloadLength(payLength, wState, user)) { ------------------ | Branch (353:13): [True: 395, False: 2.98k] ------------------ 354| 395| Impl::forceClose(wState, user, ERR_TOO_BIG_MESSAGE); 355| 395| return true; 356| 395| } 357| | 358| 2.98k| if (payLength + MESSAGE_HEADER <= length) { ------------------ | Branch (358:13): [True: 1.94k, False: 1.03k] ------------------ 359| 1.94k| bool fin = isFin(src); 360| 1.94k| 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| 1.94k| unmaskImpreciseCopyMask(src + MESSAGE_HEADER, (unsigned int) payLength); 363| 1.94k| if (Impl::handleFragment(src, payLength, 0, wState->state.opCode[wState->state.opStack], fin, wState, user)) { ------------------ | Branch (363:21): [True: 208, False: 1.73k] ------------------ 364| 208| return true; 365| 208| } 366| 1.94k| } 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| 1.73k| if (fin) { ------------------ | Branch (372:17): [True: 779, False: 958] ------------------ 373| 779| wState->state.opStack--; 374| 779| } 375| | 376| 1.73k| src += payLength + MESSAGE_HEADER; 377| 1.73k| length -= (unsigned int) (payLength + MESSAGE_HEADER); 378| 1.73k| wState->state.spillLength = 0; 379| 1.73k| return false; 380| 1.94k| } else { 381| 1.03k| wState->state.spillLength = 0; 382| 1.03k| wState->state.wantsHead = false; 383| 1.03k| wState->remainingBytes = (unsigned int) (payLength - length + MESSAGE_HEADER); 384| 1.03k| bool fin = isFin(src); 385| 1.03k| if constexpr (isServer) { ------------------ | Branch (385:27): [Folded - Ignored] ------------------ 386| 1.03k| memcpy(wState->mask, src + MESSAGE_HEADER - 4, 4); 387| 1.03k| uint64_t mask; 388| 1.03k| memcpy(&mask, src + MESSAGE_HEADER - 4, 4); 389| 1.03k| memcpy(((char *)&mask) + 4, src + MESSAGE_HEADER - 4, 4); 390| 1.03k| unmaskImprecise8<0>(src + MESSAGE_HEADER, mask, length); 391| 1.03k| rotateMask(4 - (length - MESSAGE_HEADER) % 4, wState->mask); 392| 1.03k| } 393| 1.03k| Impl::handleFragment(src + MESSAGE_HEADER, length - MESSAGE_HEADER, wState->remainingBytes, wState->state.opCode[wState->state.opStack], fin, wState, user); 394| 1.03k| return true; 395| 1.03k| } 396| 2.98k| } EpollEchoServerPubSub.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataEEE23unmaskImpreciseCopyMaskILi14EEEvPcj: 308| 1.94k| static inline void unmaskImpreciseCopyMask(char *src, unsigned int length) { 309| 1.94k| if constexpr (HEADER_SIZE != 6) { ------------------ | Branch (309:23): [Folded - Ignored] ------------------ 310| 1.94k| char mask[8] = {src[-4], src[-3], src[-2], src[-1], src[-4], src[-3], src[-2], src[-1]}; 311| 1.94k| uint64_t maskInt; 312| 1.94k| memcpy(&maskInt, mask, 8); 313| 1.94k| unmaskImprecise8(src, maskInt, length); 314| 1.94k| } else { 315| 1.94k| char mask[4] = {src[-4], src[-3], src[-2], src[-1]}; 316| 1.94k| uint32_t maskInt; 317| 1.94k| memcpy(&maskInt, mask, 4); 318| 1.94k| unmaskImprecise4(src, maskInt, length); 319| 1.94k| } 320| 1.94k| } EpollEchoServerPubSub.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataEEE16unmaskImprecise8ILi14EEEvPcmj: 285| 1.94k| static inline void unmaskImprecise8(char *src, uint64_t mask, unsigned int length) { 286| 9.66k| for (unsigned int n = (length >> 3) + 1; n; n--) { ------------------ | Branch (286:50): [True: 7.72k, False: 1.94k] ------------------ 287| 7.72k| uint64_t loaded; 288| 7.72k| memcpy(&loaded, src, 8); 289| 7.72k| loaded ^= mask; 290| 7.72k| memcpy(src - DESTINATION, &loaded, 8); 291| 7.72k| src += 8; 292| 7.72k| } 293| 1.94k| } _ZN3uWS8protocol8bit_castImEET_Pc: 87| 6.91k|T bit_cast(char *c) { 88| 6.91k| T val; 89| 6.91k| memcpy(&val, c, sizeof(T)); 90| 6.91k| return val; 91| 6.91k|} EpollEchoServerPubSub.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataEEE19consumeContinuationERPcRjPNS_14WebSocketStateILb1EEEPv: 405| 9.45k| static inline bool consumeContinuation(char *&src, unsigned int &length, WebSocketState *wState, void *user) { 406| 9.45k| if (wState->remainingBytes <= length) { ------------------ | Branch (406:13): [True: 6.74k, False: 2.71k] ------------------ 407| 6.74k| if (isServer) { ------------------ | Branch (407:17): [Folded - Ignored] ------------------ 408| 6.74k| unsigned int n = wState->remainingBytes >> 2; 409| 6.74k| unmaskInplace(src, src + n * 4, wState->mask); 410| 15.9k| for (unsigned int i = 0, s = wState->remainingBytes % 4; i < s; i++) { ------------------ | Branch (410:74): [True: 9.18k, False: 6.74k] ------------------ 411| 9.18k| src[n * 4 + i] ^= wState->mask[i]; 412| 9.18k| } 413| 6.74k| } 414| | 415| 6.74k| if (Impl::handleFragment(src, wState->remainingBytes, 0, wState->state.opCode[wState->state.opStack], wState->state.lastFin, wState, user)) { ------------------ | Branch (415:17): [True: 2.64k, False: 4.09k] ------------------ 416| 2.64k| return false; 417| 2.64k| } 418| | 419| 4.09k| if (wState->state.lastFin) { ------------------ | Branch (419:17): [True: 2.86k, False: 1.23k] ------------------ 420| 2.86k| wState->state.opStack--; 421| 2.86k| } 422| | 423| 4.09k| src += wState->remainingBytes; 424| 4.09k| length -= wState->remainingBytes; 425| 4.09k| wState->state.wantsHead = true; 426| 4.09k| return true; 427| 6.74k| } else { 428| 2.71k| if (isServer) { ------------------ | Branch (428:17): [Folded - Ignored] ------------------ 429| | /* No need to unmask if mask is 0 */ 430| 2.71k| uint32_t nullmask = 0; 431| 2.71k| if (memcmp(wState->mask, &nullmask, sizeof(uint32_t))) { ------------------ | Branch (431:21): [True: 2.43k, False: 278] ------------------ 432| 2.43k| if /*constexpr*/ (LIBUS_RECV_BUFFER_LENGTH == length) { ------------------ | | 22| 2.43k|#define LIBUS_RECV_BUFFER_LENGTH 524288 ------------------ | Branch (432:39): [True: 0, False: 2.43k] ------------------ 433| 0| unmaskAll(src, wState->mask); 434| 2.43k| } else { 435| | // Slow path 436| 2.43k| unmaskInplace(src, src + ((length >> 2) + 1) * 4, wState->mask); 437| 2.43k| } 438| 2.43k| } 439| 2.71k| } 440| | 441| 2.71k| wState->remainingBytes -= length; 442| 2.71k| if (Impl::handleFragment(src, length, wState->remainingBytes, wState->state.opCode[wState->state.opStack], wState->state.lastFin, wState, user)) { ------------------ | Branch (442:17): [True: 239, False: 2.47k] ------------------ 443| 239| return false; 444| 239| } 445| | 446| 2.47k| if (isServer && length % 4) { ------------------ | Branch (446:17): [Folded - Ignored] | Branch (446:29): [True: 2.23k, False: 239] ------------------ 447| 2.23k| rotateMask(4 - (length % 4), wState->mask); 448| 2.23k| } 449| 2.47k| return false; 450| 2.71k| } 451| 9.45k| } EpollEchoServerPubSub.cpp:_ZN3uWS17WebSocketProtocolILb1ENS_16WebSocketContextILb1ELb1EZ4testvE13PerSocketDataEEE13unmaskInplaceEPcS5_S5_: 330| 9.18k| static inline void unmaskInplace(char *data, char *stop, char *mask) { 331| 55.0k| while (data < stop) { ------------------ | Branch (331:16): [True: 45.9k, False: 9.18k] ------------------ 332| 45.9k| *(data++) ^= mask[0]; 333| 45.9k| *(data++) ^= mask[1]; 334| 45.9k| *(data++) ^= mask[2]; 335| 45.9k| *(data++) ^= mask[3]; 336| 45.9k| } 337| 9.18k| } _ZN3uWS14WebSocketStateILb1EE5StateC2Ev: 70| 105k| State() { 71| 105k| wantsHead = true; 72| 105k| spillLength = 0; 73| 105k| opStack = -1; 74| 105k| lastFin = true; 75| 105k| } apple_no_sigpipe: 269| 1.22M|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.22M| return fd; 277| 1.22M|} bsd_set_nonblocking: 279| 1.22M|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.22M| fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); 284| 1.22M|#endif 285| 1.22M| return fd; 286| 1.22M|} bsd_socket_nodelay: 288| 1.22M|void bsd_socket_nodelay(LIBUS_SOCKET_DESCRIPTOR fd, int enabled) { 289| 1.22M| setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void *) &enabled, sizeof(enabled)); 290| 1.22M|} bsd_create_socket: 300| 5.39k|LIBUS_SOCKET_DESCRIPTOR bsd_create_socket(int domain, int type, int protocol) { 301| | // returns INVALID_SOCKET on error 302| 5.39k| int flags = 0; 303| 5.39k|#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) 304| 5.39k| flags = SOCK_CLOEXEC | SOCK_NONBLOCK; 305| 5.39k|#endif 306| | 307| 5.39k| LIBUS_SOCKET_DESCRIPTOR created_fd = socket(domain, type | flags, protocol); ------------------ | | 38| 5.39k|#define LIBUS_SOCKET_DESCRIPTOR int ------------------ 308| | 309| 5.39k| return bsd_set_nonblocking(apple_no_sigpipe(created_fd)); 310| 5.39k|} bsd_close_socket: 312| 1.22M|void bsd_close_socket(LIBUS_SOCKET_DESCRIPTOR fd) { 313| |#ifdef _WIN32 314| | closesocket(fd); 315| |#else 316| 1.22M| close(fd); 317| 1.22M|#endif 318| 1.22M|} bsd_shutdown_socket: 320| 521k|void bsd_shutdown_socket(LIBUS_SOCKET_DESCRIPTOR fd) { 321| |#ifdef _WIN32 322| | shutdown(fd, SD_SEND); 323| |#else 324| 521k| shutdown(fd, SHUT_WR); 325| 521k|#endif 326| 521k|} internal_finalize_bsd_addr: 336| 1.22M|void internal_finalize_bsd_addr(struct bsd_addr_t *addr) { 337| | // parse, so to speak, the address 338| 1.22M| if (addr->mem.ss_family == AF_INET6) { ------------------ | Branch (338:9): [True: 285k, False: 935k] ------------------ 339| 285k| addr->ip = (char *) &((struct sockaddr_in6 *) addr)->sin6_addr; 340| 285k| addr->ip_length = sizeof(struct in6_addr); 341| 285k| addr->port = ntohs(((struct sockaddr_in6 *) addr)->sin6_port); 342| 935k| } else if (addr->mem.ss_family == AF_INET) { ------------------ | Branch (342:16): [True: 935k, False: 0] ------------------ 343| 935k| addr->ip = (char *) &((struct sockaddr_in *) addr)->sin_addr; 344| 935k| addr->ip_length = sizeof(struct in_addr); 345| 935k| addr->port = ntohs(((struct sockaddr_in *) addr)->sin_port); 346| 935k| } else { 347| 0| addr->ip_length = 0; 348| 0| addr->port = -1; 349| 0| } 350| 1.22M|} bsd_addr_get_ip: 370| 1.22M|char *bsd_addr_get_ip(struct bsd_addr_t *addr) { 371| 1.22M| return addr->ip; 372| 1.22M|} bsd_addr_get_ip_length: 374| 1.22M|int bsd_addr_get_ip_length(struct bsd_addr_t *addr) { 375| 1.22M| return addr->ip_length; 376| 1.22M|} bsd_accept_socket: 383| 2.20M|LIBUS_SOCKET_DESCRIPTOR bsd_accept_socket(LIBUS_SOCKET_DESCRIPTOR fd, struct bsd_addr_t *addr) { 384| 2.20M| LIBUS_SOCKET_DESCRIPTOR accepted_fd; ------------------ | | 38| 2.20M|#define LIBUS_SOCKET_DESCRIPTOR int ------------------ 385| 2.20M| addr->len = sizeof(addr->mem); 386| | 387| 2.20M|#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) 388| | // Linux, FreeBSD 389| 2.20M| 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| 2.20M| if (accepted_fd == LIBUS_SOCKET_ERROR) { ------------------ | | 44| 2.20M|#define LIBUS_SOCKET_ERROR -1 ------------------ | Branch (397:9): [True: 980k, False: 1.22M] ------------------ 398| 980k| return LIBUS_SOCKET_ERROR; ------------------ | | 44| 980k|#define LIBUS_SOCKET_ERROR -1 ------------------ 399| 980k| } 400| | 401| 1.22M| internal_finalize_bsd_addr(addr); 402| | 403| 1.22M| return bsd_set_nonblocking(apple_no_sigpipe(accepted_fd)); 404| 2.20M|} bsd_recv: 406| 831k|int bsd_recv(LIBUS_SOCKET_DESCRIPTOR fd, void *buf, int length, int flags) { 407| 831k| return recv(fd, buf, length, flags); 408| 831k|} bsd_send: 436| 749k|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| 749k|#ifdef MSG_MORE 445| | 446| | // for Linux we do not want signals 447| 749k| 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| 749k|} bsd_would_block: 458| 11.2k|int bsd_would_block() { 459| |#ifdef _WIN32 460| | return WSAGetLastError() == WSAEWOULDBLOCK; 461| |#else 462| 11.2k| return errno == EWOULDBLOCK;// || errno == EAGAIN; 463| 11.2k|#endif 464| 11.2k|} bsd_create_listen_socket: 468| 5.39k|LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket(const char *host, int port, int options) { 469| 5.39k| struct addrinfo hints, *result; 470| 5.39k| memset(&hints, 0, sizeof(struct addrinfo)); 471| | 472| 5.39k| hints.ai_flags = AI_PASSIVE; 473| 5.39k| hints.ai_family = AF_UNSPEC; 474| 5.39k| hints.ai_socktype = SOCK_STREAM; 475| | 476| 5.39k| char port_string[16]; 477| 5.39k| snprintf(port_string, 16, "%d", port); 478| | 479| 5.39k| if (getaddrinfo(host, port_string, &hints, &result)) { ------------------ | Branch (479:9): [True: 0, False: 5.39k] ------------------ 480| 0| return LIBUS_SOCKET_ERROR; ------------------ | | 44| 0|#define LIBUS_SOCKET_ERROR -1 ------------------ 481| 0| } 482| | 483| 5.39k| LIBUS_SOCKET_DESCRIPTOR listenFd = LIBUS_SOCKET_ERROR; ------------------ | | 38| 5.39k|#define LIBUS_SOCKET_DESCRIPTOR int ------------------ LIBUS_SOCKET_DESCRIPTOR listenFd = LIBUS_SOCKET_ERROR; ------------------ | | 44| 5.39k|#define LIBUS_SOCKET_ERROR -1 ------------------ 484| 5.39k| struct addrinfo *listenAddr; 485| 10.7k| for (struct addrinfo *a = result; a && listenFd == LIBUS_SOCKET_ERROR; a = a->ai_next) { ------------------ | | 44| 5.39k|#define LIBUS_SOCKET_ERROR -1 ------------------ | Branch (485:39): [True: 5.39k, False: 5.39k] | Branch (485:44): [True: 5.39k, False: 0] ------------------ 486| 5.39k| if (a->ai_family == AF_INET6) { ------------------ | Branch (486:13): [True: 4.09k, False: 1.29k] ------------------ 487| 4.09k| listenFd = bsd_create_socket(a->ai_family, a->ai_socktype, a->ai_protocol); 488| 4.09k| listenAddr = a; 489| 4.09k| } 490| 5.39k| } 491| | 492| 6.69k| for (struct addrinfo *a = result; a && listenFd == LIBUS_SOCKET_ERROR; a = a->ai_next) { ------------------ | | 44| 5.39k|#define LIBUS_SOCKET_ERROR -1 ------------------ | Branch (492:39): [True: 5.39k, False: 1.29k] | Branch (492:44): [True: 1.29k, False: 4.09k] ------------------ 493| 1.29k| if (a->ai_family == AF_INET) { ------------------ | Branch (493:13): [True: 1.29k, False: 2] ------------------ 494| 1.29k| listenFd = bsd_create_socket(a->ai_family, a->ai_socktype, a->ai_protocol); 495| 1.29k| listenAddr = a; 496| 1.29k| } 497| 1.29k| } 498| | 499| 5.39k| if (listenFd == LIBUS_SOCKET_ERROR) { ------------------ | | 44| 5.39k|#define LIBUS_SOCKET_ERROR -1 ------------------ | Branch (499:9): [True: 2, False: 5.39k] ------------------ 500| 2| freeaddrinfo(result); 501| 2| return LIBUS_SOCKET_ERROR; ------------------ | | 44| 2|#define LIBUS_SOCKET_ERROR -1 ------------------ 502| 2| } 503| | 504| 5.39k| if (port != 0) { ------------------ | Branch (504:9): [True: 5.39k, 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.39k| #if /*defined(__linux) &&*/ defined(SO_REUSEPORT) 516| 5.39k| if (!(options & LIBUS_LISTEN_EXCLUSIVE_PORT)) { ------------------ | Branch (516:13): [True: 5.39k, False: 0] ------------------ 517| 5.39k| int optval = 1; 518| 5.39k| setsockopt(listenFd, SOL_SOCKET, SO_REUSEPORT, (void *) &optval, sizeof(optval)); 519| 5.39k| } 520| 5.39k| #endif 521| 5.39k| int enabled = 1; 522| 5.39k| setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, (void *) &enabled, sizeof(enabled)); 523| 5.39k|#endif 524| | 525| 5.39k| } 526| | 527| 5.39k|#ifdef IPV6_V6ONLY 528| 5.39k| int disabled = 0; 529| 5.39k| setsockopt(listenFd, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &disabled, sizeof(disabled)); 530| 5.39k|#endif 531| | 532| 5.39k| if (bind(listenFd, listenAddr->ai_addr, (socklen_t) listenAddr->ai_addrlen) || listen(listenFd, 512)) { ------------------ | Branch (532:9): [True: 0, False: 5.39k] | Branch (532:84): [True: 11, False: 5.38k] ------------------ 533| 11| bsd_close_socket(listenFd); 534| 11| freeaddrinfo(result); 535| 11| return LIBUS_SOCKET_ERROR; ------------------ | | 44| 11|#define LIBUS_SOCKET_ERROR -1 ------------------ 536| 11| } 537| | 538| 5.38k| freeaddrinfo(result); 539| 5.38k| return listenFd; 540| 5.39k|} default_is_low_prio_handler: 25| 831k|int default_is_low_prio_handler(struct us_socket_t *s) { 26| 831k| return 0; 27| 831k|} us_listen_socket_close: 35| 5.38k|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.38k| if (!us_socket_is_closed(0, &ls->s)) { ------------------ | Branch (37:9): [True: 5.38k, False: 0] ------------------ 38| 5.38k| us_internal_socket_context_unlink_listen_socket(ls->s.context, ls); 39| 5.38k| us_poll_stop((struct us_poll_t *) &ls->s, ls->s.context->loop); 40| 5.38k| 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.38k| ls->s.next = ls->s.context->loop->data.closed_head; 44| 5.38k| ls->s.context->loop->data.closed_head = &ls->s; 45| | 46| | /* Any socket with prev = context is marked as closed */ 47| 5.38k| ls->s.prev = (struct us_socket_t *) ls->s.context; 48| 5.38k| } 49| | 50| | /* We cannot immediately free a listen socket as we can be inside an accept loop */ 51| 5.38k|} us_internal_socket_context_unlink_listen_socket: 71| 5.38k|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.38k| if (ls == (struct us_listen_socket_t *) context->iterator) { ------------------ | Branch (73:9): [True: 0, False: 5.38k] ------------------ 74| 0| context->iterator = ls->s.next; 75| 0| } 76| | 77| 5.38k| if (ls->s.prev == ls->s.next) { ------------------ | Branch (77:9): [True: 5.38k, False: 0] ------------------ 78| 5.38k| context->head_listen_sockets = 0; 79| 5.38k| } 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.38k|} us_internal_socket_context_unlink_socket: 91| 1.32M|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.32M| if (s == context->iterator) { ------------------ | Branch (93:9): [True: 4.30k, False: 1.32M] ------------------ 94| 4.30k| context->iterator = s->next; 95| 4.30k| } 96| | 97| 1.32M| if (s->prev == s->next) { ------------------ | Branch (97:9): [True: 263k, False: 1.06M] ------------------ 98| 263k| context->head_sockets = 0; 99| 1.06M| } else { 100| 1.06M| if (s->prev) { ------------------ | Branch (100:13): [True: 506k, False: 556k] ------------------ 101| 506k| s->prev->next = s->next; 102| 556k| } else { 103| 556k| context->head_sockets = s->next; 104| 556k| } 105| 1.06M| if (s->next) { ------------------ | Branch (105:13): [True: 1.03M, False: 26.8k] ------------------ 106| 1.03M| s->next->prev = s->prev; 107| 1.03M| } 108| 1.06M| } 109| 1.32M|} us_internal_socket_context_link_listen_socket: 112| 5.38k|void us_internal_socket_context_link_listen_socket(struct us_socket_context_t *context, struct us_listen_socket_t *ls) { 113| 5.38k| ls->s.context = context; 114| 5.38k| ls->s.next = (struct us_socket_t *) context->head_listen_sockets; 115| 5.38k| ls->s.prev = 0; 116| 5.38k| if (context->head_listen_sockets) { ------------------ | Branch (116:9): [True: 0, False: 5.38k] ------------------ 117| 0| context->head_listen_sockets->s.prev = &ls->s; 118| 0| } 119| 5.38k| context->head_listen_sockets = ls; 120| 5.38k|} us_internal_socket_context_link_socket: 123| 1.32M|void us_internal_socket_context_link_socket(struct us_socket_context_t *context, struct us_socket_t *s) { 124| 1.32M| s->context = context; 125| 1.32M| s->next = context->head_sockets; 126| 1.32M| s->prev = 0; 127| 1.32M| if (context->head_sockets) { ------------------ | Branch (127:9): [True: 1.06M, False: 263k] ------------------ 128| 1.06M| context->head_sockets->prev = s; 129| 1.06M| } 130| 1.32M| context->head_sockets = s; 131| 1.32M|} us_socket_context_loop: 133| 6.13M|struct us_loop_t *us_socket_context_loop(int ssl, struct us_socket_context_t *context) { 134| 6.13M| return context->loop; 135| 6.13M|} us_socket_server_name_userdata: 150| 124k|void *us_socket_server_name_userdata(int ssl, struct us_socket_t *s) { 151| |#ifndef LIBUS_NO_SSL 152| | if (ssl) { 153| | return us_internal_ssl_socket_get_sni_userdata((struct us_internal_ssl_socket_t *) s); 154| | } 155| |#endif 156| 124k| return NULL; 157| 124k|} us_create_socket_context: 204| 10.7k|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| 10.7k| struct us_socket_context_t *context = malloc(sizeof(struct us_socket_context_t) + context_ext_size); 216| 10.7k| context->loop = loop; 217| 10.7k| context->head_sockets = 0; 218| 10.7k| context->head_listen_sockets = 0; 219| 10.7k| context->iterator = 0; 220| 10.7k| context->next = 0; 221| 10.7k| context->is_low_prio = default_is_low_prio_handler; 222| | 223| | /* Begin at 0 */ 224| 10.7k| context->timestamp = 0; 225| 10.7k| context->long_timestamp = 0; 226| 10.7k| context->global_tick = 0; 227| | 228| | /* Some new events must be set to null for backwards compatibility */ 229| 10.7k| context->on_pre_open = 0; 230| | 231| 10.7k| 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| 10.7k| return context; 235| 10.7k|} us_socket_context_free: 237| 10.7k|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| 10.7k| us_internal_loop_unlink(context->loop, context); 250| 10.7k| free(context); 251| 10.7k|} us_socket_context_listen: 253| 5.39k|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.39k| LIBUS_SOCKET_DESCRIPTOR listen_socket_fd = bsd_create_listen_socket(host, port, options); ------------------ | | 38| 5.39k|#define LIBUS_SOCKET_DESCRIPTOR int ------------------ 261| | 262| 5.39k| if (listen_socket_fd == LIBUS_SOCKET_ERROR) { ------------------ | | 44| 5.39k|#define LIBUS_SOCKET_ERROR -1 ------------------ | Branch (262:9): [True: 13, False: 5.38k] ------------------ 263| 13| return 0; 264| 13| } 265| | 266| 5.38k| struct us_poll_t *p = us_create_poll(context->loop, 0, sizeof(struct us_listen_socket_t)); 267| 5.38k| us_poll_init(p, listen_socket_fd, POLL_TYPE_SEMI_SOCKET); 268| 5.38k| us_poll_start(p, context->loop, LIBUS_SOCKET_READABLE); ------------------ | | 27| 5.38k|#define LIBUS_SOCKET_READABLE EPOLLIN ------------------ 269| | 270| 5.38k| struct us_listen_socket_t *ls = (struct us_listen_socket_t *) p; 271| | 272| 5.38k| ls->s.context = context; 273| 5.38k| ls->s.timeout = 255; 274| 5.38k| ls->s.long_timeout = 255; 275| 5.38k| ls->s.low_prio_state = 0; 276| 5.38k| ls->s.next = 0; 277| 5.38k| us_internal_socket_context_link_listen_socket(context, ls); 278| | 279| 5.38k| ls->socket_ext_size = socket_ext_size; 280| | 281| 5.38k| return ls; 282| 5.39k|} us_create_child_socket_context: 373| 5.39k|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| 5.39k| struct us_socket_context_options_t options = {0}; 382| 5.39k| return us_create_socket_context(ssl, context->loop, context_ext_size, options); 383| 5.39k|} us_socket_context_adopt_socket: 386| 105k|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| 105k| if (us_socket_is_closed(ssl, s)) { ------------------ | Branch (394:9): [True: 0, False: 105k] ------------------ 395| 0| return s; 396| 0| } 397| | 398| 105k| if (s->low_prio_state != 1) { ------------------ | Branch (398:9): [True: 105k, False: 0] ------------------ 399| | /* This properly updates the iterator if in on_timeout */ 400| 105k| us_internal_socket_context_unlink_socket(s->context, s); 401| 105k| } 402| | 403| 105k| 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| 105k| new_s->timeout = 255; 405| 105k| new_s->long_timeout = 255; 406| | 407| 105k| if (new_s->low_prio_state == 1) { ------------------ | Branch (407:9): [True: 0, False: 105k] ------------------ 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| 105k| } else { 414| 105k| us_internal_socket_context_link_socket(context, new_s); 415| 105k| } 416| | 417| 105k| return new_s; 418| 105k|} us_socket_context_on_open: 426| 5.39k|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.39k| context->on_open = on_open; 435| 5.39k|} us_socket_context_on_close: 437| 10.7k|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| 10.7k| context->on_close = on_close; 446| 10.7k|} us_socket_context_on_data: 448| 10.7k|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| 10.7k| context->on_data = on_data; 457| 10.7k|} us_socket_context_on_writable: 459| 10.7k|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| 10.7k| context->on_writable = on_writable; 468| 10.7k|} us_socket_context_on_long_timeout: 470| 5.39k|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| 5.39k| context->on_socket_long_timeout = on_long_timeout; 479| 5.39k|} us_socket_context_on_timeout: 481| 10.7k|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| 10.7k| context->on_socket_timeout = on_timeout; 490| 10.7k|} us_socket_context_on_end: 492| 10.7k|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| 10.7k| context->on_end = on_end; 501| 10.7k|} us_socket_context_ext: 514| 16.4M|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| 16.4M| return context + 1; 522| 16.4M|} us_loop_free: 36| 5.39k|void us_loop_free(struct us_loop_t *loop) { 37| 5.39k| us_internal_loop_data_free(loop); 38| 5.39k| close(loop->fd); 39| 5.39k| free(loop); 40| 5.39k|} us_create_poll: 43| 1.24M|struct us_poll_t *us_create_poll(struct us_loop_t *loop, int fallthrough, unsigned int ext_size) { 44| 1.24M| if (!fallthrough) { ------------------ | Branch (44:9): [True: 1.22M, False: 16.1k] ------------------ 45| 1.22M| loop->num_polls++; 46| 1.22M| } 47| 1.24M| return malloc(sizeof(struct us_poll_t) + ext_size); 48| 1.24M|} us_poll_free: 51| 1.24M|void us_poll_free(struct us_poll_t *p, struct us_loop_t *loop) { 52| 1.24M| loop->num_polls--; 53| 1.24M| free(p); 54| 1.24M|} us_poll_init: 61| 1.24M|void us_poll_init(struct us_poll_t *p, LIBUS_SOCKET_DESCRIPTOR fd, int poll_type) { 62| 1.24M| p->state.fd = fd; 63| 1.24M| p->state.poll_type = poll_type; 64| 1.24M|} us_poll_events: 66| 9.68M|int us_poll_events(struct us_poll_t *p) { 67| 9.68M| 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| 9.68M|#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| 9.68M|#define LIBUS_SOCKET_WRITABLE EPOLLOUT ------------------ | Branch (67:13): [True: 9.61M, False: 61.8k] | Branch (67:89): [True: 1.41M, False: 8.26M] ------------------ 68| 9.68M|} us_poll_fd: 70| 8.60M|LIBUS_SOCKET_DESCRIPTOR us_poll_fd(struct us_poll_t *p) { 71| 8.60M| return p->state.fd; 72| 8.60M|} us_internal_poll_type: 75| 9.94M|int us_internal_poll_type(struct us_poll_t *p) { 76| 9.94M| return p->state.poll_type & 3; 77| 9.94M|} us_internal_poll_set_type: 80| 521k|void us_internal_poll_set_type(struct us_poll_t *p, int poll_type) { 81| 521k| p->state.poll_type = poll_type | (p->state.poll_type & 12); 82| 521k|} us_timer_ext: 85| 935k|void *us_timer_ext(struct us_timer_t *timer) { 86| 935k| return ((struct us_internal_callback_t *) timer) + 1; 87| 935k|} us_create_loop: 96| 5.39k|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.39k| struct us_loop_t *loop = (struct us_loop_t *) malloc(sizeof(struct us_loop_t) + ext_size); 98| 5.39k| loop->num_polls = 0; 99| | /* These could be accessed if we close a poll before starting the loop */ 100| 5.39k| loop->num_ready_polls = 0; 101| 5.39k| loop->current_ready_poll = 0; 102| | 103| 5.39k|#ifdef LIBUS_USE_EPOLL 104| 5.39k| loop->fd = epoll_create1(EPOLL_CLOEXEC); 105| |#else 106| | loop->fd = kqueue(); 107| |#endif 108| | 109| 5.39k| us_internal_loop_data_init(loop, wakeup_cb, pre_cb, post_cb); 110| 5.39k| return loop; 111| 5.39k|} us_loop_run: 113| 5.39k|void us_loop_run(struct us_loop_t *loop) { 114| 5.39k| us_loop_integrate(loop); 115| | 116| | /* While we have non-fallthrough polls we shouldn't fall through */ 117| 1.30M| while (loop->num_polls) { ------------------ | Branch (117:12): [True: 1.29M, False: 5.39k] ------------------ 118| | /* Emit pre callback */ 119| 1.29M| us_internal_loop_pre(loop); 120| | 121| | /* Fetch ready polls */ 122| 1.29M|#ifdef LIBUS_USE_EPOLL 123| 1.29M| 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| 6.73M| for (loop->current_ready_poll = 0; loop->current_ready_poll < loop->num_ready_polls; loop->current_ready_poll++) { ------------------ | Branch (129:44): [True: 5.43M, False: 1.29M] ------------------ 130| 5.43M| struct us_poll_t *poll = GET_READY_POLL(loop, loop->current_ready_poll); ------------------ | | 28| 5.43M|#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| 5.43M| if (poll) { ------------------ | Branch (132:17): [True: 5.43M, False: 0] ------------------ 133| 5.43M|#ifdef LIBUS_USE_EPOLL 134| 5.43M| int events = loop->ready_polls[loop->current_ready_poll].events; 135| 5.43M| 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| 5.43M| events &= us_poll_events(poll); 146| 5.43M| if (events || error) { ------------------ | Branch (146:21): [True: 3.66M, False: 1.77M] | Branch (146:31): [True: 1.77M, False: 0] ------------------ 147| 5.43M| us_internal_dispatch_ready_poll(poll, error, events); 148| 5.43M| } 149| 5.43M| } 150| 5.43M| } 151| | /* Emit post callback */ 152| 1.29M| us_internal_loop_post(loop); 153| 1.29M| } 154| 5.39k|} us_internal_loop_update_pending_ready_polls: 156| 1.24M|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.24M|#ifdef LIBUS_USE_EPOLL 158| | /* Epoll only has one ready poll per poll */ 159| 1.24M| 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| 2.47M| for (int i = loop->current_ready_poll; i < loop->num_ready_polls && num_entries_possibly_remaining; i++) { ------------------ | Branch (168:44): [True: 2.43M, False: 37.8k] | Branch (168:73): [True: 1.22M, False: 1.20M] ------------------ 169| 1.22M| if (GET_READY_POLL(loop, i) == old_poll) { ------------------ | | 28| 1.22M|#define GET_READY_POLL(loop, index) (struct us_poll_t *) loop->ready_polls[index].data.ptr ------------------ | Branch (169:13): [True: 1.21M, False: 12.9k] ------------------ 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.21M| SET_READY_POLL(loop, i, new_poll); ------------------ | | 29| 1.21M|#define SET_READY_POLL(loop, index, poll) loop->ready_polls[index].data.ptr = poll ------------------ 173| | 174| 1.21M| num_entries_possibly_remaining--; 175| 1.21M| } 176| 1.22M| } 177| 1.24M|} us_poll_resize: 205| 105k|struct us_poll_t *us_poll_resize(struct us_poll_t *p, struct us_loop_t *loop, unsigned int ext_size) { 206| 105k| int events = us_poll_events(p); 207| | 208| 105k| struct us_poll_t *new_p = realloc(p, sizeof(struct us_poll_t) + ext_size); 209| 105k| if (p != new_p && events) { ------------------ | Branch (209:9): [True: 0, False: 105k] | 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| 105k| return new_p; 224| 105k|} us_poll_start: 226| 1.24M|void us_poll_start(struct us_poll_t *p, struct us_loop_t *loop, int events) { 227| 1.24M| 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.24M|#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.24M|#define LIBUS_SOCKET_WRITABLE EPOLLOUT ------------------ | Branch (227:54): [True: 1.24M, False: 0] | Branch (227:118): [True: 0, False: 1.24M] ------------------ 228| | 229| 1.24M|#ifdef LIBUS_USE_EPOLL 230| 1.24M| struct epoll_event event; 231| 1.24M| event.events = events; 232| 1.24M| event.data.ptr = p; 233| 1.24M| 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.24M|} us_poll_change: 239| 1.32M|void us_poll_change(struct us_poll_t *p, struct us_loop_t *loop, int events) { 240| 1.32M| int old_events = us_poll_events(p); 241| 1.32M| if (old_events != events) { ------------------ | Branch (241:9): [True: 1.21M, False: 115k] ------------------ 242| | 243| 1.21M| 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.21M|#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.21M|#define LIBUS_SOCKET_WRITABLE EPOLLOUT ------------------ | Branch (243:58): [True: 1.14M, False: 61.8k] | Branch (243:122): [True: 629k, False: 581k] ------------------ 244| | 245| 1.21M|#ifdef LIBUS_USE_EPOLL 246| 1.21M| struct epoll_event event; 247| 1.21M| event.events = events; 248| 1.21M| event.data.ptr = p; 249| 1.21M| 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.21M| } 256| 1.32M|} us_poll_stop: 258| 1.24M|void us_poll_stop(struct us_poll_t *p, struct us_loop_t *loop) { 259| 1.24M| int old_events = us_poll_events(p); 260| 1.24M| int new_events = 0; 261| 1.24M|#ifdef LIBUS_USE_EPOLL 262| 1.24M| struct epoll_event event; 263| 1.24M| 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.24M| us_internal_loop_update_pending_ready_polls(loop, p, 0, old_events, new_events); 272| 1.24M|} us_internal_accept_poll_event: 274| 3.04M|unsigned int us_internal_accept_poll_event(struct us_poll_t *p) { 275| 3.04M|#ifdef LIBUS_USE_EPOLL 276| 3.04M| int fd = us_poll_fd(p); 277| 3.04M| uint64_t buf; 278| 3.04M| int read_length = read(fd, &buf, 8); 279| 3.04M| (void)read_length; 280| 3.04M| return buf; 281| |#else 282| | /* Kqueue has no underlying FD for timers or user events */ 283| | return 0; 284| |#endif 285| 3.04M|} us_create_timer: 289| 10.7k|struct us_timer_t *us_create_timer(struct us_loop_t *loop, int fallthrough, unsigned int ext_size) { 290| 10.7k| struct us_poll_t *p = us_create_poll(loop, fallthrough, sizeof(struct us_internal_callback_t) + ext_size); 291| 10.7k| int timerfd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK | TFD_CLOEXEC); 292| 10.7k| if (timerfd == -1) { ------------------ | Branch (292:9): [True: 0, False: 10.7k] ------------------ 293| 0| return NULL; 294| 0| } 295| 10.7k| us_poll_init(p, timerfd, POLL_TYPE_CALLBACK); 296| | 297| 10.7k| struct us_internal_callback_t *cb = (struct us_internal_callback_t *) p; 298| 10.7k| cb->loop = loop; 299| 10.7k| cb->cb_expects_the_loop = 0; 300| 10.7k| cb->leave_poll_ready = 0; 301| | 302| 10.7k| return (struct us_timer_t *) cb; 303| 10.7k|} us_timer_close: 325| 10.7k|void us_timer_close(struct us_timer_t *timer) { 326| 10.7k| struct us_internal_callback_t *cb = (struct us_internal_callback_t *) timer; 327| | 328| 10.7k| us_poll_stop(&cb->p, cb->loop); 329| 10.7k| close(us_poll_fd(&cb->p)); 330| | 331| | /* (regular) sockets are the only polls which are not freed immediately */ 332| 10.7k| us_poll_free((struct us_poll_t *) timer, cb->loop); 333| 10.7k|} us_timer_set: 335| 10.7k|void us_timer_set(struct us_timer_t *t, void (*cb)(struct us_timer_t *t), int ms, int repeat_ms) { 336| 10.7k| struct us_internal_callback_t *internal_cb = (struct us_internal_callback_t *) t; 337| | 338| 10.7k| internal_cb->cb = (void (*)(struct us_internal_callback_t *)) cb; 339| | 340| 10.7k| struct itimerspec timer_spec = { 341| 10.7k| {repeat_ms / 1000, (long) (repeat_ms % 1000) * (long) 1000000}, 342| 10.7k| {ms / 1000, (long) (ms % 1000) * (long) 1000000} 343| 10.7k| }; 344| | 345| 10.7k| timerfd_settime(us_poll_fd((struct us_poll_t *) t), 0, &timer_spec, NULL); 346| 10.7k| us_poll_start((struct us_poll_t *) t, internal_cb->loop, LIBUS_SOCKET_READABLE); ------------------ | | 27| 10.7k|#define LIBUS_SOCKET_READABLE EPOLLIN ------------------ 347| 10.7k|} us_internal_create_async: 374| 5.39k|struct us_internal_async *us_internal_create_async(struct us_loop_t *loop, int fallthrough, unsigned int ext_size) { 375| 5.39k| struct us_poll_t *p = us_create_poll(loop, fallthrough, sizeof(struct us_internal_callback_t) + ext_size); 376| 5.39k| us_poll_init(p, eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC), POLL_TYPE_CALLBACK); 377| | 378| 5.39k| struct us_internal_callback_t *cb = (struct us_internal_callback_t *) p; 379| 5.39k| cb->loop = loop; 380| 5.39k| cb->cb_expects_the_loop = 1; 381| 5.39k| cb->leave_poll_ready = 0; 382| | 383| 5.39k| return (struct us_internal_async *) cb; 384| 5.39k|} us_internal_async_close: 387| 5.39k|void us_internal_async_close(struct us_internal_async *a) { 388| 5.39k| struct us_internal_callback_t *cb = (struct us_internal_callback_t *) a; 389| | 390| 5.39k| us_poll_stop(&cb->p, cb->loop); 391| 5.39k| close(us_poll_fd(&cb->p)); 392| | 393| | /* (regular) sockets are the only polls which are not freed immediately */ 394| 5.39k| us_poll_free((struct us_poll_t *) a, cb->loop); 395| 5.39k|} us_internal_async_set: 397| 5.39k|void us_internal_async_set(struct us_internal_async *a, void (*cb)(struct us_internal_async *)) { 398| 5.39k| struct us_internal_callback_t *internal_cb = (struct us_internal_callback_t *) a; 399| | 400| 5.39k| internal_cb->cb = (void (*)(struct us_internal_callback_t *)) cb; 401| | 402| 5.39k| us_poll_start((struct us_poll_t *) a, internal_cb->loop, LIBUS_SOCKET_READABLE); ------------------ | | 27| 5.39k|#define LIBUS_SOCKET_READABLE EPOLLIN ------------------ 403| 5.39k|} us_internal_loop_data_init: 26| 5.39k| void (*pre_cb)(struct us_loop_t *loop), void (*post_cb)(struct us_loop_t *loop)) { 27| 5.39k| loop->data.sweep_timer = us_create_timer(loop, 1, 0); 28| 5.39k| loop->data.recv_buf = malloc(LIBUS_RECV_BUFFER_LENGTH + LIBUS_RECV_BUFFER_PADDING * 2); ------------------ | | 22| 5.39k|#define LIBUS_RECV_BUFFER_LENGTH 524288 ------------------ loop->data.recv_buf = malloc(LIBUS_RECV_BUFFER_LENGTH + LIBUS_RECV_BUFFER_PADDING * 2); ------------------ | | 26| 5.39k|#define LIBUS_RECV_BUFFER_PADDING 32 ------------------ 29| 5.39k| loop->data.ssl_data = 0; 30| 5.39k| loop->data.head = 0; 31| 5.39k| loop->data.iterator = 0; 32| 5.39k| loop->data.closed_head = 0; 33| 5.39k| loop->data.low_prio_head = 0; 34| 5.39k| loop->data.low_prio_budget = 0; 35| | 36| 5.39k| loop->data.pre_cb = pre_cb; 37| 5.39k| loop->data.post_cb = post_cb; 38| 5.39k| loop->data.iteration_nr = 0; 39| | 40| 5.39k| loop->data.wakeup_async = us_internal_create_async(loop, 1, 0); 41| 5.39k| us_internal_async_set(loop->data.wakeup_async, (void (*)(struct us_internal_async *)) wakeup_cb); 42| 5.39k|} us_internal_loop_data_free: 44| 5.39k|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.39k| free(loop->data.recv_buf); 50| | 51| 5.39k| us_timer_close(loop->data.sweep_timer); 52| 5.39k| us_internal_async_close(loop->data.wakeup_async); 53| 5.39k|} us_internal_loop_link: 59| 10.7k|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| 10.7k| context->next = loop->data.head; 62| 10.7k| context->prev = 0; 63| 10.7k| if (loop->data.head) { ------------------ | Branch (63:9): [True: 5.39k, False: 5.39k] ------------------ 64| 5.39k| loop->data.head->prev = context; 65| 5.39k| } 66| 10.7k| loop->data.head = context; 67| 10.7k|} us_internal_loop_unlink: 70| 10.7k|void us_internal_loop_unlink(struct us_loop_t *loop, struct us_socket_context_t *context) { 71| 10.7k| if (loop->data.head == context) { ------------------ | Branch (71:9): [True: 5.39k, False: 5.39k] ------------------ 72| 5.39k| loop->data.head = context->next; 73| 5.39k| if (loop->data.head) { ------------------ | Branch (73:13): [True: 0, False: 5.39k] ------------------ 74| 0| loop->data.head->prev = 0; 75| 0| } 76| 5.39k| } else { 77| 5.39k| context->prev->next = context->next; 78| 5.39k| if (context->next) { ------------------ | Branch (78:13): [True: 0, False: 5.39k] ------------------ 79| 0| context->next->prev = context->prev; 80| 0| } 81| 5.39k| } 82| 10.7k|} us_internal_timer_sweep: 85| 1.05M|void us_internal_timer_sweep(struct us_loop_t *loop) { 86| 1.05M| struct us_internal_loop_data_t *loop_data = &loop->data; 87| | /* For all socket contexts in this loop */ 88| 3.15M| for (loop_data->iterator = loop_data->head; loop_data->iterator; loop_data->iterator = loop_data->iterator->next) { ------------------ | Branch (88:49): [True: 2.10M, False: 1.05M] ------------------ 89| | 90| 2.10M| 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| 2.10M| context->global_tick++; 94| 2.10M| unsigned char short_ticks = context->timestamp = context->global_tick % 240; 95| 2.10M| unsigned char long_ticks = context->long_timestamp = (context->global_tick / 15) % 240; 96| | 97| | /* Begin at head */ 98| 2.10M| struct us_socket_t *s = context->head_sockets; 99| 2.10M| while (s) { ------------------ | Branch (99:16): [True: 62.8k, False: 2.04M] ------------------ 100| | /* Seek until end or timeout found (tightest loop) */ 101| 189k| while (1) { ------------------ | Branch (101:20): [Folded - Ignored] ------------------ 102| | /* We only read from 1 random cache line here */ 103| 189k| if (short_ticks == s->timeout || long_ticks == s->long_timeout) { ------------------ | Branch (103:21): [True: 4.30k, False: 185k] | Branch (103:50): [True: 0, False: 185k] ------------------ 104| 4.30k| break; 105| 4.30k| } 106| | 107| | /* Did we reach the end without a find? */ 108| 185k| if ((s = s->next) == 0) { ------------------ | Branch (108:21): [True: 58.5k, False: 126k] ------------------ 109| 58.5k| goto next_context; 110| 58.5k| } 111| 185k| } 112| | 113| | /* Here we have a timeout to emit (slow path) */ 114| 4.30k| context->iterator = s; 115| | 116| 4.30k| if (short_ticks == s->timeout) { ------------------ | Branch (116:17): [True: 4.30k, False: 0] ------------------ 117| 4.30k| s->timeout = 255; 118| 4.30k| context->on_socket_timeout(s); 119| 4.30k| } 120| | 121| 4.30k| if (context->iterator == s && long_ticks == s->long_timeout) { ------------------ | Branch (121:17): [True: 0, False: 4.30k] | Branch (121:43): [True: 0, False: 0] ------------------ 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| 4.30k| if (s == context->iterator) { ------------------ | Branch (127:17): [True: 0, False: 4.30k] ------------------ 128| 0| s = s->next; 129| 4.30k| } else { 130| | /* The iterator was changed by event handler */ 131| 4.30k| s = context->iterator; 132| 4.30k| } 133| 4.30k| } 134| | /* We always store a 0 to context->iterator here since we are no longer iterating this context */ 135| 2.10M| next_context: 136| 2.10M| context->iterator = 0; 137| 2.10M| } 138| 1.05M|} us_internal_handle_low_priority_sockets: 145| 1.29M|void us_internal_handle_low_priority_sockets(struct us_loop_t *loop) { 146| 1.29M| struct us_internal_loop_data_t *loop_data = &loop->data; 147| 1.29M| struct us_socket_t *s; 148| | 149| 1.29M| loop_data->low_prio_budget = MAX_LOW_PRIO_SOCKETS_PER_LOOP_ITERATION; 150| | 151| 1.29M| 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: 1.29M] | 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| 1.29M|} us_internal_free_closed_sockets: 165| 1.29M|void us_internal_free_closed_sockets(struct us_loop_t *loop) { 166| | /* Free all closed sockets (maybe it is better to reverse order?) */ 167| 1.29M| if (loop->data.closed_head) { ------------------ | Branch (167:9): [True: 285k, False: 1.01M] ------------------ 168| 1.51M| for (struct us_socket_t *s = loop->data.closed_head; s; ) { ------------------ | Branch (168:62): [True: 1.22M, False: 285k] ------------------ 169| 1.22M| struct us_socket_t *next = s->next; 170| 1.22M| us_poll_free((struct us_poll_t *) s, loop); 171| 1.22M| s = next; 172| 1.22M| } 173| 285k| loop->data.closed_head = 0; 174| 285k| } 175| 1.29M|} sweep_timer_cb: 177| 1.05M|void sweep_timer_cb(struct us_internal_callback_t *cb) { 178| 1.05M| us_internal_timer_sweep(cb->loop); 179| 1.05M|} us_internal_loop_pre: 186| 1.29M|void us_internal_loop_pre(struct us_loop_t *loop) { 187| 1.29M| loop->data.iteration_nr++; 188| 1.29M| us_internal_handle_low_priority_sockets(loop); 189| 1.29M| loop->data.pre_cb(loop); 190| 1.29M|} us_internal_loop_post: 192| 1.29M|void us_internal_loop_post(struct us_loop_t *loop) { 193| 1.29M| us_internal_free_closed_sockets(loop); 194| 1.29M| loop->data.post_cb(loop); 195| 1.29M|} us_adopt_accepted_socket: 198| 1.22M| 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.22M| 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.22M| us_poll_init(accepted_p, accepted_fd, POLL_TYPE_SOCKET); 207| 1.22M| us_poll_start(accepted_p, context->loop, LIBUS_SOCKET_READABLE); ------------------ | | 27| 1.22M|#define LIBUS_SOCKET_READABLE EPOLLIN ------------------ 208| | 209| 1.22M| struct us_socket_t *s = (struct us_socket_t *) accepted_p; 210| | 211| 1.22M| s->context = context; 212| 1.22M| s->timeout = 255; 213| 1.22M| s->long_timeout = 255; 214| 1.22M| s->low_prio_state = 0; 215| | 216| | /* We always use nodelay */ 217| 1.22M| bsd_socket_nodelay(accepted_fd, 1); 218| | 219| 1.22M| us_internal_socket_context_link_socket(context, s); 220| | 221| 1.22M| context->on_open(s, 0, addr_ip, addr_ip_length); 222| 1.22M| return s; 223| 1.22M|} us_internal_dispatch_ready_poll: 225| 5.43M|void us_internal_dispatch_ready_poll(struct us_poll_t *p, int error, int events) { 226| 5.43M| switch (us_internal_poll_type(p)) { ------------------ | Branch (226:13): [True: 0, False: 5.43M] ------------------ 227| 3.04M| case POLL_TYPE_CALLBACK: { ------------------ | Branch (227:5): [True: 3.04M, False: 2.39M] ------------------ 228| 3.04M| 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| 3.04M| if (!cb->leave_poll_ready) { ------------------ | Branch (230:17): [True: 3.04M, False: 0] ------------------ 231| | /* Let's just have this macro to silence the CodeQL alert regarding empty function when using libuv */ 232| 3.04M| #ifndef LIBUS_USE_LIBUV 233| 3.04M| us_internal_accept_poll_event(p); 234| 3.04M| #endif 235| 3.04M| } 236| 3.04M| 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.06M, False: 1.98M] ------------------ 237| 3.04M| } 238| 3.04M| break; 239| 980k| case POLL_TYPE_SEMI_SOCKET: { ------------------ | Branch (239:5): [True: 980k, False: 4.45M] ------------------ 240| | /* Both connect and listen sockets are semi-sockets 241| | * but they poll for different events */ 242| 980k| if (us_poll_events(p) == LIBUS_SOCKET_WRITABLE) { ------------------ | | 28| 980k|#define LIBUS_SOCKET_WRITABLE EPOLLOUT ------------------ | Branch (242:17): [True: 0, False: 980k] ------------------ 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| 980k| } else { 266| 980k| struct us_listen_socket_t *listen_socket = (struct us_listen_socket_t *) p; 267| 980k| struct bsd_addr_t addr; 268| | 269| 980k| LIBUS_SOCKET_DESCRIPTOR client_fd = bsd_accept_socket(us_poll_fd(p), &addr); ------------------ | | 38| 980k|#define LIBUS_SOCKET_DESCRIPTOR int ------------------ 270| 980k| if (client_fd == LIBUS_SOCKET_ERROR) { ------------------ | | 44| 980k|#define LIBUS_SOCKET_ERROR -1 ------------------ | Branch (270:21): [True: 783k, False: 196k] ------------------ 271| | /* Todo: start timer here */ 272| | 273| 783k| } else { 274| | 275| | /* Todo: stop timer if any */ 276| | 277| 1.22M| do { 278| 1.22M| 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.22M| if (context->on_pre_open == 0 || context->on_pre_open(client_fd) == client_fd) { ------------------ | Branch (280:29): [True: 1.22M, False: 0] | Branch (280:58): [True: 0, False: 0] ------------------ 281| | 282| | /* Adopt the newly accepted socket */ 283| 1.22M| us_adopt_accepted_socket(0, context, 284| 1.22M| 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.22M| if (us_socket_is_closed(0, &listen_socket->s)) { ------------------ | Branch (287:33): [True: 0, False: 1.22M] ------------------ 288| 0| break; 289| 0| } 290| | 291| 1.22M| } 292| | 293| 1.22M| } while ((client_fd = bsd_accept_socket(us_poll_fd(p), &addr)) != LIBUS_SOCKET_ERROR); ------------------ | | 44| 1.22M|#define LIBUS_SOCKET_ERROR -1 ------------------ | Branch (293:30): [True: 1.02M, False: 196k] ------------------ 294| 196k| } 295| 980k| } 296| 980k| } 297| 0| break; 298| 2.10k| case POLL_TYPE_SOCKET_SHUT_DOWN: ------------------ | Branch (298:5): [True: 2.10k, False: 5.43M] ------------------ 299| 1.41M| case POLL_TYPE_SOCKET: { ------------------ | Branch (299:5): [True: 1.41M, False: 4.02M] ------------------ 300| | /* We should only use s, no p after this point */ 301| 1.41M| struct us_socket_t *s = (struct us_socket_t *) p; 302| | 303| | /* Such as epollerr epollhup */ 304| 1.41M| if (error) { ------------------ | Branch (304:17): [True: 576k, False: 837k] ------------------ 305| | /* Todo: decide what code we give here */ 306| 576k| s = us_socket_close(0, s, 0, NULL); 307| 576k| return; 308| 576k| } 309| | 310| 837k| if (events & LIBUS_SOCKET_WRITABLE) { ------------------ | | 28| 837k|#define LIBUS_SOCKET_WRITABLE EPOLLOUT ------------------ | Branch (310:17): [True: 20.1k, False: 817k] ------------------ 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| 20.1k| s->context->loop->data.last_write_failed = 0; 314| | 315| 20.1k| s = s->context->on_writable(s); 316| | 317| 20.1k| if (us_socket_is_closed(0, s)) { ------------------ | Branch (317:21): [True: 194, False: 19.9k] ------------------ 318| 194| return; 319| 194| } 320| | 321| | /* If we have no failed write or if we shut down, then stop polling for more writable */ 322| 19.9k| if (!s->context->loop->data.last_write_failed || us_socket_is_shut_down(0, s)) { ------------------ | Branch (322:21): [True: 2.45k, False: 17.5k] | Branch (322:66): [True: 0, False: 17.5k] ------------------ 323| 2.45k| us_poll_change(&s->p, us_socket_context(0, s)->loop, us_poll_events(&s->p) & LIBUS_SOCKET_READABLE); ------------------ | | 27| 2.45k|#define LIBUS_SOCKET_READABLE EPOLLIN ------------------ 324| 2.45k| } 325| 19.9k| } 326| | 327| 836k| if (events & LIBUS_SOCKET_READABLE) { ------------------ | | 27| 836k|#define LIBUS_SOCKET_READABLE EPOLLIN ------------------ | Branch (327:17): [True: 831k, False: 5.29k] ------------------ 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| 831k| if (s->context->is_low_prio(s)) { ------------------ | Branch (331:21): [True: 0, False: 831k] ------------------ 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| 831k| int length; 355| 831k| read_more: 356| 831k| length = bsd_recv(us_poll_fd(&s->p), s->context->loop->data.recv_buf + LIBUS_RECV_BUFFER_PADDING, LIBUS_RECV_BUFFER_LENGTH, 0); ------------------ | | 26| 831k|#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| 831k|#define LIBUS_RECV_BUFFER_LENGTH 524288 ------------------ 357| 831k| if (length > 0) { ------------------ | Branch (357:21): [True: 757k, False: 73.8k] ------------------ 358| 757k| s = s->context->on_data(s, s->context->loop->data.recv_buf + LIBUS_RECV_BUFFER_PADDING, length); ------------------ | | 26| 757k|#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| 757k| if (length == LIBUS_RECV_BUFFER_LENGTH && s && !us_socket_is_closed(0, s)) { ------------------ | | 22| 1.51M|#define LIBUS_RECV_BUFFER_LENGTH 524288 ------------------ | Branch (363:25): [True: 0, False: 757k] | Branch (363:63): [True: 0, False: 0] | Branch (363:68): [True: 0, False: 0] ------------------ 364| 0| goto read_more; 365| 0| } 366| | 367| 757k| } else if (!length) { ------------------ | Branch (367:28): [True: 62.6k, False: 11.2k] ------------------ 368| 62.6k| if (us_socket_is_shut_down(0, s)) { ------------------ | Branch (368:25): [True: 821, False: 61.8k] ------------------ 369| | /* We got FIN back after sending it */ 370| | /* Todo: We should give "CLEAN SHUTDOWN" as reason here */ 371| 821| s = us_socket_close(0, s, 0, NULL); 372| 61.8k| } else { 373| | /* We got FIN, so stop polling for readable */ 374| 61.8k| us_poll_change(&s->p, us_socket_context(0, s)->loop, us_poll_events(&s->p) & LIBUS_SOCKET_WRITABLE); ------------------ | | 28| 61.8k|#define LIBUS_SOCKET_WRITABLE EPOLLOUT ------------------ 375| 61.8k| s = s->context->on_end(s); 376| 61.8k| } 377| 62.6k| } else if (length == LIBUS_SOCKET_ERROR && !bsd_would_block()) { ------------------ | | 44| 22.4k|#define LIBUS_SOCKET_ERROR -1 ------------------ | Branch (377:28): [True: 11.2k, False: 0] | Branch (377:60): [True: 0, False: 11.2k] ------------------ 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| 831k| } 382| 836k| } 383| 836k| break; 384| 5.43M| } 385| 5.43M|} us_loop_integrate: 388| 5.39k|void us_loop_integrate(struct us_loop_t *loop) { 389| 5.39k| 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.39k|#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.39k|#define LIBUS_TIMEOUT_GRANULARITY 4 ------------------ 390| 5.39k|} us_loop_ext: 392| 9.83M|void *us_loop_ext(struct us_loop_t *loop) { 393| 9.83M| return loop + 1; 394| 9.83M|} us_socket_context: 61| 23.6M|struct us_socket_context_t *us_socket_context(int ssl, struct us_socket_t *s) { 62| 23.6M| return s->context; 63| 23.6M|} us_socket_timeout: 65| 1.71M|void us_socket_timeout(int ssl, struct us_socket_t *s, unsigned int seconds) { 66| 1.71M| if (seconds) { ------------------ | Branch (66:9): [True: 1.58M, False: 124k] ------------------ 67| 1.58M| s->timeout = ((unsigned int)s->context->timestamp + ((seconds + 3) >> 2)) % 240; 68| 1.58M| } else { 69| 124k| s->timeout = 255; 70| 124k| } 71| 1.71M|} us_socket_long_timeout: 73| 105k|void us_socket_long_timeout(int ssl, struct us_socket_t *s, unsigned int minutes) { 74| 105k| if (minutes) { ------------------ | Branch (74:9): [True: 0, False: 105k] ------------------ 75| 0| s->long_timeout = ((unsigned int)s->context->long_timestamp + minutes) % 240; 76| 105k| } else { 77| 105k| s->long_timeout = 255; 78| 105k| } 79| 105k|} us_socket_is_closed: 87| 8.62M|int us_socket_is_closed(int ssl, struct us_socket_t *s) { 88| 8.62M| return s->prev == (struct us_socket_t *) s->context; 89| 8.62M|} us_socket_close: 116| 1.22M|struct us_socket_t *us_socket_close(int ssl, struct us_socket_t *s, int code, void *reason) { 117| 1.22M| if (!us_socket_is_closed(0, s)) { ------------------ | Branch (117:9): [True: 1.22M, False: 0] ------------------ 118| 1.22M| if (s->low_prio_state == 1) { ------------------ | Branch (118:13): [True: 0, False: 1.22M] ------------------ 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.22M| } else { 129| 1.22M| us_internal_socket_context_unlink_socket(s->context, s); 130| 1.22M| } 131| 1.22M| us_poll_stop((struct us_poll_t *) s, s->context->loop); 132| 1.22M| 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.22M| s->next = s->context->loop->data.closed_head; 136| 1.22M| s->context->loop->data.closed_head = s; 137| | 138| | /* Any socket with prev = context is marked as closed */ 139| 1.22M| s->prev = (struct us_socket_t *) s->context; 140| | 141| 1.22M| return s->context->on_close(s, code, reason); 142| 1.22M| } 143| 0| return s; 144| 1.22M|} us_socket_write: 173| 749k|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| 749k| if (us_socket_is_closed(ssl, s) || us_socket_is_shut_down(ssl, s)) { ------------------ | Branch (180:9): [True: 0, False: 749k] | Branch (180:40): [True: 0, False: 749k] ------------------ 181| 0| return 0; 182| 0| } 183| | 184| 749k| int written = bsd_send(us_poll_fd(&s->p), data, length, msg_more); 185| 749k| if (written != length) { ------------------ | Branch (185:9): [True: 740k, False: 8.85k] ------------------ 186| 740k| s->context->loop->data.last_write_failed = 1; 187| 740k| us_poll_change(&s->p, s->context->loop, LIBUS_SOCKET_READABLE | LIBUS_SOCKET_WRITABLE); ------------------ | | 27| 740k|#define LIBUS_SOCKET_READABLE EPOLLIN ------------------ us_poll_change(&s->p, s->context->loop, LIBUS_SOCKET_READABLE | LIBUS_SOCKET_WRITABLE); ------------------ | | 28| 740k|#define LIBUS_SOCKET_WRITABLE EPOLLOUT ------------------ 188| 740k| } 189| | 190| 749k| return written < 0 ? 0 : written; ------------------ | Branch (190:12): [True: 7.26k, False: 741k] ------------------ 191| 749k|} us_socket_ext: 193| 21.1M|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| 21.1M| return s + 1; 201| 21.1M|} us_socket_is_shut_down: 203| 2.04M|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| 2.04M| return us_internal_poll_type(&s->p) == POLL_TYPE_SOCKET_SHUT_DOWN; 211| 2.04M|} us_socket_shutdown: 213| 522k|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| 522k| if (!us_socket_is_closed(ssl, s) && !us_socket_is_shut_down(ssl, s)) { ------------------ | Branch (224:9): [True: 522k, False: 0] | Branch (224:41): [True: 521k, False: 348] ------------------ 225| 521k| us_internal_poll_set_type(&s->p, POLL_TYPE_SOCKET_SHUT_DOWN); 226| 521k| us_poll_change(&s->p, s->context->loop, us_poll_events(&s->p) & LIBUS_SOCKET_READABLE); ------------------ | | 27| 521k|#define LIBUS_SOCKET_READABLE EPOLLIN ------------------ 227| 521k| bsd_shutdown_socket(us_poll_fd((struct us_poll_t *) s)); 228| 521k| } 229| 522k|} _Z4testv: 11| 5.39k|void test() { 12| | 13| | /* ws->getUserData returns one of these */ 14| 5.39k| struct PerSocketData { 15| | /* Fill with user data */ 16| 5.39k| std::vector topics; 17| 5.39k| int nr = 0; 18| 5.39k| }; 19| | 20| | /* Keep in mind that uWS::SSLApp({options}) is the same as uWS::App() when compiled without SSL support. 21| | * You may swap to using uWS:App() if you don't need SSL */ 22| 5.39k| uWS::SSLApp *app = new uWS::SSLApp({ 23| | /* There are example certificates in uWebSockets.js repo */ 24| 5.39k| .key_file_name = "../misc/key.pem", 25| 5.39k| .cert_file_name = "../misc/cert.pem", 26| 5.39k| .passphrase = "1234" 27| 5.39k| }); 28| | 29| 5.39k| app->ws("/*", { 30| | /* Settings */ 31| 5.39k| .compression = uWS::DISABLED, 32| 5.39k| .maxPayloadLength = 512, // also have a low value here for fuzzing 33| 5.39k| .idleTimeout = 60, 34| 5.39k| .maxBackpressure = 128, // we want a low number so that we can reach this in fuzzing 35| 5.39k| .closeOnBackpressureLimit = false, // this one could be tested as well 36| 5.39k| .resetIdleTimeoutOnSend = true, // and this 37| 5.39k| .sendPingsAutomatically = false, // and this 38| | /* Handlers */ 39| 5.39k| .upgrade = nullptr, 40| 5.39k| .open = [](auto *ws) { 41| | /* Open event here, you may access ws->getUserData() which points to a PerSocketData struct */ 42| | 43| 5.39k| PerSocketData *perSocketData = (PerSocketData *) ws->getUserData(); 44| | 45| 5.39k| for (int i = 0; i < 100; i++) { 46| 5.39k| std::string topic = std::to_string((uintptr_t)ws) + "-" + std::to_string(i); 47| 5.39k| perSocketData->topics.push_back(topic); 48| 5.39k| ws->subscribe(topic); 49| 5.39k| } 50| 5.39k| }, 51| 5.39k| .message = [&app](auto *ws, std::string_view message, uWS::OpCode opCode) { 52| 5.39k| PerSocketData *perSocketData = (PerSocketData *) ws->getUserData(); 53| | 54| 5.39k| app->publish(perSocketData->topics[++perSocketData->nr % 100], message, opCode); 55| 5.39k| }, 56| 5.39k| .drain = [](auto */*ws*/) { 57| | /* Check ws->getBufferedAmount() here */ 58| | //std::cout << "drain" << std::endl; 59| 5.39k| }, 60| 5.39k| .ping = [](auto */*ws*/, std::string_view ) { 61| | /* Not implemented yet */ 62| 5.39k| }, 63| 5.39k| .pong = [](auto */*ws*/, std::string_view ) { 64| | /* Not implemented yet */ 65| 5.39k| }, 66| 5.39k| .close = [](auto */*ws*/, int /*code*/, std::string_view /*message*/) { 67| | /* You may access ws->getUserData() here */ 68| 5.39k| } 69| 5.39k| }).listen(9001, [](auto *listen_s) { 70| 5.39k| if (listen_s) { 71| | //std::cout << "Listening on port " << 9001 << std::endl; 72| 5.39k| listen_socket = listen_s; 73| 5.39k| } 74| 5.39k| }); 75| | 76| 5.39k| app->run(); 77| | 78| 5.39k| delete app; 79| | 80| 5.39k| uWS::Loop::get()->free(); 81| 5.39k|} _Z8teardownv: 84| 5.38k|void teardown() { 85| | /* If we are called twice there's a bug (it potentially could if 86| | * all open sockets cannot be error-closed in one epoll_wait call). 87| | * But we only allow 1k FDs and we have a buffer of 1024 from epoll_wait */ 88| 5.38k| if (!listen_socket) { ------------------ | Branch (88:6): [True: 0, False: 5.38k] ------------------ 89| 0| exit(-1); 90| 0| } 91| | 92| | /* We might have open sockets still, and these will be error-closed by epoll_wait */ 93| | // us_socket_context_close - close all open sockets created with this socket context 94| 5.38k| if (listen_socket) { ------------------ | Branch (94:9): [True: 5.38k, False: 0] ------------------ 95| 5.38k| us_listen_socket_close(0, listen_socket); 96| 5.38k| listen_socket = NULL; 97| 5.38k| } 98| 5.38k|} EpollEchoServerPubSub.cpp:_ZZ4testvENK3$_0clIN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEEEDaPT_: 40| 105k| .open = [](auto *ws) { 41| | /* Open event here, you may access ws->getUserData() which points to a PerSocketData struct */ 42| | 43| 105k| PerSocketData *perSocketData = (PerSocketData *) ws->getUserData(); 44| | 45| 10.6M| for (int i = 0; i < 100; i++) { ------------------ | Branch (45:29): [True: 10.5M, False: 105k] ------------------ 46| 10.5M| std::string topic = std::to_string((uintptr_t)ws) + "-" + std::to_string(i); 47| 10.5M| perSocketData->topics.push_back(topic); 48| 10.5M| ws->subscribe(topic); 49| 10.5M| } 50| 105k| }, EpollEchoServerPubSub.cpp:_ZZ4testvENK3$_1clIN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEEEDaPT_NSt3__117basic_string_viewIcNS7_11char_traitsIcEEEENS1_6OpCodeE: 51| 1.07M| .message = [&app](auto *ws, std::string_view message, uWS::OpCode opCode) { 52| 1.07M| PerSocketData *perSocketData = (PerSocketData *) ws->getUserData(); 53| | 54| 1.07M| app->publish(perSocketData->topics[++perSocketData->nr % 100], message, opCode); 55| 1.07M| }, EpollEchoServerPubSub.cpp:_ZZ4testvENK3$_2clIN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEEEDaPT_: 56| 10.3k| .drain = [](auto */*ws*/) { 57| | /* Check ws->getBufferedAmount() here */ 58| | //std::cout << "drain" << std::endl; 59| 10.3k| }, EpollEchoServerPubSub.cpp:_ZZ4testvENK3$_3clIN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEEEDaPT_NSt3__117basic_string_viewIcNS7_11char_traitsIcEEEE: 60| 4.94k| .ping = [](auto */*ws*/, std::string_view ) { 61| | /* Not implemented yet */ 62| 4.94k| }, EpollEchoServerPubSub.cpp:_ZZ4testvENK3$_4clIN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEEEDaPT_NSt3__117basic_string_viewIcNS7_11char_traitsIcEEEE: 63| 788| .pong = [](auto */*ws*/, std::string_view ) { 64| | /* Not implemented yet */ 65| 788| }, EpollEchoServerPubSub.cpp:_ZZ4testvENK3$_5clIN3uWS9WebSocketILb1ELb1EZ4testvE13PerSocketDataEEEEDaPT_iNSt3__117basic_string_viewIcNS7_11char_traitsIcEEEE: 66| 105k| .close = [](auto */*ws*/, int /*code*/, std::string_view /*message*/) { 67| | /* You may access ws->getUserData() here */ 68| 105k| } EpollEchoServerPubSub.cpp:_ZZ4testvENK3$_6clI18us_listen_socket_tEEDaPT_: 69| 5.39k| }).listen(9001, [](auto *listen_s) { 70| 5.39k| if (listen_s) { ------------------ | Branch (70:13): [True: 5.38k, False: 13] ------------------ 71| | //std::cout << "Listening on port " << 9001 << std::endl; 72| 5.38k| listen_socket = listen_s; 73| 5.38k| } 74| 5.39k| }); set_consumable_data: 71| 5.39k|void set_consumable_data(const unsigned char *new_data, int new_length) { 72| 5.39k| consumable_data = (unsigned char *) new_data; 73| 5.39k| consumable_data_length = new_length; 74| 5.39k|} consume_byte: 77| 2.21M|int consume_byte(unsigned char *b) { 78| 2.21M| if (consumable_data_length) { ------------------ | Branch (78:6): [True: 2.20M, False: 3.48k] ------------------ 79| 2.20M| *b = consumable_data[0]; 80| 2.20M| consumable_data++; 81| 2.20M| consumable_data_length--; 82| 2.20M| return 0; 83| 2.20M| } 84| 3.48k| return -1; 85| 2.21M|} allocate_fd: 90| 1.24M|int allocate_fd() { 91| | // this can be massively optimized by having a list of free blocks or the like 92| 331M| for (int fd = 0; fd < MAX_FDS; fd++) { ------------------ | Branch (92:19): [True: 331M, False: 429] ------------------ 93| 331M| if (!fd_to_file[fd]) { ------------------ | Branch (93:7): [True: 1.24M, False: 329M] ------------------ 94| 1.24M| num_fds++; 95| 1.24M| return fd + RESERVED_SYSTEM_FDS; 96| 1.24M| } 97| 331M| } 98| 429| return -1; 99| 1.24M|} init_fd: 102| 1.24M|void init_fd(int fd, int type, struct file *f) { 103| 1.24M| if (fd >= RESERVED_SYSTEM_FDS) { ------------------ | Branch (103:6): [True: 1.24M, False: 0] ------------------ 104| 1.24M| fd_to_file[fd - RESERVED_SYSTEM_FDS] = f; 105| 1.24M| fd_to_file[fd - RESERVED_SYSTEM_FDS]->type = type; 106| 1.24M| fd_to_file[fd - RESERVED_SYSTEM_FDS]->next = NULL; 107| 1.24M| fd_to_file[fd - RESERVED_SYSTEM_FDS]->prev = NULL; 108| 1.24M| } 109| 1.24M|} map_fd: 111| 13.8M|struct file *map_fd(int fd) { 112| 13.8M| if (fd >= RESERVED_SYSTEM_FDS && fd < MAX_FDS + RESERVED_SYSTEM_FDS) { ------------------ | Branch (112:6): [True: 13.8M, False: 0] | Branch (112:35): [True: 13.8M, False: 0] ------------------ 113| 13.8M| return fd_to_file[fd - RESERVED_SYSTEM_FDS]; 114| 13.8M| } 115| 0| return NULL; 116| 13.8M|} free_fd: 119| 1.24M|int free_fd(int fd) { 120| 1.24M| if (fd >= RESERVED_SYSTEM_FDS && fd < MAX_FDS + RESERVED_SYSTEM_FDS) { ------------------ | Branch (120:6): [True: 1.24M, False: 0] | Branch (120:35): [True: 1.24M, False: 0] ------------------ 121| 1.24M| if (fd_to_file[fd - RESERVED_SYSTEM_FDS]) { ------------------ | Branch (121:7): [True: 1.24M, False: 0] ------------------ 122| 1.24M| fd_to_file[fd - RESERVED_SYSTEM_FDS] = 0; 123| 1.24M| num_fds--; 124| 1.24M| return 0; 125| 1.24M| } 126| 1.24M| } 127| | 128| 0| return -1; 129| 1.24M|} __wrap_epoll_create1: 141| 5.39k|int __wrap_epoll_create1(int flags) { 142| | 143| | /* Todo: check that we do not allocate more than one epoll FD */ 144| 5.39k| int fd = allocate_fd(); 145| | 146| 5.39k| if (fd != -1) { ------------------ | Branch (146:6): [True: 5.39k, False: 0] ------------------ 147| 5.39k| struct epoll_file *ef = (struct epoll_file *)malloc(sizeof(struct epoll_file)); 148| | 149| | /* Init the epoll_file */ 150| 5.39k| ef->poll_set_head = NULL; 151| 5.39k| ef->poll_set_tail = NULL; 152| | 153| 5.39k| init_fd(fd, FD_TYPE_EPOLL, (struct file *)ef); 154| 5.39k| } 155| | 156| |#ifdef PRINTF_DEBUG 157| | printf("epoll_create1 returning epfd: %d\n", fd); 158| |#endif 159| | 160| 5.39k| return fd; 161| 5.39k|} __wrap_epoll_ctl: 165| 3.69M|int __wrap_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) { 166| | 167| 3.69M| struct epoll_file *ef = (struct epoll_file *)map_fd(epfd); 168| 3.69M| if (!ef) { ------------------ | Branch (168:6): [True: 0, False: 3.69M] ------------------ 169| 0| return -1; 170| 0| } 171| | 172| 3.69M| struct file *f = (struct file *)map_fd(fd); 173| 3.69M| if (!f) { ------------------ | Branch (173:6): [True: 0, False: 3.69M] ------------------ 174| 0| return -1; 175| 0| } 176| | 177| | /* We add new polls in the head */ 178| 3.69M| if (op == EPOLL_CTL_ADD) { ------------------ | Branch (178:6): [True: 1.24M, False: 2.45M] ------------------ 179| | // if there is a head already 180| 1.24M| if (ef->poll_set_head) { ------------------ | Branch (180:7): [True: 1.23M, False: 5.39k] ------------------ 181| 1.23M| ef->poll_set_head->prev = f; 182| | 183| | // then it will be our next 184| 1.23M| f->next = ef->poll_set_head; 185| 1.23M| } else { 186| | // if there was no head then we became the tail also 187| 5.39k| ef->poll_set_tail = f; 188| 5.39k| } 189| | 190| | // we are now the head in any case 191| 1.24M| ef->poll_set_head = f; 192| | 193| 1.24M| f->epev = *event; 194| | 195| 2.45M| } else if (op == EPOLL_CTL_MOD) { ------------------ | Branch (195:13): [True: 1.21M, False: 1.24M] ------------------ 196| | /* Modifying is simply changing the file itself */ 197| 1.21M| f->epev = *event; 198| 1.24M| } else if (op == EPOLL_CTL_DEL) { ------------------ | Branch (198:13): [True: 1.24M, False: 0] ------------------ 199| | 200| 1.24M| if (f->prev) { ------------------ | Branch (200:7): [True: 559k, False: 682k] ------------------ 201| 559k| f->prev->next = f->next; 202| 682k| } else { 203| 682k| ef->poll_set_head = f->next; 204| 682k| } 205| | 206| 1.24M| if (f->next) { ------------------ | Branch (206:7): [True: 1.23M, False: 5.39k] ------------------ 207| 1.23M| f->next->prev = f->prev; 208| 1.23M| } else { 209| | // tail ska vara vår.prev 210| 5.39k| ef->poll_set_tail = f->prev; 211| 5.39k| } 212| | 213| | // a file that is not in the list should be reset to NULL 214| 1.24M| f->prev = NULL; 215| 1.24M| f->next = NULL; 216| 1.24M| } 217| | 218| | /* You have to poll for errors and hangups */ 219| 3.69M| f->epev.events |= EPOLLERR | EPOLLHUP; 220| | 221| 3.69M| return 0; 222| 3.69M|} __wrap_epoll_wait: 226| 1.29M| 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| 1.29M| struct epoll_file *ef = (struct epoll_file *)map_fd(epfd); 234| 1.29M| if (!ef) { ------------------ | Branch (234:6): [True: 0, False: 1.29M] ------------------ 235| 0| return -1; 236| 0| } 237| | 238| 1.29M| if (consumable_data_length) { ------------------ | Branch (238:6): [True: 1.29M, False: 5.38k] ------------------ 239| | 240| 1.29M| int ready_events = 0; 241| | 242| 8.92M| for (struct file *f = ef->poll_set_head; f; f = f->next) { ------------------ | Branch (242:44): [True: 7.63M, False: 1.29M] ------------------ 243| | 244| | 245| | /* Consume one fuzz byte, AND it with the event */ 246| 7.63M| if (!consumable_data_length) { ------------------ | Branch (246:8): [True: 472, False: 7.63M] ------------------ 247| | // break if we have no data 248| 472| break; 249| 472| } 250| | 251| | // here we have the main condition that drives everything 252| 7.63M| int ready_event = consumable_data[0] & f->epev.events; 253| | 254| | // consume the byte 255| 7.63M| consumable_data_length--; 256| 7.63M| consumable_data++; 257| | 258| 7.63M| if (ready_event) { ------------------ | Branch (258:8): [True: 5.38M, False: 2.25M] ------------------ 259| 5.38M| if (ready_events < maxevents) { ------------------ | Branch (259:9): [True: 5.38M, False: 0] ------------------ 260| 5.38M| 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| 5.38M| events[ready_events++].events = ready_event; 264| 5.38M| } else { 265| | // we are full, break 266| 0| break; 267| 0| } 268| 5.38M| } 269| | 270| 7.63M| } 271| | 272| 1.29M| return ready_events; 273| | 274| 1.29M| } else { 275| | 276| |#ifdef PRINTF_DEBUG 277| | printf("Calling teardown\n"); 278| |#endif 279| 5.38k| 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.38k| int ready_events = 0; 287| | 288| |#ifdef PRINTF_DEBUG 289| | printf("Emitting error on every remaining FD\n"); 290| |#endif 291| 77.2k| for (struct file *f = ef->poll_set_head; f; f = f->next) { ------------------ | Branch (291:44): [True: 71.8k, False: 5.38k] ------------------ 292| | 293| 71.8k| if (f->type == FD_TYPE_SOCKET) { ------------------ | Branch (293:8): [True: 55.7k, False: 16.1k] ------------------ 294| | 295| 55.7k| if (ready_events < maxevents) { ------------------ | Branch (295:9): [True: 55.7k, False: 0] ------------------ 296| 55.7k| 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.7k| events[ready_events++].events = EPOLLERR | EPOLLHUP; 300| 55.7k| } else { 301| | // we are full, break 302| 0| break; 303| 0| } 304| | 305| 55.7k| } 306| 71.8k| } 307| | 308| |#ifdef PRINTF_DEBUG 309| | printf("Ready events: %d\n", ready_events); 310| |#endif 311| | 312| 5.38k| return ready_events; 313| 5.38k| } 314| 1.29M|} __wrap_read: 332| 3.87M|int __wrap_read(int fd, void *buf, size_t count) { 333| | 334| 3.87M| if (fd < RESERVED_SYSTEM_FDS) { ------------------ | Branch (334:6): [True: 0, False: 3.87M] ------------------ 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| 3.87M| struct file *f = map_fd(fd); 346| 3.87M| if (!f) { ------------------ | Branch (346:6): [True: 0, False: 3.87M] ------------------ 347| 0| return -1; 348| 0| } 349| | 350| 3.87M| errno = 0; 351| | 352| 3.87M| if (f->type == FD_TYPE_SOCKET) { ------------------ | Branch (352:6): [True: 831k, False: 3.04M] ------------------ 353| | 354| 831k| if (!consumable_data_length) { ------------------ | Branch (354:7): [True: 11.2k, False: 820k] ------------------ 355| 11.2k| errno = EWOULDBLOCK; 356| 11.2k| return -1; 357| 820k| } else { 358| 820k| int data_available = (unsigned char) consumable_data[0]; 359| 820k| consumable_data_length--; 360| 820k| consumable_data++; 361| | 362| 820k| if (consumable_data_length < data_available) { ------------------ | Branch (362:8): [True: 4.29k, False: 816k] ------------------ 363| 4.29k| data_available = consumable_data_length; 364| 4.29k| } 365| | 366| 820k| if (count < data_available) { ------------------ | Branch (366:8): [True: 0, False: 820k] ------------------ 367| 0| data_available = count; 368| 0| } 369| | 370| 820k| memcpy(buf, consumable_data, data_available); 371| | 372| 820k| consumable_data_length -= data_available; 373| 820k| consumable_data += data_available; 374| | 375| 820k| return data_available; 376| 820k| } 377| 831k| } 378| | 379| 3.04M| if (f->type == FD_TYPE_EVENT) { ------------------ | Branch (379:6): [True: 1.06M, False: 1.98M] ------------------ 380| 1.06M| memset(buf, 1, 8); 381| 1.06M| return 8; 382| 1.06M| } 383| | 384| 1.98M| if (f->type == FD_TYPE_TIMER) { ------------------ | Branch (384:6): [True: 1.98M, False: 0] ------------------ 385| 1.98M| memset(buf, 1, 8); 386| 1.98M| return 8; 387| 1.98M| } 388| | 389| 0| return -1; 390| 1.98M|} __wrap_recv: 393| 831k|int __wrap_recv(int sockfd, void *buf, size_t len, int flags) { 394| 831k| return __wrap_read(sockfd, buf, len); 395| 831k|} __wrap_send: 397| 749k|int __wrap_send(int sockfd, const void *buf, size_t len, int flags) { 398| | 399| 749k| if (consumable_data_length) { ------------------ | Branch (399:6): [True: 741k, False: 7.26k] ------------------ 400| | /* We can send len scaled by the 1 byte */ 401| 741k| unsigned char scale = consumable_data[0]; 402| 741k| consumable_data++; 403| 741k| consumable_data_length--; 404| | 405| 741k| int written = float(scale) / 255.0f * len; 406| | 407| 741k| if (written == 0) { ------------------ | Branch (407:7): [True: 361k, False: 379k] ------------------ 408| 361k| errno = EWOULDBLOCK; 409| 379k| } else { 410| 379k| errno = 0; 411| 379k| } 412| | 413| 741k| return written; 414| 741k| } else { 415| 7.26k| return -1; 416| 7.26k| } 417| 749k|} __wrap_bind: 424| 5.39k|int __wrap_bind() { 425| 5.39k| return 0; 426| 5.39k|} __wrap_setsockopt: 428| 1.23M|int __wrap_setsockopt() { 429| 1.23M| return 0; 430| 1.23M|} __wrap_fcntl: 433| 2.45M|int __wrap_fcntl(int fd, int cmd, ... /* arg */) { 434| 2.45M| if (fd < RESERVED_SYSTEM_FDS) { ------------------ | Branch (434:6): [True: 2, False: 2.45M] ------------------ 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| 2.45M| return 0; 443| 2.45M|} __wrap_getaddrinfo: 448| 5.39k| struct addrinfo **res) { 449| | //printf("Wrapped getaddrinfo\n"); 450| | 451| 5.39k| struct addrinfo default_hints = {}; 452| | 453| 5.39k| if (!hints) { ------------------ | Branch (453:6): [True: 0, False: 5.39k] ------------------ 454| 0| hints = &default_hints; 455| 0| } 456| | 457| 5.39k| unsigned char b; 458| 5.39k| if (consume_byte(&b)) { ------------------ | Branch (458:6): [True: 0, False: 5.39k] ------------------ 459| 0| return -1; 460| 0| } 461| | 462| | /* This one should be thread_local */ 463| 5.39k| static /*thread_local*/ struct addrinfo ai; 464| 5.39k| ai.ai_flags = hints->ai_flags; 465| 5.39k| ai.ai_socktype = hints->ai_socktype; 466| 5.39k| ai.ai_protocol = hints->ai_protocol; 467| | 468| 5.39k| if (b > 127) { ------------------ | Branch (468:6): [True: 1.29k, False: 4.09k] ------------------ 469| 1.29k| ai.ai_family = AF_INET;//hints->ai_family; 470| 4.09k| } else { 471| 4.09k| ai.ai_family = AF_INET6;//hints->ai_family; 472| 4.09k| } 473| | 474| | /* This one is for generating the wrong family (maybe invalid?) */ 475| 5.39k| if (b == 0) { ------------------ | Branch (475:6): [True: 2, False: 5.39k] ------------------ 476| 2| ai.ai_family = hints->ai_family; 477| 2| } 478| | 479| 5.39k| ai.ai_next = NULL; 480| 5.39k| ai.ai_canonname = NULL; // fel 481| | 482| | // these should depend on inet6 or inet */ 483| 5.39k| ai.ai_addrlen = 4; // fel 484| 5.39k| ai.ai_addr = NULL; // ska peka på en sockaddr! 485| | 486| | // we need to return an addrinfo with family AF_INET6 487| | 488| 5.39k| *res = &ai; 489| 5.39k| return 0; 490| 5.39k|} __wrap_freeaddrinfo: 492| 5.39k|int __wrap_freeaddrinfo() { 493| 5.39k| return 0; 494| 5.39k|} __wrap_accept4: 521| 2.20M|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| 2.20M| unsigned char b; 525| 2.20M| if (consume_byte(&b)) { ------------------ | Branch (525:6): [True: 3.47k, False: 2.19M] ------------------ 526| 3.47k| return -1; 527| 3.47k| } 528| | 529| | /* This rule might change, anything below 10 is accepted */ 530| 2.19M| if (b < 10) { ------------------ | Branch (530:6): [True: 1.22M, False: 976k] ------------------ 531| | 532| 1.22M| int fd = allocate_fd(); 533| 1.22M| if (fd != -1) { ------------------ | Branch (533:7): [True: 1.22M, False: 429] ------------------ 534| | 535| | /* Allocate the file */ 536| 1.22M| 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.22M| 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.22M| memset(&sf->addr, 0, sizeof(struct sockaddr_in6)); 547| 1.22M| sf->len = sizeof(struct sockaddr_in6); 548| 1.22M| sf->addr.in6.sin6_family = AF_INET6; 549| | 550| | /* Opt-in to ipv4 */ 551| 1.22M| if (b < 5) { ------------------ | Branch (551:8): [True: 935k, False: 285k] ------------------ 552| 935k| memset(&sf->addr, 0, sizeof(struct sockaddr_in6)); 553| 935k| sf->len = sizeof(struct sockaddr_in); 554| 935k| sf->addr.in.sin_family = AF_INET; 555| 935k| } 556| | 557| 1.22M| if (addr) { ------------------ | Branch (557:8): [True: 1.22M, False: 0] ------------------ 558| | /* Copy from socket to addr */ 559| 1.22M| memcpy(addr, &sf->addr, sf->len); 560| 1.22M| } 561| 1.22M| } 562| | 563| 1.22M| return fd; 564| 1.22M| } 565| | 566| 976k| return -1; 567| 2.19M|} __wrap_listen: 569| 5.39k|int __wrap_listen() { 570| | /* Listen consumes one byte and fails on -1 */ 571| 5.39k| unsigned char b; 572| 5.39k| if (consume_byte(&b)) { ------------------ | Branch (572:6): [True: 10, False: 5.38k] ------------------ 573| 10| return -1; 574| 10| } 575| | 576| 5.38k| if (b) { ------------------ | Branch (576:6): [True: 5.38k, False: 1] ------------------ 577| 5.38k| return 0; 578| 5.38k| } 579| | 580| 1| return -1; 581| 5.38k|} __wrap_socket: 584| 5.39k|int __wrap_socket(int domain, int type, int protocol) { 585| | 586| | /* Only accept valid families */ 587| 5.39k| if (domain != AF_INET && domain != AF_INET6) { ------------------ | Branch (587:6): [True: 4.09k, False: 1.29k] | Branch (587:27): [True: 0, False: 4.09k] ------------------ 588| 0| return -1; 589| 0| } 590| | 591| 5.39k| int fd = allocate_fd(); 592| | 593| 5.39k| if (fd != -1) { ------------------ | Branch (593:6): [True: 5.39k, False: 0] ------------------ 594| 5.39k| struct socket_file *sf = (struct socket_file *)malloc(sizeof(struct socket_file)); 595| | 596| | /* Init the file */ 597| | 598| 5.39k| init_fd(fd, FD_TYPE_SOCKET, (struct file *)sf); 599| 5.39k| } 600| | 601| |#ifdef PRINTF_DEBUG 602| | printf("socket returning fd: %d\n", fd); 603| |#endif 604| | 605| 5.39k| return fd; 606| 5.39k|} __wrap_shutdown: 608| 521k|int __wrap_shutdown() { 609| | //printf("Wrapped shutdown\n"); 610| 521k| return 0; 611| 521k|} __wrap_timerfd_create: 619| 10.7k|int __wrap_timerfd_create(int clockid, int flags) { 620| | 621| 10.7k| int fd = allocate_fd(); 622| | 623| 10.7k| if (fd != -1) { ------------------ | Branch (623:6): [True: 10.7k, False: 0] ------------------ 624| 10.7k| struct timer_file *tf = (struct timer_file *)malloc(sizeof(struct timer_file)); 625| | 626| | /* Init the file */ 627| | 628| | 629| 10.7k| init_fd(fd, FD_TYPE_TIMER, (struct file *)tf); 630| | 631| 10.7k| } 632| | 633| |#ifdef PRINTF_DEBUG 634| | printf("timerfd_create returning fd: %d\n", fd); 635| |#endif 636| | 637| 10.7k| return fd; 638| 10.7k|} __wrap_timerfd_settime: 642| 10.7k| struct itimerspec *old_value) { 643| | //printf("timerfd_settime: %d\n", fd); 644| 10.7k| return 0; 645| 10.7k|} __wrap_eventfd: 653| 5.39k|int __wrap_eventfd() { 654| | 655| 5.39k| int fd = allocate_fd(); 656| | 657| 5.39k| if (fd != -1) { ------------------ | Branch (657:6): [True: 5.39k, False: 0] ------------------ 658| 5.39k| struct event_file *ef = (struct event_file *)malloc(sizeof(struct event_file)); 659| | 660| | /* Init the file */ 661| | 662| 5.39k| init_fd(fd, FD_TYPE_EVENT, (struct file *)ef); 663| | 664| | //printf("eventfd: %d\n", fd); 665| 5.39k| } 666| | 667| |#ifdef PRINTF_DEBUG 668| | printf("eventfd returning fd: %d\n", fd); 669| |#endif 670| | 671| 5.39k| return fd; 672| 5.39k|} __wrap_close: 678| 1.24M|int __wrap_close(int fd) { 679| | 680| 1.24M| if (fd < RESERVED_SYSTEM_FDS) { ------------------ | Branch (680:6): [True: 0, False: 1.24M] ------------------ 681| 0| return __real_close(fd); 682| 0| } 683| | 684| 1.24M| struct file *f = map_fd(fd); 685| | 686| 1.24M| if (!f) { ------------------ | Branch (686:6): [True: 0, False: 1.24M] ------------------ 687| 0| return -1; 688| 0| } 689| | 690| 1.24M| if (f->type == FD_TYPE_EPOLL) { ------------------ | Branch (690:6): [True: 5.39k, False: 1.24M] ------------------ 691| |#ifdef PRINTF_DEBUG 692| | printf("Closing epoll FD: %d\n", fd); 693| |#endif 694| | 695| 5.39k| free(f); 696| | 697| 5.39k| return free_fd(fd); 698| | 699| 1.24M| } else if (f->type == FD_TYPE_TIMER) { ------------------ | Branch (699:13): [True: 10.7k, False: 1.23M] ------------------ 700| |#ifdef PRINTF_DEBUG 701| | printf("Closing timer fd: %d\n", fd); 702| |#endif 703| | 704| 10.7k| free(f); 705| | 706| 10.7k| return free_fd(fd); 707| 1.23M| } else if (f->type == FD_TYPE_EVENT) { ------------------ | Branch (707:13): [True: 5.39k, False: 1.22M] ------------------ 708| |#ifdef PRINTF_DEBUG 709| | printf("Closing event fd: %d\n", fd); 710| |#endif 711| | 712| 5.39k| free(f); 713| | 714| 5.39k| return free_fd(fd); 715| 1.22M| } else if (f->type == FD_TYPE_SOCKET) { ------------------ | Branch (715:13): [True: 1.22M, 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.22M| free(f); 723| | 724| 1.22M| int ret = free_fd(fd); 725| | 726| |#ifdef PRINTF_DEBUG 727| | printf("Ret: %d\n", ret); 728| |#endif 729| | 730| | //free(-1); 731| 1.22M| return ret; 732| 1.22M| } 733| | 734| 0| return -1; 735| 1.24M|} LLVMFuzzerTestOneInput: 737| 5.39k|int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 738| 5.39k| set_consumable_data(data, size); 739| | 740| 5.39k| test(); 741| | 742| 5.39k| if (num_fds) { ------------------ | Branch (742:6): [True: 0, False: 5.39k] ------------------ 743| 0| printf("ERROR! Cannot leave open FDs after test!\n"); 744| 0| } 745| | 746| 5.39k| return 0; 747| 5.39k|}