Socket library updates to support detecting sockets passed as FDs, removed use of peek() in HTTP request handler, fixed 100% CPU usage problem for unfinished HTTP requests
This commit is contained in:
		
							parent
							
								
									3cb03392e1
								
							
						
					
					
						commit
						6a6dd5d7ed
					
				
					 7 changed files with 145 additions and 162 deletions
				
			
		|  | @ -528,6 +528,7 @@ namespace Mist{ | |||
|     } | ||||
|      | ||||
|     if (!keepGoing()){ | ||||
|       INFO_MSG("Aborting page load due to shutdown"); | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -12,6 +12,10 @@ namespace Mist { | |||
|     if (config->getString("ip").size()){ | ||||
|       myConn.setHost(config->getString("ip")); | ||||
|     } | ||||
|     firstRun = true; | ||||
|     if (config->getString("prequest").size()){ | ||||
|       myConn.Received().prepend(config->getString("prequest")); | ||||
|     } | ||||
|     config->activate(); | ||||
|   } | ||||
| 
 | ||||
|  | @ -33,14 +37,19 @@ namespace Mist { | |||
|     capa["forward"]["ip"]["help"] = "IP of forwarded connection."; | ||||
|     capa["forward"]["ip"]["type"] = "str"; | ||||
|     capa["forward"]["ip"]["option"] = "--ip"; | ||||
|     capa["forward"]["ip"]["name"] = "Previous request"; | ||||
|     capa["forward"]["ip"]["help"] = "Data to pretend arrived on the socket before parsing the socket."; | ||||
|     capa["forward"]["ip"]["type"] = "str"; | ||||
|     capa["forward"]["ip"]["option"] = "--prequest"; | ||||
|     cfg->addOption("streamname", JSON::fromString("{\"arg\":\"string\",\"short\":\"s\",\"long\":\"stream\",\"help\":\"The name of the stream that this connector will transmit.\"}")); | ||||
|     cfg->addOption("ip", JSON::fromString("{\"arg\":\"string\",\"short\":\"I\",\"long\":\"ip\",\"help\":\"IP address of connection on stdio.\"}")); | ||||
|     cfg->addOption("prequest", JSON::fromString("{\"arg\":\"string\",\"short\":\"R\",\"long\":\"prequest\",\"help\":\"Data to pretend arrived on the socket before parsing the socket.\"}")); | ||||
|     cfg->addBasicConnectorOptions(capa); | ||||
|     config = cfg; | ||||
|   } | ||||
|    | ||||
|   void HTTPOutput::onFail(const std::string & msg, bool critical){ | ||||
|     INFO_MSG("Failing '%s': %s: %s", streamName.c_str(), H.url.c_str(), msg.c_str()); | ||||
|     INFO_MSG("Failing '%s': %s", H.url.c_str(), msg.c_str()); | ||||
|     if (!webSock){ | ||||
|       H.Clean(); //make sure no parts of old requests are left in any buffers
 | ||||
|       H.SetHeader("Server", "MistServer/" PACKAGE_VERSION); | ||||
|  | @ -165,80 +174,49 @@ namespace Mist { | |||
|   } | ||||
|    | ||||
|   void HTTPOutput::requestHandler(){ | ||||
|     //Handle onIdle function caller, if needed
 | ||||
|     if (idleInterval && (Util::bootMS() > idleLast + idleInterval)){ | ||||
|       onIdle(); | ||||
|       idleLast = Util::bootMS(); | ||||
|     } | ||||
|     //Handle websockets
 | ||||
|     if (webSock){ | ||||
|       if (webSock->readFrame()){ | ||||
|         onWebsocketFrame(); | ||||
|         idleLast = Util::bootMS(); | ||||
|       }else{ | ||||
|         if (!isBlocking && !parseData){ | ||||
|           Util::sleep(100); | ||||
|         } | ||||
|         return; | ||||
|       } | ||||
|       if (!isBlocking && !parseData){Util::sleep(100);} | ||||
|       return; | ||||
|     } | ||||
|     if (myConn.Received().size() && myConn.spool()){ | ||||
|       DEBUG_MSG(DLVL_DONTEVEN, "onRequest"); | ||||
|       onRequest(); | ||||
|     }else{ | ||||
|       if (!myConn.Received().size()){ | ||||
|         if (myConn.peek() && H.Read(myConn)){ | ||||
|           std::string handler = getHandler(); | ||||
|           DEBUG_MSG(DLVL_MEDIUM, "Received request: %s => %s (%s)", H.getUrl().c_str(), handler.c_str(), H.GetVar("stream").c_str()); | ||||
|           if (!handler.size()){ | ||||
|             H.Clean(); | ||||
|             H.SetHeader("Server", "MistServer/" PACKAGE_VERSION); | ||||
|             H.SetBody("<!DOCTYPE html><html><head><title>Unsupported Media Type</title></head><body><h1>Unsupported Media Type</h1>The server isn't quite sure what you wanted to receive from it.</body></html>"); | ||||
|             H.SendResponse("415", "Unsupported Media Type", myConn); | ||||
|             myConn.close(); | ||||
|             return; | ||||
|           } | ||||
|           if (handler != capa["name"].asStringRef() || H.GetVar("stream") != streamName){ | ||||
|             DEBUG_MSG(DLVL_MEDIUM, "Switching from %s (%s) to %s (%s)", capa["name"].asStringRef().c_str(), streamName.c_str(), handler.c_str(), H.GetVar("stream").c_str()); | ||||
|             streamName = H.GetVar("stream"); | ||||
|             nProxy.userClient.finish(); | ||||
|             statsPage.finish(); | ||||
|             reConnector(handler); | ||||
|             H.Clean(); | ||||
|             if (myConn.connected()){ | ||||
|               FAIL_MSG("Request failed - no connector started"); | ||||
|               myConn.close(); | ||||
|             } | ||||
|             return; | ||||
|           }else{ | ||||
|             H.Clean(); | ||||
|             myConn.Received().clear(); | ||||
|             myConn.spool(); | ||||
|             DEBUG_MSG(DLVL_DONTEVEN, "onRequest"); | ||||
|             onRequest(); | ||||
|           } | ||||
|         }else{ | ||||
|           H.Clean(); | ||||
|           if (myConn.Received().size()){ | ||||
|             myConn.Received().clear(); | ||||
|             myConn.spool(); | ||||
|             DEBUG_MSG(DLVL_DONTEVEN, "onRequest"); | ||||
|             onRequest(); | ||||
|           } | ||||
|           if (!myConn.Received().size()){ | ||||
|             if (!isBlocking && !parseData){ | ||||
|               Util::sleep(100); | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       }else{ | ||||
|         if (!isBlocking && !parseData){ | ||||
|           Util::sleep(100); | ||||
|         } | ||||
|       } | ||||
|     //If we can't read anything more and we're non-blocking, sleep some.
 | ||||
|     if (!firstRun && !myConn.spool()){ | ||||
|       if (!isBlocking && !parseData){Util::sleep(100);} | ||||
|       return; | ||||
|     } | ||||
|   } | ||||
|    | ||||
|   void HTTPOutput::onRequest(){ | ||||
|     firstRun = false; | ||||
| 
 | ||||
|     while (H.Read(myConn)){ | ||||
|       std::string handler = getHandler(); | ||||
|       INFO_MSG("Received request: %s => %s (%s)", H.getUrl().c_str(), handler.c_str(), H.GetVar("stream").c_str()); | ||||
|       if (!handler.size()){ | ||||
|         H.Clean(); | ||||
|         H.SetHeader("Server", "MistServer/" PACKAGE_VERSION); | ||||
|         H.SetBody("<!DOCTYPE html><html><head><title>Unsupported Media Type</title></head><body><h1>Unsupported Media Type</h1>The server isn't quite sure what you wanted to receive from it.</body></html>"); | ||||
|         H.SendResponse("415", "Unsupported Media Type", myConn); | ||||
|         myConn.close(); | ||||
|         return; | ||||
|       } | ||||
|       if (handler != capa["name"].asStringRef() || H.GetVar("stream") != streamName){ | ||||
|         MEDIUM_MSG("Switching from %s (%s) to %s (%s)", capa["name"].asStringRef().c_str(), streamName.c_str(), handler.c_str(), H.GetVar("stream").c_str()); | ||||
|         streamName = H.GetVar("stream"); | ||||
|         nProxy.userClient.finish(); | ||||
|         statsPage.finish(); | ||||
|         reConnector(handler); | ||||
|         onFail("Server error - could not start connector", true); | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       if (H.hasHeader("User-Agent")){ | ||||
|         UA = H.GetHeader("User-Agent"); | ||||
|       } | ||||
|  | @ -255,7 +233,6 @@ namespace Mist { | |||
|         crc = checksum::crc32(0, mixed_ua.data(), mixed_ua.size()); | ||||
|       } | ||||
| 
 | ||||
|       INFO_MSG("Received request %s", H.getUrl().c_str()); | ||||
|       //Handle upgrade to websocket if the output supports it
 | ||||
|       if (doesWebsockets() && H.GetHeader("Upgrade") == "websocket"){ | ||||
|         INFO_MSG("Switching to Websocket mode"); | ||||
|  | @ -309,13 +286,11 @@ namespace Mist { | |||
|   } | ||||
|    | ||||
|   ///\brief Handles requests by starting a corresponding output process.
 | ||||
|   ///\param H The request to be handled
 | ||||
|   ///\param conn The connection to the client that issued the request.
 | ||||
|   ///\param connector The type of connector to be invoked.
 | ||||
|   void HTTPOutput::reConnector(std::string & connector){ | ||||
|     //taken from CheckProtocols (controller_connectors.cpp)
 | ||||
|     char * argarr[20]; | ||||
|     for (int i=0; i<20; i++){argarr[i] = 0;} | ||||
|     char * argarr[32]; | ||||
|     for (int i=0; i<32; i++){argarr[i] = 0;} | ||||
|     int id = -1; | ||||
|     JSON::Value pipedCapa; | ||||
|     JSON::Value p;//properties of protocol
 | ||||
|  | @ -358,6 +333,8 @@ namespace Mist { | |||
| 
 | ||||
|     //build arguments for starting output process
 | ||||
|     std::string tmparg = Util::getMyPath() + std::string("MistOut") + connector; | ||||
|     std::string tmpPrequest; | ||||
|     if (H.url.size()){tmpPrequest = H.BuildRequest();} | ||||
|     int argnum = 0; | ||||
|     argarr[argnum++] = (char*)tmparg.c_str(); | ||||
|     std::string temphost=getConnectedHost(); | ||||
|  | @ -366,6 +343,8 @@ namespace Mist { | |||
|     argarr[argnum++] = (char*)(temphost.c_str()); | ||||
|     argarr[argnum++] = (char*)"--stream"; | ||||
|     argarr[argnum++] = (char*)(streamName.c_str()); | ||||
|     argarr[argnum++] = (char*)"--prequest"; | ||||
|     argarr[argnum++] = (char*)(tmpPrequest.c_str()); | ||||
|     //set the debug level if non-default
 | ||||
|     if (Util::Config::printDebugLevel != DEBUG){ | ||||
|       argarr[argnum++] = (char*)"--debug"; | ||||
|  |  | |||
|  | @ -11,7 +11,6 @@ namespace Mist { | |||
|       HTTPOutput(Socket::Connection & conn); | ||||
|       virtual ~HTTPOutput(); | ||||
|       static void init(Util::Config * cfg); | ||||
|       void onRequest(); | ||||
|       virtual void onFail(const std::string & msg, bool critical = false); | ||||
|       virtual void onHTTP(){}; | ||||
|       virtual void onIdle(){}; | ||||
|  | @ -26,6 +25,7 @@ namespace Mist { | |||
|       std::string getHandler(); | ||||
|       bool parseRange(uint64_t & byteStart, uint64_t & byteEnd); | ||||
|   protected: | ||||
|       bool firstRun; | ||||
|       HTTP::Parser H; | ||||
|       HTTP::Websocket * webSock; | ||||
|       uint32_t idleInterval; | ||||
|  |  | |||
|  | @ -36,12 +36,13 @@ namespace Mist { | |||
| 
 | ||||
|   OutHTTP::OutHTTP(Socket::Connection & conn) : HTTPOutput(conn){ | ||||
|     stayConnected = false; | ||||
|     if (myConn.getPureSocket() >= 0){ | ||||
|     //If this connection is a socket and not already connected to stdio, connect it to stdio.
 | ||||
|     if (myConn.getPureSocket() != -1 && myConn.getSocket() != STDIN_FILENO && myConn.getSocket() != STDOUT_FILENO){ | ||||
|       std::string host = getConnectedHost(); | ||||
|       dup2(myConn.getSocket(), STDIN_FILENO); | ||||
|       dup2(myConn.getSocket(), STDOUT_FILENO); | ||||
|       myConn.drop(); | ||||
|       myConn = Socket::Connection(fileno(stdout),fileno(stdin) ); | ||||
|       myConn = Socket::Connection(STDOUT_FILENO, STDIN_FILENO); | ||||
|       myConn.setHost(host); | ||||
|     } | ||||
|     if (config->getOption("wrappers",true).size() == 0 || config->getString("wrappers") == ""){ | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Thulinma
						Thulinma