]> git.mxchange.org Git - flightgear.git/blobdiff - src/Network/jpg-httpd.cxx
toggle fullscreen: also adapt GUI plane when resizing
[flightgear.git] / src / Network / jpg-httpd.cxx
index 73d49fa7c4da8b580085a381ea29bb2c515c9b2b..07fa2037b4a05bdaa72f70e74aca2ef1202037b3 100644 (file)
@@ -1,5 +1,4 @@
-// httpd.hxx -- FGFS http property manager interface / external script
-//              and control class
+// jpg-httpd.cxx -- FGFS jpg-http interface
 //
 // Written by Curtis Olson, started June 2001.
 //
 
 #include <simgear/compiler.h>
 
-#include <stdlib.h>            // atoi() atof()
+#include <cstdlib>        // atoi() atof()
 
-#include STL_STRING
+#include <cstring>
 
 #include <simgear/debug/logstream.hxx>
 #include <simgear/io/iochannel.hxx>
 #include <simgear/math/sg_types.hxx>
 #include <simgear/props/props.hxx>
+#include <simgear/io/sg_netChat.hxx>
+#include <simgear/screen/jpgfactory.hxx>
 
 #include <Main/fg_props.hxx>
 #include <Main/globals.hxx>
+#include <Viewer/renderer.hxx>
 
 #include "jpg-httpd.hxx"
 
-SG_USING_STD(string);
+#define __MAX_HTTP_BLOCK_SIZE       4096
+#define __MAX_STRING_SIZE           2048
+#define __TIMEOUT_COUNT             5
+#define __HTTP_GET_STRING           "GET "
 
+#include <osgUtil/SceneView>
+#include <osgViewer/Viewer>
+extern osg::ref_ptr<osgUtil::SceneView> sceneView;
+
+using std::string;
+
+/* simple httpd server that makes an hasty stab at following the http
+   1.1 rfc.  */
+
+//////////////////////////////////////////////////////////////
+// class HttpdImageChannel
+//////////////////////////////////////////////////////////////
+
+class HttpdImageChannel : public simgear::NetChat
+{
+
+    simgear::NetBuffer buffer;
+    trJpgFactory *JpgFactory;
+
+public:
+
+    HttpdImageChannel() : buffer(512) {
+
+        int nWidth  = fgGetInt( "/sim/startup/xsize", 800 );
+        int nHeight = fgGetInt( "/sim/startup/ysize", 600 );
+
+        setTerminator("\r\n");
+        JpgFactory = new trJpgFactory();
+        int error = JpgFactory -> init( nWidth, nHeight );
+        if (0 != error)
+        {
+            SG_LOG( SG_IO, SG_ALERT, "Failed to initialize JPEG-factory, error: " << error);
+        }
+    }
+
+    ~HttpdImageChannel() {
+        JpgFactory -> destroy();
+        delete JpgFactory;
+    }
+
+    virtual void collectIncomingData (const char* s, int n) {
+        buffer.append(s,n);
+    }
+
+    // Handle the actual http request
+    virtual void foundTerminator (void);
+};
+
+//////////////////////////////////////////////////////////////
+// class HttpdImageServer
+//////////////////////////////////////////////////////////////
+
+class HttpdImageServer : private simgear::NetChannel
+{
+    virtual bool writable (void) { return false; }
+
+    virtual void handleAccept (void) {
+        simgear::IPAddress addr;
+        int handle = accept ( &addr );
+        SG_LOG( SG_IO, SG_INFO, "Client " << addr.getHost() << ":" << addr.getPort() << " connected" );
+
+        HttpdImageChannel *hc = new HttpdImageChannel;
+        hc->setHandle ( handle );
+    }
+
+public:
+
+    HttpdImageServer ( int port )
+    {
+        if (!open())
+        {
+            SG_LOG( SG_IO, SG_ALERT, "Failed to open HttpdImage port.");
+            return;
+        }
+
+        if (0 != bind( "", port ))
+        {
+            SG_LOG( SG_IO, SG_ALERT, "Failed to bind HttpdImage port.");
+            return;
+        }
+
+        if (0 != listen( 5 ))
+        {
+            SG_LOG( SG_IO, SG_ALERT, "Failed to listen on HttpdImage port.");
+            return;
+        }
+
+        SG_LOG(SG_IO, SG_ALERT, "HttpdImage server started on port " << port);
+    }
+
+};
+
+//////////////////////////////////////////////////////////////
+// class FGJpegHttpd
+//////////////////////////////////////////////////////////////
+
+FGJpegHttpd::FGJpegHttpd( int p ) :
+    port(p),
+    imageServer(NULL)
+{
+}
+
+FGJpegHttpd::~FGJpegHttpd()
+{
+    delete imageServer;
+}
 
 bool FGJpegHttpd::open() {
     if ( is_enabled() ) {
-       SG_LOG( SG_IO, SG_ALERT, "This shouldn't happen, but the channel " 
-               << "is already in use, ignoring" );
-       return false;
+    SG_LOG( SG_IO, SG_ALERT, "This shouldn't happen, but the channel "
+        << "is already in use, ignoring" );
+    return false;
     }
 
     imageServer = new HttpdImageServer( port );
@@ -65,7 +176,7 @@ bool FGJpegHttpd::open() {
 
 
 bool FGJpegHttpd::process() {
-    netChannel::poll();
+    simgear::NetChannel::poll();
 
     return true;
 }
@@ -73,48 +184,138 @@ bool FGJpegHttpd::process() {
 
 bool FGJpegHttpd::close() {
     delete imageServer;
-
+    imageServer = NULL;
     return true;
 }
 
-
 // Handle http GET requests
-void HttpdImageChannel::foundTerminator (void) {
+void HttpdImageChannel :: foundTerminator( void ) {
 
-    closeWhenDone ();
+    closeWhenDone();
 
-    string response;
+    char      szTemp[256];
+    char      szResponse[__MAX_STRING_SIZE];
+    char      *pRequest     = buffer.getData();
+    int       nStep         = 0;
+    int       nBytesSent    = 0;
+    int       nTimeoutCount = 0;
+    int       nBufferCount  = 0;
+    int       nImageLen;
+    int       nBlockSize;
 
-    const string s = buffer.getData();
-    if ( s.find( "GET " ) == 0 ) {
+
+    if ( strstr( pRequest, __HTTP_GET_STRING ) != NULL )
+    {
         
-        printf("echo: %s\n", s.c_str());
-
-        int ImageLen = JpgFactory->render();
-
-        if( ImageLen ) {
-            response = "HTTP/1.1 200 OK";
-            response += getTerminator();
-            response += "Content-Type: image/jpeg";
-            response += getTerminator();
-            push( response.c_str() );
-
-            char ctmp[256];
-            printf( "info->numbytes = %d\n", ImageLen );
-            sprintf( ctmp, "Content-Length: %d", ImageLen );
-            push( ctmp );
-
-            response = getTerminator();
-            response += "Connection: close";
-            response += getTerminator();
-            response += getTerminator();
-            push( response.c_str() );
-
-            /* can't use strlen on binary data */
-            bufferSend ( (char *)JpgFactory->data(), ImageLen ) ;
+        SG_LOG( SG_IO, SG_DEBUG, "<<<<<<<<< HTTP Request : " << pRequest );
+
+        double left, right, bottom, top, zNear, zFar;
+        osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
+        viewer->getCamera()->getProjectionMatrixAsFrustum(left, right,
+                                                          bottom, top,
+                                                          zNear, zFar);
+        JpgFactory->setFrustum( left, right, bottom, top, zNear, zFar );
+
+        nImageLen  = JpgFactory -> render();
+        nBlockSize = ( nImageLen < __MAX_HTTP_BLOCK_SIZE ? nImageLen : __MAX_HTTP_BLOCK_SIZE );
+
+        if( nImageLen )
+        {
+            strcpy( szResponse, "HTTP/1.1 200 OK" );
+            strcat( szResponse, getTerminator() );
+            strcat( szResponse, "Content-Type: image/jpeg" );
+            strcat( szResponse, getTerminator() );
+
+            SG_LOG( SG_IO, SG_DEBUG, "info->numbytes = " << nImageLen );
+            sprintf( szTemp, "Content-Length: %d", nImageLen );
+            strcat( szResponse, szTemp );
+
+            strcat( szResponse, getTerminator() );
+            strcat( szResponse, "Connection: close" );
+            strcat( szResponse, getTerminator() );
+            strcat( szResponse, getTerminator() );
+
+            if( getHandle() == -1 )
+            {
+                SG_LOG( SG_IO, SG_DEBUG, "<<<<<<<<< Invalid socket handle. Ignoring request.\n" );
+                buffer.remove();
+                SG_LOG( SG_IO, SG_DEBUG, "<<<<<<<<< End of image Transmission.\n" );
+                return;
+            }
+
+            if( send( ( char * ) szResponse, strlen( szResponse ) ) <= 0 )
+            {
+                SG_LOG( SG_IO, SG_DEBUG, "<<<<<<<<< Error to send HTTP response. Ignoring request.\n" );
+                buffer.remove();
+                SG_LOG( SG_IO, SG_DEBUG, "<<<<<<<<< End of image Transmission.\n" );
+                return;
+            }
+
+            /*
+             * Send block with size defined by __MAX_HTTP_BLOCK_SIZE
+             */
+            while( nStep <= nImageLen )
+            {
+                nBufferCount++;
+
+                if( getHandle() == -1 )
+                {
+                    SG_LOG( SG_IO, SG_DEBUG, "<<<<<<<<< Invalid socket handle. Ignoring request.\n" );
+                    break;
+                }
+
+                nBytesSent = send( ( char * ) JpgFactory -> data() + nStep, nBlockSize );
+
+                if( nBytesSent <= 0 )
+                {
+                    if( nTimeoutCount == __TIMEOUT_COUNT )
+                    {
+                        SG_LOG( SG_IO, SG_DEBUG, "<<<<<<<<< Timeout reached. Exiting before end of image transmission.\n" );
+                        nTimeoutCount = 0;
+                        break;
+                    }
+
+                    SG_LOG( SG_IO, SG_DEBUG, "<<<<<<<<< Zero bytes sent.\n" );
+
+#ifdef _WIN32
+                    Sleep(1000);
+#else
+                    sleep(1);
+#endif
+                    nTimeoutCount++;
+                    continue;
+                }
+
+                SG_LOG( SG_IO, SG_DEBUG, ">>>>>>>>> (" << nBufferCount << ") BLOCK STEP " << nStep << " - IMAGELEN " << nImageLen << " - BLOCKSIZE " << nBlockSize << " - SENT " << nBytesSent );
+
+                /*
+                 * Calculate remaining image.
+                 */
+                if( ( nStep + nBlockSize ) >= nImageLen )
+                {
+                    nBlockSize = ( nImageLen - nStep );
+                    nStep += nBlockSize;
+                }
+
+                nStep += nBytesSent;
+                nTimeoutCount = 0;
+#ifdef _WIN32
+                Sleep(1);
+#else
+                usleep( 1000 );
+#endif
+            }
+
+            SG_LOG( SG_IO, SG_DEBUG, "<<<<<<<<< End of image Transmission.\n" );
+
         } else {
-            printf("!!! NO IMAGE !!!\n\tinfo->numbytes = %d\n", ImageLen );
+            SG_LOG( SG_IO, SG_ALERT, "Failed to generate JPEG image data. Error: " << nImageLen);
         }
+
+        /*
+         * Release JPEG buffer.
+         */
+        JpgFactory -> destroy();
     }
 
     buffer.remove();