]> git.mxchange.org Git - flightgear.git/blob - src/Network/jpg-httpd.cxx
Fix a couple of 64-bit warnings identified by GCC.
[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
120 public:
121
122     HttpdImageServer ( int port )
123     {
124         if (!open())
125         {
126             SG_LOG( SG_IO, SG_ALERT, "Failed to open HttpdImage port.");
127             return;
128         }
129
130         if (0 != bind( "", port ))
131         {
132             SG_LOG( SG_IO, SG_ALERT, "Failed to bind HttpdImage port.");
133             return;
134         }
135
136         if (0 != listen( 5 ))
137         {
138             SG_LOG( SG_IO, SG_ALERT, "Failed to listen on HttpdImage port.");
139             return;
140         }
141
142         SG_LOG(SG_IO, SG_ALERT, "HttpdImage server started on port " << port);
143     }
144
145 };
146
147 //////////////////////////////////////////////////////////////
148 // class FGJpegHttpd
149 //////////////////////////////////////////////////////////////
150
151 FGJpegHttpd::FGJpegHttpd( int p ) :
152     port(p),
153     imageServer(NULL)
154 {
155 }
156
157 FGJpegHttpd::~FGJpegHttpd()
158 {
159     delete imageServer;
160 }
161
162 bool FGJpegHttpd::open() {
163     if ( is_enabled() ) {
164     SG_LOG( SG_IO, SG_ALERT, "This shouldn't happen, but the channel "
165         << "is already in use, ignoring" );
166     return false;
167     }
168
169     imageServer = new HttpdImageServer( port );
170     
171     set_hz( 5 );                // default to processing requests @ 5Hz
172     set_enabled( true );
173
174     return true;
175 }
176
177
178 bool FGJpegHttpd::process() {
179     simgear::NetChannel::poll();
180
181     return true;
182 }
183
184
185 bool FGJpegHttpd::close() {
186     delete imageServer;
187     imageServer = NULL;
188     return true;
189 }
190
191 // Handle http GET requests
192 void HttpdImageChannel :: foundTerminator( void ) {
193
194     closeWhenDone();
195
196     char      szTemp[256];
197     char      szResponse[__MAX_STRING_SIZE];
198     char      *pRequest     = buffer.getData();
199     int       nStep         = 0;
200     int       nBytesSent    = 0;
201     int       nTimeoutCount = 0;
202     int       nBufferCount  = 0;
203     int       nImageLen;
204     int       nBlockSize;
205
206
207     if ( strstr( pRequest, __HTTP_GET_STRING ) != NULL )
208     {
209         
210         SG_LOG( SG_IO, SG_DEBUG, "<<<<<<<<< HTTP Request : " << pRequest );
211
212         double left, right, bottom, top, zNear, zFar;
213         osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
214         viewer->getCamera()->getProjectionMatrixAsFrustum(left, right,
215                                                           bottom, top,
216                                                           zNear, zFar);
217         JpgFactory->setFrustum( left, right, bottom, top, zNear, zFar );
218
219         nImageLen  = JpgFactory -> render();
220         nBlockSize = ( nImageLen < __MAX_HTTP_BLOCK_SIZE ? nImageLen : __MAX_HTTP_BLOCK_SIZE );
221
222         if( nImageLen )
223         {
224             strcpy( szResponse, "HTTP/1.1 200 OK" );
225             strcat( szResponse, getTerminator() );
226             strcat( szResponse, "Content-Type: image/jpeg" );
227             strcat( szResponse, getTerminator() );
228
229             SG_LOG( SG_IO, SG_DEBUG, "info->numbytes = " << nImageLen );
230             sprintf( szTemp, "Content-Length: %d", nImageLen );
231             strcat( szResponse, szTemp );
232
233             strcat( szResponse, getTerminator() );
234             strcat( szResponse, "Connection: close" );
235             strcat( szResponse, getTerminator() );
236             strcat( szResponse, getTerminator() );
237
238             if( getHandle() == -1 )
239             {
240                 SG_LOG( SG_IO, SG_DEBUG, "<<<<<<<<< Invalid socket handle. Ignoring request.\n" );
241                 buffer.remove();
242                 SG_LOG( SG_IO, SG_DEBUG, "<<<<<<<<< End of image Transmission.\n" );
243                 return;
244             }
245
246             if( send( ( char * ) szResponse, strlen( szResponse ) ) <= 0 )
247             {
248                 SG_LOG( SG_IO, SG_DEBUG, "<<<<<<<<< Error to send HTTP response. Ignoring request.\n" );
249                 buffer.remove();
250                 SG_LOG( SG_IO, SG_DEBUG, "<<<<<<<<< End of image Transmission.\n" );
251                 return;
252             }
253
254             /*
255              * Send block with size defined by __MAX_HTTP_BLOCK_SIZE
256              */
257             while( nStep <= nImageLen )
258             {
259                 nBufferCount++;
260
261                 if( getHandle() == -1 )
262                 {
263                     SG_LOG( SG_IO, SG_DEBUG, "<<<<<<<<< Invalid socket handle. Ignoring request.\n" );
264                     break;
265                 }
266
267                 nBytesSent = send( ( char * ) JpgFactory -> data() + nStep, nBlockSize );
268
269                 if( nBytesSent <= 0 )
270                 {
271                     if( nTimeoutCount == __TIMEOUT_COUNT )
272                     {
273                         SG_LOG( SG_IO, SG_DEBUG, "<<<<<<<<< Timeout reached. Exiting before end of image transmission.\n" );
274                         nTimeoutCount = 0;
275                         break;
276                     }
277
278                     SG_LOG( SG_IO, SG_DEBUG, "<<<<<<<<< Zero bytes sent.\n" );
279
280 #ifdef _WIN32
281                     Sleep(1000);
282 #else
283                     sleep(1);
284 #endif
285                     nTimeoutCount++;
286                     continue;
287                 }
288
289                 SG_LOG( SG_IO, SG_DEBUG, ">>>>>>>>> (" << nBufferCount << ") BLOCK STEP " << nStep << " - IMAGELEN " << nImageLen << " - BLOCKSIZE " << nBlockSize << " - SENT " << nBytesSent );
290
291                 /*
292                  * Calculate remaining image.
293                  */
294                 if( ( nStep + nBlockSize ) >= nImageLen )
295                 {
296                     nBlockSize = ( nImageLen - nStep );
297                     nStep += nBlockSize;
298                 }
299
300                 nStep += nBytesSent;
301                 nTimeoutCount = 0;
302 #ifdef _WIN32
303                 Sleep(1);
304 #else
305                 usleep( 1000 );
306 #endif
307             }
308
309             SG_LOG( SG_IO, SG_DEBUG, "<<<<<<<<< End of image Transmission.\n" );
310
311         } else {
312             SG_LOG( SG_IO, SG_ALERT, "Failed to generate JPEG image data. Error: " << nImageLen);
313         }
314
315         /*
316          * Release JPEG buffer.
317          */
318         JpgFactory -> destroy();
319     }
320
321     buffer.remove();
322 }