~ubuntu-branches/ubuntu/warty/aqsis/warty

« back to all changes in this revision

Viewing changes to libdd/dd.cpp

  • Committer: Bazaar Package Importer
  • Author(s): LaMont Jones
  • Date: 2004-08-24 07:25:04 UTC
  • Revision ID: james.westby@ubuntu.com-20040824072504-zf993vnevvisdsvb
Tags: upstream-0.9.1
ImportĀ upstreamĀ versionĀ 0.9.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Aqsis
 
2
// Copyright ļæ½ 1997 - 2001, Paul C. Gregory
 
3
//
 
4
// Contact: pgregory@aqsis.com
 
5
//
 
6
// This library is free software; you can redistribute it and/or
 
7
// modify it under the terms of the GNU General Public
 
8
// License as published by the Free Software Foundation; either
 
9
// version 2 of the License, or (at your option) any later version.
 
10
//
 
11
// This library is distributed in the hope that it will be useful,
 
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
// General Public License for more details.
 
15
//
 
16
// You should have received a copy of the GNU General Public
 
17
// License along with this library; if not, write to the Free Software
 
18
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
19
 
 
20
 
 
21
/** \file
 
22
                \brief Implements the base message handling functionality required by display drivers.
 
23
                \author Paul C. Gregory (pgregory@aqsis.com)
 
24
                \author Timothy M. Shead (tshead@k-3d.com)
 
25
*/
 
26
 
 
27
#include <iostream>
 
28
#include <memory>
 
29
 
 
30
#include "aqsis.h"
 
31
#include <logging.h>
 
32
 
 
33
#ifdef AQSIS_SYSTEM_WIN32
 
34
 
 
35
#include <winsock2.h>
 
36
 
 
37
#else // AQSIS_SYSTEM_WIN32
 
38
 
 
39
#include <stdlib.h>
 
40
#include <unistd.h>
 
41
#include <netdb.h>
 
42
#include <netinet/in.h>
 
43
#include <sys/time.h>
 
44
#include <sys/types.h>
 
45
#include <sys/socket.h>
 
46
 
 
47
typedef int SOCKET;
 
48
typedef sockaddr_in SOCKADDR_IN;
 
49
typedef sockaddr* PSOCKADDR;
 
50
 
 
51
static const int INVALID_SOCKET = -1;
 
52
static const int SOCKET_ERROR = -1;
 
53
static const int SD_BOTH = 2;
 
54
 
 
55
#endif // !AQSIS_SYSTEM_WIN32
 
56
 
 
57
#include        <stdio.h>
 
58
#include        "displaydriver.h"
 
59
 
 
60
using namespace Aqsis;
 
61
 
 
62
/** External function to handle a query message, must be provided by linking application.
 
63
 */
 
64
TqInt Query( SOCKET s, SqDDMessageBase* pMsg );
 
65
/** External function to handle an open message, must be provided by linking application.
 
66
 */
 
67
TqInt Open( SOCKET s, SqDDMessageBase* pMsg );
 
68
/** External function to handle a data message, must be provided by linking application.
 
69
 */
 
70
TqInt Data( SOCKET s, SqDDMessageBase* pMsg );
 
71
/** External function to handle a close message, must be provided by linking application.
 
72
 */
 
73
TqInt Close( SOCKET s, SqDDMessageBase* pMsg );
 
74
/** External function to handle an abandon message, must be provided by linking application.
 
75
 */
 
76
TqInt Abandon( SOCKET s, SqDDMessageBase* pMsg );
 
77
/** External function to handle a general message, must be provided by linking application.
 
78
 */
 
79
TqInt HandleMessage( SOCKET s, SqDDMessageBase* pMsg );
 
80
 
 
81
START_NAMESPACE( Aqsis )
 
82
 
 
83
static void CloseSocket( SOCKET& Socket );
 
84
 
 
85
/// Hides incompatibilities between sockets and WinSock
 
86
void InitializeSockets()
 
87
{
 
88
#ifdef AQSIS_SYSTEM_WIN32
 
89
        WSADATA wsaData;
 
90
        WSAStartup( MAKEWORD( 2, 0 ), &wsaData );
 
91
#endif // AQSIS_SYSTEM_WIN32
 
92
}
 
93
 
 
94
/// Hides incompatibilities amongst platforms
 
95
hostent* GetHostByName(const std::string& HostName)
 
96
{
 
97
#ifdef AQSIS_SYSTEM_MACOSX
 
98
        // Remove this conditional section and use gethostbyname() if Apple ever
 
99
        // fixes the problem of resolving localhost without a connection to a DNS server
 
100
        return gethostent();    // assumes localhost defined first in /etc/hosts
 
101
#else // AQSIS_SYSTEM_MACOSX
 
102
        return gethostbyname( HostName.c_str() );
 
103
#endif // !AQSIS_SYSTEM_MACOSX
 
104
}
 
105
 
 
106
 
 
107
//----------------------------------------------------------------------
 
108
/** Receive a specified length of data from the specified socket.
 
109
 */
 
110
 
 
111
TqInt DDReceiveSome( TqInt s, void* buffer, TqInt len )
 
112
{
 
113
    TqInt tot = 0, need = len;
 
114
    while ( need > 0 )
 
115
    {
 
116
        TqInt n;
 
117
        if ( ( n = recv( s, reinterpret_cast<char*>( buffer ) + tot, need, 0 ) ) >0 )
 
118
        {
 
119
            need -= n;
 
120
            tot += n;
 
121
        }
 
122
        else
 
123
            return ( n );
 
124
    }
 
125
    return ( tot );
 
126
}
 
127
 
 
128
 
 
129
//----------------------------------------------------------------------
 
130
/** Receive a formatted message from the specified socket.
 
131
 */
 
132
 
 
133
TqInt DDReceiveMsg( TqInt s, SqDDMessageBase*& pMsg )
 
134
{
 
135
    SqDDMessageBase msghdr;
 
136
    TqInt ret;
 
137
 
 
138
    pMsg = 0;
 
139
    if ( ( ret = DDReceiveSome( s, &msghdr, sizeof( msghdr ) ) ) > 0 )
 
140
    {
 
141
        // Allocate space for the message.
 
142
        char * msgbuffer = new char[ msghdr.m_MessageLength ];
 
143
        // Copy the header.
 
144
        memcpy( msgbuffer, &msghdr, ret );
 
145
        pMsg = reinterpret_cast<SqDDMessageBase*>( msgbuffer );
 
146
 
 
147
        if ( ret < msghdr.m_MessageLength )
 
148
        {
 
149
            if ( ( ret = DDReceiveSome( s, msgbuffer + ret, msghdr.m_MessageLength - ret ) ) <= 0 )
 
150
            {
 
151
                delete[] ( msgbuffer );
 
152
                pMsg = 0;
 
153
                return ( ret );
 
154
            }
 
155
        }
 
156
        return ( msghdr.m_MessageLength );
 
157
    }
 
158
    return ( ret );
 
159
}
 
160
 
 
161
 
 
162
 
 
163
//----------------------------------------------------------------------
 
164
/** Send a specified length of data to the specified socket.
 
165
 */
 
166
 
 
167
TqInt DDSendSome( TqInt s, void* buffer, TqInt len )
 
168
{
 
169
    TqInt tot = 0, need = len;
 
170
    while ( need > 0 )
 
171
    {
 
172
        TqInt n;
 
173
        if ( ( n = send( s, reinterpret_cast<char*>( buffer ) + tot, need, 0 ) ) >0 )
 
174
        {
 
175
            need -= n;
 
176
            tot += n;
 
177
        }
 
178
        else
 
179
            return ( n );
 
180
    }
 
181
    return ( tot );
 
182
}
 
183
 
 
184
 
 
185
//----------------------------------------------------------------------
 
186
/** Send a preformatted message to the specified port.
 
187
 */
 
188
 
 
189
TqInt DDSendMsg( TqInt s, SqDDMessageBase* pMsg )
 
190
{
 
191
    return ( DDSendSome( s, pMsg, pMsg->m_MessageLength ) );
 
192
}
 
193
 
 
194
 
 
195
static SOCKET g_Socket = INVALID_SOCKET;
 
196
 
 
197
//----------------------------------------------------------------------
 
198
/** Enter a loop processing messages from the server.
 
199
 */
 
200
 
 
201
TqInt DDInitialise( const TqChar* phostname, TqInt port )
 
202
{
 
203
        InitializeSockets();
 
204
 
 
205
        // Open a socket.
 
206
        g_Socket = socket( AF_INET, SOCK_STREAM, 0 );
 
207
        if ( g_Socket == INVALID_SOCKET )
 
208
                return -1;
 
209
 
 
210
        // If no host name specified, use the local machine
 
211
        std::string hostName(phostname ? phostname : "");
 
212
        if(hostName.empty())
 
213
                {
 
214
                        hostName.resize(256);
 
215
                        gethostname( &hostName[0], hostName.size() );
 
216
                        hostName.resize(strlen(hostName.c_str()));
 
217
                }
 
218
                
 
219
        hostent* const pHost = GetHostByName(hostName);
 
220
 
 
221
        SOCKADDR_IN saTemp;
 
222
        memset( &saTemp, 0, sizeof( saTemp ) );
 
223
        saTemp.sin_family = AF_INET;
 
224
        
 
225
        if ( port < 0 )
 
226
                port = 27747;
 
227
 
 
228
        saTemp.sin_port = htons( port );
 
229
        memcpy( &saTemp.sin_addr, pHost->h_addr, pHost->h_length );
 
230
 
 
231
        if(SOCKET_ERROR == connect( g_Socket, PSOCKADDR(&saTemp), sizeof(saTemp)))
 
232
                {
 
233
                        std::cerr << error << "Connecting to " << hostName.c_str() << ":" << port << " ... " << strerror(errno) << std::endl;
 
234
                        CloseSocket(g_Socket);
 
235
                        return -1;
 
236
                }
 
237
 
 
238
        return 0;
 
239
}
 
240
 
 
241
//----------------------------------------------------------------------
 
242
/** Process a single message synchronously (blocks), returning false iff there are no more messages to process
 
243
 */
 
244
 
 
245
bool DDProcessMessage()
 
246
{
 
247
    SqDDMessageBase * message = 0;
 
248
    const TqInt length = DDReceiveMsg( g_Socket, message );
 
249
    if ( 0 == length )
 
250
    {
 
251
        // Connection closed gracefully by server ...
 
252
        CloseSocket( g_Socket );
 
253
        return false;
 
254
    }
 
255
    else if ( length < 0 )
 
256
    {
 
257
        std::cerr << "Error reading from socket" << std::endl;
 
258
        CloseSocket( g_Socket );
 
259
        return false;
 
260
    }
 
261
 
 
262
    // Make sure our message gets deallocated ...
 
263
    std::auto_ptr<SqDDMessageBase> messagestorage( message );
 
264
 
 
265
    switch ( message->m_MessageID )
 
266
    {
 
267
    case MessageID_FormatQuery:
 
268
        {
 
269
            if ( 0 != Query( g_Socket, message ) )
 
270
            {
 
271
                CloseSocket( g_Socket );
 
272
                return false;
 
273
            }
 
274
        }
 
275
        break;
 
276
 
 
277
    case MessageID_Open:
 
278
        {
 
279
            if ( 0 != Open( g_Socket, message ) )
 
280
            {
 
281
                CloseSocket( g_Socket );
 
282
                return false;
 
283
            }
 
284
        }
 
285
        break;
 
286
 
 
287
    case MessageID_Data:
 
288
        {
 
289
            if ( 0 != Data( g_Socket, message ) )
 
290
            {
 
291
                CloseSocket( g_Socket );
 
292
                return false;
 
293
            }
 
294
        }
 
295
        break;
 
296
 
 
297
    case MessageID_Close:
 
298
        {
 
299
            if ( 0 != Close( g_Socket, message ) )
 
300
            {
 
301
                CloseSocket( g_Socket );
 
302
 
 
303
#ifdef DD_EXIT_AT_CLOSE
 
304
                // Define DD_EXIT_AT_CLOSE for display device exit when rendering done
 
305
                exit( 0 );
 
306
#endif
 
307
 
 
308
                return false;
 
309
            }
 
310
        }
 
311
        break;
 
312
 
 
313
    default:
 
314
        {
 
315
            if ( 0 != HandleMessage( g_Socket, message ) )
 
316
            {
 
317
                CloseSocket( g_Socket );
 
318
                return false;
 
319
            }
 
320
        }
 
321
        break;
 
322
    }
 
323
 
 
324
    return true;
 
325
}
 
326
 
 
327
//----------------------------------------------------------------------
 
328
/**     Process a single message asynchronously (returns after the given timeout if there are no messages to process),
 
329
                returning false iff there are no more messages to process
 
330
 */
 
331
 
 
332
bool DDProcessMessageAsync( const TqUint TimeoutSeconds, const TqUint TimeoutMicroSeconds )
 
333
{
 
334
    // Check to see if we have anything waiting ...
 
335
    fd_set files;
 
336
    FD_ZERO( &files );
 
337
    FD_SET( g_Socket, &files );
 
338
 
 
339
    timeval timeout;
 
340
    timeout.tv_sec = TimeoutSeconds;
 
341
    timeout.tv_usec = TimeoutMicroSeconds;
 
342
 
 
343
    const int ready = select( g_Socket + 1, &files, 0, 0, &timeout );
 
344
    if ( 0 == ready )
 
345
        return true;
 
346
 
 
347
    // We've got data waiting, so process it normally ...
 
348
    return DDProcessMessage();
 
349
}
 
350
 
 
351
//----------------------------------------------------------------------
 
352
/** Enter a loop processing messages from the server.
 
353
 */
 
354
 
 
355
TqInt DDProcessMessages()
 
356
{
 
357
    while ( 1 )
 
358
    {
 
359
        SqDDMessageBase * pMsg;
 
360
        TqInt len;
 
361
        TqInt ret;
 
362
        if ( ( len = DDReceiveMsg( g_Socket, pMsg ) ) > 0 )
 
363
        {
 
364
            switch ( pMsg->m_MessageID )
 
365
            {
 
366
            case MessageID_FormatQuery:
 
367
                {
 
368
                    if ( ( ret = Query( g_Socket, pMsg ) ) != 0 )
 
369
                    {
 
370
                        CloseSocket( g_Socket );
 
371
                        return ( ret );
 
372
                    }
 
373
                }
 
374
                break;
 
375
 
 
376
            case MessageID_Open:
 
377
                {
 
378
                    if ( ( ret = Open( g_Socket, pMsg ) ) != 0 )
 
379
                    {
 
380
                        CloseSocket( g_Socket );
 
381
                        return ( ret );
 
382
                    }
 
383
                }
 
384
                break;
 
385
 
 
386
            case MessageID_Data:
 
387
                {
 
388
                    if ( ( ret = Data( g_Socket, pMsg ) ) != 0 )
 
389
                    {
 
390
                        CloseSocket( g_Socket );
 
391
                        return ( ret );
 
392
                    }
 
393
                }
 
394
                break;
 
395
 
 
396
            case MessageID_Close:
 
397
                {
 
398
                    if ( ( ret = Close( g_Socket, pMsg ) ) != 0 )
 
399
                    {
 
400
                        CloseSocket( g_Socket );
 
401
 
 
402
#ifdef DD_EXIT_AT_CLOSE
 
403
                        // Define DD_EXIT_AT_CLOSE for display device exit when rendering done
 
404
                        exit( 0 );
 
405
#endif
 
406
 
 
407
                        return ( ret );
 
408
                    }
 
409
                }
 
410
                break;
 
411
 
 
412
            case MessageID_Abandon:
 
413
                {
 
414
                    if ( ( ret = Abandon( g_Socket, pMsg ) ) != 0 )
 
415
                    {
 
416
                        CloseSocket( g_Socket );
 
417
 
 
418
#ifdef DD_EXIT_AT_CLOSE
 
419
                        // Define DD_EXIT_AT_CLOSE for display device exit when rendering done
 
420
                        exit( 0 );
 
421
#endif
 
422
 
 
423
                        return ( ret );
 
424
                    }
 
425
                }
 
426
                break;
 
427
 
 
428
            default:
 
429
                {
 
430
                    if ( ( ret = HandleMessage( g_Socket, pMsg ) ) != 0 )
 
431
                    {
 
432
                        CloseSocket( g_Socket );
 
433
                        return ( ret );
 
434
                    }
 
435
                }
 
436
            }
 
437
            delete[] ( pMsg );
 
438
        }
 
439
        else if ( len == 0 )
 
440
        {
 
441
            // Connection closed gracefully by server.
 
442
            CloseSocket( g_Socket );
 
443
            return ( 0 );
 
444
        }
 
445
        else
 
446
        {
 
447
            std::cerr << "Error reading from socket" << std::endl;
 
448
            CloseSocket( g_Socket );
 
449
            return ( -1 );
 
450
        }
 
451
    }
 
452
}
 
453
 
 
454
/** Close the given socket.
 
455
 */
 
456
static void CloseSocket( SOCKET& Socket )
 
457
{
 
458
#ifdef AQSIS_SYSTEM_WIN32
 
459
    int x = 1;
 
460
    LINGER ling;
 
461
    ling.l_onoff = 1;
 
462
    ling.l_linger = 10;
 
463
    setsockopt( Socket, SOL_SOCKET, SO_LINGER, reinterpret_cast<const char*>( &ling ), sizeof( ling ) );
 
464
    shutdown( Socket, SD_BOTH );
 
465
    closesocket( Socket );
 
466
#else // AQSIS_SYSTEM_WIN32
 
467
    shutdown( Socket, SD_BOTH );
 
468
    close( Socket );
 
469
#endif // !AQSIS_SYSTEM_WIN32
 
470
 
 
471
    Socket = INVALID_SOCKET;
 
472
}
 
473
 
 
474
 
 
475
//---------------------------------------------------------------------
 
476
 
 
477
END_NAMESPACE( Aqsis )