]> git.mxchange.org Git - flightgear.git/blob - src/Network/jpg-httpd.cxx
Fix JPEG-factory build
[flightgear.git] / src / Network / jpg-httpd.cxx
1 // jpg-httpd.cxx -- FGFS jpg-http interface
2 //
3 // Written by Curtis Olson, started June 2001.
4 //
5 // Copyright (C) 2001  Curtis L. Olson - http://www.flightgear.org/~curt
6 //
7 // Jpeg Image Support added August 2001
8 //  by Norman Vine - nhv@cape.com
9 //
10 // This program is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU General Public License as
12 // published by the Free Software Foundation; either version 2 of the
13 // License, or (at your option) any later version.
14 //
15 // This program is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 // General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with this program; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
23 //
24 // $Id$
25
26
27 #ifdef HAVE_CONFIG_H
28 #  include <config.h>
29 #endif
30
31 #include <simgear/compiler.h>
32
33 #include <cstdlib>        // atoi() atof()
34
35 #include <cstring>
36
37 #include <simgear/debug/logstream.hxx>
38 #include <simgear/io/iochannel.hxx>
39 #include <simgear/math/sg_types.hxx>
40 #include <simgear/props/props.hxx>
41 #include <simgear/io/sg_netChat.hxx>
42 #include <simgear/screen/jpgfactory.hxx>
43
44 #include <Main/fg_props.hxx>
45 #include <Main/globals.hxx>
46 #include <Viewer/renderer.hxx>
47
48 #include "jpg-httpd.hxx"
49
50 #define __MAX_HTTP_BLOCK_SIZE       4096
51 #define __MAX_STRING_SIZE           2048
52 #define __TIMEOUT_COUNT             5
53 #define __HTTP_GET_STRING           "GET "
54
55 #include <osgUtil/SceneView>
56 #include <osgViewer/Viewer>
57 extern osg::ref_ptr<osgUtil::SceneView> sceneView;
58
59 using std::string;
60
61 /* simple httpd server that makes an hasty stab at following the http
62    1.1 rfc.  */
63
64 //////////////////////////////////////////////////////////////
65 // class HttpdImageChannel
66 //////////////////////////////////////////////////////////////
67
68 class HttpdImageChannel : public simgear::NetChat
69 {
70
71     simgear::NetBuffer buffer;
72     trJpgFactory *JpgFactory;
73
74 public:
75
76     HttpdImageChannel() : buffer(512) {
77
78         int nWidth  = fgGetInt( "/sim/startup/xsize", 800 );
79         int nHeight = fgGetInt( "/sim/startup/ysize", 600 );
80
81         setTerminator("\r\n");
82         JpgFactory = new trJpgFactory();
83         int error = JpgFactory -> init( nWidth, nHeight );
84         if (0 != error)
85         {
86             SG_LOG( SG_IO, SG_ALERT, "Failed to initialize JPEG-factory, error: " << error);
87         }
88     }
89
90     ~HttpdImageChannel() {
91         JpgFactory -> destroy();
92         delete JpgFactory;
93     }
94
95     virtual void collectIncomingData (const char* s, int n) {
96         buffer.append(s,n);
97     }
98
99     // Handle the actual http request
100     virtual void foundTerminator (void);
101 };
102
103 //////////////////////////////////////////////////////////////
104 // class HttpdImageServer
105 //////////////////////////////////////////////////////////////
106
107 class HttpdImageServer : private simgear::NetChannel
108 {
109     virtual bool writable (void) { return false; }
110
111     virtual void handleAccept (void) {
112         simgear::IPAddress addr;
113         int handle = accept ( &addr );
114         SG_LOG( SG_IO, SG_INFO, "Client " << addr.getHost() << ":" << addr.getPort() << " connected" );
115
116         HttpdImageChannel *hc = new HttpdImageChannel;
117         hc->setHandle ( handle );
118         
119         poller.addChannel( hc );
120     }
121
122     simgear::NetChannelPoller poller;
123 public:
124
125     HttpdImageServer ( int port )
126     {
127         if (!open())
128         {
129             SG_LOG( SG_IO, SG_ALERT, "Failed to open HttpdImage port.");
130             return;
131         }
132
133         if (0 != bind( "", port ))
134         {
135             SG_LOG( SG_IO, SG_ALERT, "Failed to bind HttpdImage port.");
136             return;
137         }
138
139         if (0 != listen( 5 ))
140         {
141             SG_LOG( SG_IO, SG_ALERT, "Failed to listen on HttpdImage port.");
142             return;
143         }
144
145         poller.addChannel(this);
146         SG_LOG(SG_IO, SG_ALERT, "HttpdImage server started on port " << port);
147     }
148
149     void poll()
150     {
151         poller.poll();
152     }
153 };
154
155 //////////////////////////////////////////////////////////////
156 // class FGJpegHttpd
157 //////////////////////////////////////////////////////////////
158
159 FGJpegHttpd::FGJpegHttpd( int p ) :
160     port(p),
161     imageServer(NULL)
162 {
163 }
164
165 FGJpegHttpd::~FGJpegHttpd()
166 {
167     delete imageServer;
168 }
169
170 bool FGJpegHttpd::open() {
171     if ( is_enabled() ) {
172     SG_LOG( SG_IO, SG_ALERT, "This shouldn't happen, but the channel "
173         << "is already in use, ignoring" );
174     return false;
175     }
176
177     imageServer = new HttpdImageServer( port );
178     
179     set_hz( 5 );                // default to processing requests @ 5Hz
180     set_enabled( true );
181
182     return true;
183 }
184
185
186 bool FGJpegHttpd::process() {
187     imageServer->poll();
188
189     return true;
190 }
191
192
193 bool FGJpegHttpd::close() {
194     delete imageServer;
195     imageServer = NULL;
196     return true;
197 }
198
199 // Handle http GET requests
200 void HttpdImageChannel :: foundTerminator( void ) {
201
202     closeWhenDone();
203
204     char      szTemp[256];
205     char      szResponse[__MAX_STRING_SIZE];
206     char      *pRequest     = buffer.getData();
207     int       nStep         = 0;
208     int       nBytesSent    = 0;
209     int       nTimeoutCount = 0;
210     int       nBufferCount  = 0;
211     int       nImageLen;
212     int       nBlockSize;
213
214
215     if ( strstr( pRequest, __HTTP_GET_STRING ) != NULL )
216     {
217         
218         SG_LOG( SG_IO, SG_DEBUG, "<<<<<<<<< HTTP Request : " << pRequest );
219
220         double left, right, bottom, top, zNear, zFar;
221         osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
222         viewer->getCamera()->getProjectionMatrixAsFrustum(left, right,
223                                                           bottom, top,
224                                                           zNear, zFar);
225         JpgFactory->setFrustum( left, right, bottom, top, zNear, zFar );
226
227         nImageLen  = JpgFactory -> render();
228         nBlockSize = ( nImageLen < __MAX_HTTP_BLOCK_SIZE ? nImageLen : __MAX_HTTP_BLOCK_SIZE );
229
230         if( nImageLen )
231         {
232             strcpy( szResponse, "HTTP/1.1 200 OK" );
233             strcat( szResponse, getTerminator() );
234             strcat( szResponse, "Content-Type: image/jpeg" );
235             strcat( szResponse, getTerminator() );
236
237             SG_LOG( SG_IO, SG_DEBUG, "info->numbytes = " << nImageLen );
238             sprintf( szTemp, "Content-Length: %d", nImageLen );
239             strcat( szResponse, szTemp );
240
241             strcat( szResponse, getTerminator() );
242             strcat( szResponse, "Connection: close" );
243             strcat( szResponse, getTerminator() );
244             strcat( szResponse, getTerminator() );
245
246             if( getHandle() == -1 )
247             {
248                 SG_LOG( SG_IO, SG_DEBUG, "<<<<<<<<< Invalid socket handle. Ignoring request.\n" );
249                 buffer.remove();
250                 SG_LOG( SG_IO, SG_DEBUG, "<<<<<<<<< End of image Transmission.\n" );
251                 return;
252             }
253
254             if( send( ( char * ) szResponse, strlen( szResponse ) ) <= 0 )
255             {
256                 SG_LOG( SG_IO, SG_DEBUG, "<<<<<<<<< Error to send HTTP response. Ignoring request.\n" );
257                 buffer.remove();
258                 SG_LOG( SG_IO, SG_DEBUG, "<<<<<<<<< End of image Transmission.\n" );
259                 return;
260             }
261
262             /*
263              * Send block with size defined by __MAX_HTTP_BLOCK_SIZE
264              */
265             while( nStep <= nImageLen )
266             {
267                 nBufferCount++;
268
269                 if( getHandle() == -1 )
270                 {
271                     SG_LOG( SG_IO, SG_DEBUG, "<<<<<<<<< Invalid socket handle. Ignoring request.\n" );
272                     break;
273                 }
274
275                 nBytesSent = send( ( char * ) JpgFactory -> data() + nStep, nBlockSize );
276
277                 if( nBytesSent <= 0 )
278                 {
279                     if( nTimeoutCount == __TIMEOUT_COUNT )
280                     {
281                         SG_LOG( SG_IO, SG_DEBUG, "<<<<<<<<< Timeout reached. Exiting before end of image transmission.\n" );
282                         nTimeoutCount = 0;
283                         break;
284                     }
285
286                     SG_LOG( SG_IO, SG_DEBUG, "<<<<<<<<< Zero bytes sent.\n" );
287
288 #ifdef _WIN32
289                     Sleep(1000);
290 #else
291                     sleep(1);
292 #endif
293                     nTimeoutCount++;
294                     continue;
295                 }
296
297                 SG_LOG( SG_IO, SG_DEBUG, ">>>>>>>>> (" << nBufferCount << ") BLOCK STEP " << nStep << " - IMAGELEN " << nImageLen << " - BLOCKSIZE " << nBlockSize << " - SENT " << nBytesSent );
298
299                 /*
300                  * Calculate remaining image.
301                  */
302                 if( ( nStep + nBlockSize ) >= nImageLen )
303                 {
304                     nBlockSize = ( nImageLen - nStep );
305                     nStep += nBlockSize;
306                 }
307
308                 nStep += nBytesSent;
309                 nTimeoutCount = 0;
310 #ifdef _WIN32
311                 Sleep(1);
312 #else
313                 usleep( 1000 );
314 #endif
315             }
316
317             SG_LOG( SG_IO, SG_DEBUG, "<<<<<<<<< End of image Transmission.\n" );
318
319         } else {
320             SG_LOG( SG_IO, SG_ALERT, "Failed to generate JPEG image data. Error: " << nImageLen);
321         }
322
323         /*
324          * Release JPEG buffer.
325          */
326         JpgFactory -> destroy();
327     }
328
329     buffer.remove();
330 }