Sorry for sending twice wez, I meant to send it here in the first place.
No I'm not familiar with the fcgi spec.. I just by myself wrote an fcgi interface, that's all. ok you're right, _just_ a dup2 would be insufficient, even if it uses pipes behind the scenes it's not much different from below. please Consider the following, and this is pretty keeping it simple: --- Oh and in the example below I screwed up, padding is only fcgibuf[6], I forgot it's only 1 byte to indicate the size of the padding. (Fixed in this example) Now this won't do _everything_ but it's a start :-P struct FastCGI { std::string stdin; void stdout(std::string&); // wrap in fcgi header, print to socket int socket; std::string fcgibuf; void parseOneRequest(std::string&); int pipeforstdin; int pipeforstdout; } void FastCGI::parseOneRequest(std::string&in) { fcgibuf += in; if(fcgibuf.size() < FCGI_HEADER_SIZE) return; //fast_cgiheader = fcgibuf[0]-fcgibuf[7]; //FCGI_HEADER_SIZE = 8 size_t contentsize = (fcgibuf[4]<<8)+fcgibuf[5]; unsigned char padding = fcgibuf[6]; size_t totalsize = contentsize+padding+FCGI_HEADER_SIZE; if(fcgibuf.size() < totalsize) return; int type = request[1]; size_t requestid = (b[2]<<8 )+b[1]; std::string content = ""; if(contentsize() > 0) content = fcgibuf.substr(FCGI_HEADER_SIZE, contentsize); fcgibuf.replace(0, totalsize, ""); // Clear it out for next request. // We have a full request, the type, all the data, and the request id. if(type == BEGIN_REQUEST) { int childstdin[2]; int childstdout[2]; pipe(childstdin); // may fail pipe(childstdout); // may fail stdin = childstdin[1]; stdout = childstdout[0]; BytecodeController.prepare_thread_for_request(requestid, childstdin[0], childstdout[1]); // [0] for reading [1] for writing. return; } if(type == FCGI_STDIN) { write(childstdin, content.c_str(), content.size()); // If when a child now calls fgets(stdin) it can read to a valid pipe. return; } if(type == FCGI_PARAMS) { BytecodeController.EnviromentalControls(requestid,content); // "environment variables" return; } if(type == FCGI_ABORT_REQUEST) { // respond with request aborted, kill script continue on } } class FCGIParse { public: static std::vector<FastCGI> fastcgiusers; static void ParseFCGI(int &socket, std::string &request); static void close(int &socket); static void doAllStdOuts(); // do a non-blocking read on all the stdout pipes, wrap a response if any is found in an fcgi header and send them out. } FCGIParse::ParseFCGI(int &socket, std::string &request) { std::vector<FastCGI>::iterator iter = fastcgiusers.begin(), end = fastcgiusers.end(); for(;iter<end;iter++){ if((*(iter)).socket == socket) { // now we can parse a single request (*(iter)).parseOneRequest(request); return; } } FastCGI newrequest; newrequest.socket = socket; (*(iter)).parseOneRequest(request); } FCGIParse::close(int &socket) { std::vector<FastCGI>::iterator iter = fastcgiusers.begin(), end = fastcgiusers.end(); for(;iter<end;iter++) { if((*(iter)).socket == socket) {fastcgiusers.erase(iter); return;}; } } Middle layer to tie them together class RunFCGIHandler { public: RunFCGIHandler(); void setup(); void run(); // almost never returns } struct aPacket; // below in the socket layer part RunFCGIHandler::setup() { socks->bindserversocket(); } RunFCGIHandler::run() { // Main loop setup(); while(RUNNING() ){ std::vector<aPacket> &packets = socks->listen(); std::vector<aPacket>::iterator iter = packets.begin(), end = packets.end(); FCGIParse::doAllStdOuts(); for(;iter<end;iter++) { FCGIParse::parse((*(iter)).socket, (*(iter)).data); } } } Socket layor arcitecture: Bind port in a constructor somewhere struct aPacket { std::string data; //std::strings can hold binary as long as += is used int socket; bool closed = false; }; struct ConnectedUsers { string ip; int socket; }; std::vector<ConnectedUsers> users; std::vector<aPacket> listen() { fdset rmask; FD_SET(serverfd, &rmask); if(users.size() > 0) { std::vector<ConnectedUsers>::iterator iter = users.begin(), end = users.end(); for(;iter<end;iter++) { FD_SET((*(iter)).socket, &rmask); } } timeout.usec = 1000; int nfound = select(rmask, ..,timeout); std::vector<aPacket> ret; if(FD_ISSET(ssd)) { accept, push back new user } if(nfound > 0) { std::vector<ConnectedUsers>::iterator iter = users.begin(), end = users.end(); for(;iter<end;iter++) { if(!FD_ISSET((*(iter)).socket))) continue; int somesize = somesize; char buf[somesize]; int nread = read((*(iter)).socket, buf, somesize); if(nread < 0 ) errorhandle.. if(nread == 0) { aPacket np; np.close = true; np.socket = (*(iter)).socket; ret.push_back(np); continue; } if(nread >0) { aPacket np; np.socket = (*(iter)).socket; np.close = false; for(int c = 0;c<nread;c++) np.data += buf[c]; ret.push_back(np); } } return ret; } >>>>>>>>>>>>>>>>>>>>>>>>>> If you're that familiar with the fcgi spec, then you'll realize that a simple dup2() is not sufficient. It's still better to tackle the problem "the right way" instead of trying to force something to work in a way that it doesn't. Hence the term "abuse". Advocating the use of threads to "solve" this is also a bad idea, likewise, where are you going to fit the dispatcher for multiplexing? Take my advice: take a step back, take a deep breath and look at the problem again, and remember: KISS. --Wez. On 3/28/06, [EMAIL PROTECTED] <[EMAIL PROTECTED]> wrote: > sorry the word abuse pissed me off. I'm not abusing anything the protocols weren't designed to support (even if they don't know it, but then, they do know it). I can understand if nobody ever thought of this use of it before and is why there is no support for using fcgistdin with php, even tho any other programming language can use it if it properly and _fully_ supports the fast-cgi protocol. > > The easiest way I can think of to make a fast-cgi client application would be to simple close socket 0, and socket 1 (stdin and stdout), then dup2ing to the end of a pipe, cout data would be grabbed from the end of one of the pipes, wrapped in a fast-cgi header, printed to the server, stdin data from the server would come in to a second thread (or a multiplexing select() core), using the request id it finds the proper stdin pipe and just sends the data there. > > That's not hard to do, that's not off from the fast-cgi protocol, that's not an abuse, and that would allow the very simple stdin/stdout protocols to work for the easiest, most extendable server scripting ever convieved. > > -------------- Original message -------------- > From: "Wez Furlong" <[EMAIL PROTECTED]> > > > IMO, you're better off using stream_socket_server() and writing a > > "real" daemon for that. Abusing fastcgi/cgi to work in that way is > > only going to bite you in the ass. > > > > --Wez > > > > On 3/24/06, Matthew wrote: > > > I'm sorry if this is the wrong place for this post, I just don't know where > > > else to go. > > > > > > I need some help figuring out how to use FCGI_STDIN with a running php > > > script. > > > > > > I have written a server in c++, which for a while been running php through > > > it's plain old cgi interface. I have been using php for 2 things, the > > > obvious one, web pages, and the not so obvious, safe command/server > > > scripting. I have just implimented a fast-cgi interface to replace the cgi > > > interface, however, the scripting stuff i had that worked over regular cgi > > > just doesn't want to work with fast-cgi. > > > > > > Basically, the php script outputs a command and arguments, all commands > > > start with a %, so: > > > $var = "%print"; > > > printf("%s hello world\n", $var); > > > Can be used to print to the user calling the script. > > > > > > That part still works fine of course :). > > > > > > It doesn't stop there however, some of the %callbacks will return strings of > > > data over stdin so they can be $var = trim(fgets($STDIN)) for a very simple > > > and effective method of communicating with the server. > > > > > > I've tried doing the same with fast-cgi, but it seems > > > fopen("php://stdin","r") is not the right place to be reading from. > > > > > > I'm sending: > > > > > > (C++) > > > // loops over ever line of input, test it > > > std::string response = processALineFromCGI-OrFastCGIScript(oneLine) > > > if(response.compare("NOCMD") == 0) > > > buffer_to_print_to_user_who_called_this_when_request_finishs(); > > > else if(response.size() > 0) { > > > std::string sendout = FCGI_Headerize(response, FCGI_STDIN, ..); > > > non-blocking_send(sendout); > > > } > > > oneLine.erase(); > > > I use the same function to build the headers for FCGI_BEGIN_REQUEST, > > > FCGI_PARAMS, FCGI_STDIN on POST input, it works great there(now) > > > > > > > > > Also, is it possible to keep the connection open to php-cgi to avoid > > > connect/accept calls? Even if it's only fifo so only 1 request can go at a > > > time? > > > > > > If I must I could create a special c++ fast-cgi server that binds a second > > > port to pipe requests from php streams to the server, but would be a MAJOR > > > hack for what I'm trying to do.. :-D > > > > > > Thanks in advance! > > > > > > -- > > > PHP Internals - PHP Runtime Development Mailing List > > > To unsubscribe, visit: http://www.php.net/unsub.php > > > > > > > On Tue, 2006-03-28 at 20:31 -0500, Wez Furlong wrote: > If you're that familiar with the fcgi spec, then you'll realize that a > simple dup2() is not sufficient. > > It's still better to tackle the problem "the right way" instead of > trying to force something to work in a way that it doesn't. Hence the > term "abuse". > > Advocating the use of threads to "solve" this is also a bad idea, > likewise, where are you going to fit the dispatcher for multiplexing? > > Take my advice: take a step back, take a deep breath and look at the > problem again, and remember: KISS. > > --Wez. > > On 3/28/06, [EMAIL PROTECTED] <[EMAIL PROTECTED]> wrote: > > sorry the word abuse pissed me off. I'm not abusing anything the > protocols weren't designed to support (even if they don't know it, but > then, they do know it). I can understand if nobody ever thought of > this use of it before and is why there is no support for using > fcgistdin with php, even tho any other programming language can use it > if it properly and _fully_ supports the fast-cgi protocol. > > > > The easiest way I can think of to make a fast-cgi client application > would be to simple close socket 0, and socket 1 (stdin and stdout), > then dup2ing to the end of a pipe, cout data would be grabbed from the > end of one of the pipes, wrapped in a fast-cgi header, printed to the > server, stdin data from the server would come in to a second thread > (or a multiplexing select() core), using the request id it finds the > proper stdin pipe and just sends the data there. > > > > That's not hard to do, that's not off from the fast-cgi protocol, > that's not an abuse, and that would allow the very simple stdin/stdout > protocols to work for the easiest, most extendable server scripting > ever convieved. > > > > -------------- Original message -------------- > > From: "Wez Furlong" <[EMAIL PROTECTED]> > > > > > IMO, you're better off using stream_socket_server() and writing a > > > "real" daemon for that. Abusing fastcgi/cgi to work in that way is > > > only going to bite you in the ass. > > > > > > --Wez > > > > > > On 3/24/06, Matthew wrote: > > > > I'm sorry if this is the wrong place for this post, I just don't > know where > > > > else to go. > > > > > > > > I need some help figuring out how to use FCGI_STDIN with a > running php > > > > script. > > > > > > > > I have written a server in c++, which for a while been running > php through > > > > it's plain old cgi interface. I have been using php for 2 > things, the > > > > obvious one, web pages, and the not so obvious, safe > command/server > > > > scripting. I have just implimented a fast-cgi interface to > replace the cgi > > > > interface, however, the scripting stuff i had that worked over > regular cgi > > > > just doesn't want to work with fast-cgi. > > > > > > > > Basically, the php script outputs a command and arguments, all > commands > > > > start with a %, so: > > > > $var = "%print"; > > > > printf("%s hello world\n", $var); > > > > Can be used to print to the user calling the script. > > > > > > > > That part still works fine of course :). > > > > > > > > It doesn't stop there however, some of the %callbacks will > return strings of > > > > data over stdin so they can be $var = trim(fgets($STDIN)) for a > very simple > > > > and effective method of communicating with the server. > > > > > > > > I've tried doing the same with fast-cgi, but it seems > > > > fopen("php://stdin","r") is not the right place to be reading > from. > > > > > > > > I'm sending: > > > > > > > > (C++) > > > > // loops over ever line of input, test it > > > > std::string response = > processALineFromCGI-OrFastCGIScript(oneLine) > > > > if(response.compare("NOCMD") == 0) > > > > buffer_to_print_to_user_who_called_this_when_request_finishs(); > > > > else if(response.size() > 0) { > > > > std::string sendout = FCGI_Headerize(response, FCGI_STDIN, ..); > > > > non-blocking_send(sendout); > > > > } > > > > oneLine.erase(); > > > > I use the same function to build the headers for > FCGI_BEGIN_REQUEST, > > > > FCGI_PARAMS, FCGI_STDIN on POST input, it works great there(now) > > > > > > > > > > > > Also, is it possible to keep the connection open to php-cgi to > avoid > > > > connect/accept calls? Even if it's only fifo so only 1 request > can go at a > > > > time? > > > > > > > > If I must I could create a special c++ fast-cgi server that > binds a second > > > > port to pipe requests from php streams to the server, but would > be a MAJOR > > > > hack for what I'm trying to do.. :-D > > > > > > > > Thanks in advance! > > > > > > > > -- > > > > PHP Internals - PHP Runtime Development Mailing List > > > > To unsubscribe, visit: http://www.php.net/unsub.php > > > > > > > > > > > -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php