<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.iis.net/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:cs="http://blogs.iis.net/"><channel><title>Search results matching tags 'FastCGI' and 'FastCGI Client'</title><link>http://blogs.iis.net/search/SearchResults.aspx?o=DateDescending&amp;tag=FastCGI,FastCGI+Client&amp;orTags=0</link><description>Search results matching tags 'FastCGI' and 'FastCGI Client'</description><dc:language>en-US</dc:language><generator>CommunityServer 2007 SP1 (Build: 20510.895)</generator><item><title>Getting started with writing a FastCGI Client application (FastCGI Test Client)</title><link>http://blogs.iis.net/yaminij/archive/2009/01/07/getting-started-with-writing-a-fastcgi-client-application-fastcgi-test-client.aspx</link><pubDate>Thu, 08 Jan 2009 02:05:00 GMT</pubDate><guid isPermaLink="false">50bcf3b4-f6fe-4638-adff-0c150e922e99:2853176</guid><dc:creator>yaminij</dc:creator><cs:applicationKey>yaminij</cs:applicationKey><description>&lt;P&gt;I worked on the FastCGI for IIS&amp;nbsp;6.0&amp;nbsp;RTM release a while ago and during that time, I worked on developing a FastCGI Client application, in order to test FastCGI at a protocol level. I just decided to blog about it, just in case any of you are interested in getting started with writing a FastCGI client application from scratch.&amp;nbsp; 
&lt;P&gt;You can download the sample client application along with the source code from &lt;A class="" href="http://blogs.iis.net/blogs/yaminij/FCGIClient.zip" mce_href="http://blogs.iis.net/blogs/yaminij/FCGIClient.zip"&gt;here&lt;/A&gt;. This application can work both over TCP and Named Pipes. 
&lt;P&gt;The FastCGI Client application is a generic application that will be used to communicate with the Web Server (FastCGI handler) through FastCGI protocol either over Named Pipes or TCP.&amp;nbsp; The FastCGI test client communicates in the form of messages with the FastCGI Server.&amp;nbsp; All these messages are in the form of STDIN, STDOUT and STDERR. The Web Server (FastCGI Handler) creates a Named Pipe or a TCP stream for communication and duplicates these handles onto the stdout, stdin and stderr (parent processes can override the stdin, stdout and stderr of child). By this, the application just has to write it’s protocol messages to stdin, stdout and stderr and the details of the TCP/Named Pipe communication is abstracted out. 
&lt;P&gt;As a first step, you can determine if the application was invoked using CGI or FastCGI by calling getpeername on the STD_INPUT_HANDLE.&amp;nbsp; You should get a socket error if the client was invoked using a FastCGI application. Depending on whether your server uses TCP or Named Pipes, your WSAGetLastError() could return WASENOTCONN or WSAENOTSOCK respectively. &lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;bool&lt;/SPAN&gt; IsApplicationInvokedUsingFastCGI( HANDLE s )
{
        &lt;SPAN class=rem&gt;// Determine if this application was invoked using CGI or FastCGI&lt;/SPAN&gt;
        &lt;SPAN class=kwrd&gt;struct&lt;/SPAN&gt; sockaddr nameOfConnectedSocket;
        &lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt; nameLenOfConnectedSocket;
        HRESULT hr = S_OK;
        &lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt; errs; 

        errs = getpeername( (SOCKET)s, &amp;amp;nameOfConnectedSocket, &amp;amp;nameLenOfConnectedSocket );        
        &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; ( errs == SOCKET_ERROR )
        {
            hr = HRESULT_FROM_WIN32( WSAGetLastError() );
            &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt;(  hr == HRESULT_FROM_WIN32( WSAENOTCONN ) )
            {
                    &lt;SPAN class=rem&gt;//LogMessage( TRACE_MESSAGE, "Application was invoked using FastCGI over TCP, got a WSAENOTCONN on a call to getpeername()" );                    &lt;/SPAN&gt;
                    &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; TRUE;
            }
            &lt;SPAN class=kwrd&gt;else&lt;/SPAN&gt;            
            &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt;( hr == HRESULT_FROM_WIN32( WSAENOTSOCK ) ) 
            {                    
                    &lt;SPAN class=rem&gt;//LogMessage( TRACE_MESSAGE, "Application was invoked using FastCGI over Named Pipe, got a WSAENOTSOCK on a call to getpeername()" );                    &lt;/SPAN&gt;
                    &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; TRUE;
            }            
            &lt;SPAN class=kwrd&gt;else&lt;/SPAN&gt;            
            {                                        
                    &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; FALSE;            
            }
        }        
        &lt;SPAN class=kwrd&gt;else&lt;/SPAN&gt;
        {
            &lt;SPAN class=rem&gt;// Quit, this app is not compatible with FastCGI&lt;/SPAN&gt;
            &lt;SPAN class=rem&gt;//LogMessage( TRACE_MESSAGE, "Application was invoked using CGI, getpeername() successful" );&lt;/SPAN&gt;
            &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; FALSE;
        }        
}&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&amp;nbsp;&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: Consolas, "Courier New", Courier, Monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: Consolas, "Courier New", Courier, Monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;P&gt;Next step to writing a client is to try and determine if the communication with the Web Server should happen over Named Pipes or TCP. Do an accept() socket call on the STDIN and if it succeeds, use TCP, else use Named Pipes.&amp;nbsp; &lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;bool&lt;/SPAN&gt; IsNamedPipeOrSocket( HANDLE hStdin, FASTCGI_PROTOCOL * useNamedPipeOrSocket )
{
        HRESULT hr = S_OK; 

        &lt;SPAN class=kwrd&gt;try&lt;/SPAN&gt;
        {
            acceptSocket = accept( (SOCKET)hStdin, NULL, NULL ); 

            &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt;( acceptSocket == INVALID_SOCKET )
            {
                (*useNamedPipeOrSocket) = FcgiConfigProtocolNamedPipe;                
            }
            &lt;SPAN class=kwrd&gt;else&lt;/SPAN&gt;
            {
                (*useNamedPipeOrSocket) = FcgiConfigProtocolTcp;
            }            
        }
        &lt;SPAN class=kwrd&gt;catch&lt;/SPAN&gt;(...)
        {
            &lt;SPAN class=rem&gt;//LogMessage( TRACE_EXCEPTION, "Exception is IsNamedPipeOrSocket() function" );&lt;/SPAN&gt;
            &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; FALSE;
        }
        &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; TRUE;
}&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&amp;nbsp;&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: Consolas, "Courier New", Courier, Monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: Consolas, "Courier New", Courier, Monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;P&gt;Then Initialize the transport connection and receive and send messages from and to the FastCGI Server respectively. For more information on this exchange please refer the &lt;A class="" href="http://www.fastcgi.com/devkit/doc/fcgi-spec.html" mce_href="http://www.fastcgi.com/devkit/doc/fcgi-spec.html"&gt;FastCGI protocol specification&lt;/A&gt;.&lt;PRE class=csharpcode&gt;&lt;SPAN class=rem&gt;// Initialize the transport connection based on whether the Server is using Named Pipes or TCP.&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt;( namePipeOrSocket == FcgiConfigProtocolNamedPipe )
{
        pTransport = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; TRANSPORT_NAMEDPIPE();
}
&lt;SPAN class=kwrd&gt;else&lt;/SPAN&gt;
{
        pTransport = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; TRANSPORT_TCP();
}&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;class&lt;/SPAN&gt; TRANSPORT
{
    &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt;: 

        TRANSPORT()
        {}
        ~TRANSPORT()
        {} 

        HRESULT Send( PBYTE pBuffer, DWORD dwSize)
        {
            &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; SendReceive( TRUE, pBuffer, dwSize );
        }
        HRESULT Receive( PBYTE pBuffer, DWORD dwSize)
        {
            &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; SendReceive( FALSE, pBuffer, dwSize );
        } 

    &lt;SPAN class=kwrd&gt;protected&lt;/SPAN&gt;: 

        &lt;SPAN class=kwrd&gt;virtual&lt;/SPAN&gt; HRESULT SendReceive( &lt;SPAN class=kwrd&gt;bool&lt;/SPAN&gt; fSend, PBYTE pBuffer, DWORD dwSize ) = 0;
}; &lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;class&lt;/SPAN&gt; TRANSPORT_NAMEDPIPE : &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; TRANSPORT
{&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;}&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: Consolas, "Courier New", Courier, Monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: Consolas, "Courier New", Courier, Monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: Consolas, "Courier New", Courier, Monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: Consolas, "Courier New", Courier, Monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;
&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;class&lt;/SPAN&gt; TRANSPORT_TCP : &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; TRANSPORT
{&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;}&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: Consolas, "Courier New", Courier, Monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: Consolas, "Courier New", Courier, Monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;
&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;class&lt;/SPAN&gt; TRANSPORT_NAMEDPIPE : &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; TRANSPORT
{
    &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt;: 

        TRANSPORT_NAMEDPIPE()
        {}
        ~TRANSPORT_NAMEDPIPE()
        {}
    &lt;SPAN class=kwrd&gt;protected&lt;/SPAN&gt;:            

        HRESULT SendReceive( &lt;SPAN class=kwrd&gt;bool&lt;/SPAN&gt; fSend, PBYTE pBuffer, DWORD dwSize )
        {
            BOOL fRet  = FALSE;
            DWORD dwLastError = 0;
            DWORD nNumberOfBytesRead = 0; 

            &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt;( fSend == TRUE )
            {        
                fRet = WriteFile( hStdin, pBuffer, dwSize, &amp;amp;nNumberOfBytesRead, NULL );
            }
            &lt;SPAN class=kwrd&gt;else&lt;/SPAN&gt;
            {
                fRet = ReadFile( hStdin, pBuffer, dwSize, &amp;amp;nNumberOfBytesRead, NULL );
            } 

            &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt;(!fRet)
            {
                dwLastError = GetLastError();
            } 

            &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; HRESULT_FROM_WIN32( dwLastError );
        }
}; 

&lt;SPAN class=kwrd&gt;class&lt;/SPAN&gt; TRANSPORT_TCP : &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; TRANSPORT
{
    &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt;: 

        TRANSPORT_TCP()
        {}
        ~TRANSPORT_TCP()
        {} 

    &lt;SPAN class=kwrd&gt;protected&lt;/SPAN&gt;: 

        HRESULT SendReceive( &lt;SPAN class=kwrd&gt;bool&lt;/SPAN&gt; fSend, PBYTE pBuffer, DWORD dwSize )
        {
            &lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt; iRet = 0;
            WSABUF winsockBuffer;
            DWORD   dwBytesTransferred  = 0;
            DWORD   dwFlags             = 0;
            DWORD   dwLastError            = 0; 

            winsockBuffer.len = dwSize;
            winsockBuffer.buf = (&lt;SPAN class=kwrd&gt;char&lt;/SPAN&gt; *)pBuffer; 

            &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt;( fSend == TRUE )
            {
                iRet = WSASend( acceptSocket, &amp;amp;winsockBuffer, 1, &amp;amp;dwBytesTransferred, 0, NULL, NULL ); 
            }
            &lt;SPAN class=kwrd&gt;else&lt;/SPAN&gt;
            {
                iRet = WSARecv( acceptSocket, &amp;amp;winsockBuffer, 1, &amp;amp;dwBytesTransferred, &amp;amp;dwFlags, NULL, NULL );
            } 

            &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt;( SOCKET_ERROR == iRet )
            {
                dwLastError = WSAGetLastError();
            } 

            &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; HRESULT_FROM_WIN32( dwLastError );
        }
};&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&amp;nbsp;&lt;/PRE&gt;
&lt;P&gt;A while ago, Rick who was the developer of the FastCGI core module, published a &lt;A class="" href="http://blogs.iis.net/rickjames/archive/2007/02/04/fake-fastcgi-web-server.aspx" mce_href="http://blogs.iis.net/rickjames/archive/2007/02/04/fake-fastcgi-web-server.aspx"&gt;fake fastcgi server&lt;/A&gt;&amp;nbsp;that works only over Named Pipes. To quickly see the working of this client application, you can run it with the fake server as below. The &lt;FONT color=#ff0000&gt;highlighted&lt;/FONT&gt; messages are returned by the client application TestClient.exe. 
&lt;P&gt;D:\fake&amp;gt;fakefcgi.exe d:\php\hello.php TestClient.exe &lt;BR&gt;Fake FastCGI web server &lt;BR&gt;FCGI_PARAMS sent &lt;BR&gt;FCGI_STDIN sent &lt;BR&gt;Launching receive loop &lt;BR&gt;FCGI_STDOUT: &lt;FONT color=#ff0000&gt;FCGIClient : Obtained FCGI_BEGIN_REQUEST message from Server &lt;BR&gt;&lt;/FONT&gt;FCGI_STDOUT: &lt;FONT color=#ff0000&gt;FCGIClient : Obtained FCGI_PARAMS from Server &lt;BR&gt;&lt;/FONT&gt;FCGI_STDOUT: &lt;FONT color=#ff0000&gt;FCGIClient : Obtained FCGI_STDIN from Server &lt;BR&gt;&lt;/FONT&gt;FCGI_STDOUT: &lt;FONT color=#ff0000&gt;FCGIClient : Sending FCGI_END_REQUEST to Server &lt;BR&gt;&lt;/FONT&gt;FCGI_END_REQUEST received &lt;BR&gt;killing app &lt;BR&gt;FastCGI process exited with 0 &lt;/P&gt;</description></item></channel></rss>