~ubuntu-branches/ubuntu/karmic/gnash/karmic

« back to all changes in this revision

Viewing changes to libnet/network.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alexander Sack
  • Date: 2008-10-13 14:29:49 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20081013142949-f6qdvnu4mn05ltdc
Tags: 0.8.4~~bzr9980-0ubuntu1
* new upstream release 0.8.4 (LP: #240325)
* ship new lib usr/lib/gnash/libmozsdk.so.* in mozilla-plugin-gnash
  - update debian/mozilla-plugin-gnash.install
* ship new lib usr/lib/gnash/libgnashnet.so.* in gnash-common
  - update debian/gnash-common.install
* add basic debian/build_head script to build latest CVS head packages.
  - add debian/build_head
* new sound architecture requires build depend on libsdl1.2-dev
  - update debian/control
* head build script now has been completely migrated to bzr (upstream +
  ubuntu)
  - update debian/build_head
* disable kde gui until klash/qt4 has been fixed; keep kde packages as empty
  packages for now.
  - update debian/rules
  - debian/klash.install
  - debian/klash.links
  - debian/klash.manpages
  - debian/konqueror-plugin-gnash.install
* drop libkonq5-dev build dependency accordingly
  - update debian/control
* don't install headers manually anymore. gnash doesnt provide a -dev
  package after all
  - update debian/rules
* update libs installed in gnash-common; libgnashserver-*.so is not available
  anymore (removed); in turn we add the new libgnashcore-*.so
  - update debian/gnash-common.install
* use -Os for optimization and properly pass CXXFLAGS=$(CFLAGS) to configure
  - update debian/rules
* touch firefox .autoreg in postinst of mozilla plugin
  - update debian/mozilla-plugin-gnash.postinst
* link gnash in ubufox plugins directory for the plugin alternative switcher
  - add debian/mozilla-plugin-gnash.links
* suggest ubufox accordingly
  - update debian/control
* add new required build-depends on libgif-dev
  - update debian/control
* add Xb-Npp-Description and Xb-Npp-File as new plugin database meta data
  - update debian/control

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
//   Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
 
3
//
 
4
// This program is free software; you can redistribute it and/or modify
 
5
// it under the terms of the GNU General Public License as published by
 
6
// the Free Software Foundation; either version 3 of the License, or
 
7
// (at your option) any later version.
 
8
//
 
9
// This program is distributed in the hope that it will be useful,
 
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
// GNU General Public License for more details.
 
13
//
 
14
// You should have received a copy of the GNU General Public License
 
15
// along with this program; if not, write to the Free Software
 
16
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
17
//
 
18
 
 
19
#ifdef HAVE_CONFIG_H
 
20
#include "gnashconfig.h"
 
21
#endif
 
22
 
 
23
#include <boost/thread/mutex.hpp>
 
24
 
 
25
 
 
26
#include "utility.h"
 
27
#include "log.h"
 
28
#include "network.h"
 
29
 
 
30
#include <sys/types.h>
 
31
#include <cstring>
 
32
#include <cstdio>
 
33
#include <cerrno>
 
34
#include <fcntl.h>
 
35
#if defined(HAVE_WINSOCK_H) && !defined(__OS2__)
 
36
# include <winsock2.h>
 
37
# include <windows.h>
 
38
# include <sys/stat.h>
 
39
# include <io.h>
 
40
# include <ws2tcpip.h>
 
41
#else
 
42
# include <sys/time.h>
 
43
# include <unistd.h>
 
44
# include <sys/select.h>
 
45
# include <netinet/in.h>
 
46
# include <arpa/inet.h>
 
47
# include <sys/socket.h>
 
48
# include <sys/un.h>
 
49
# include <netdb.h>
 
50
# include <sys/param.h>
 
51
# include <sys/select.h>
 
52
#endif
 
53
 
 
54
#include "buffer.h"
 
55
 
 
56
#ifndef MAXHOSTNAMELEN
 
57
#define MAXHOSTNAMELEN 256
 
58
#endif
 
59
 
 
60
using namespace std;
 
61
 
 
62
namespace gnash {
 
63
 
 
64
static const char *DEFAULTPROTO = "tcp";
 
65
static const short DEFAULTPORT  = RTMP_PORT;
 
66
 
 
67
#ifndef INADDR_NONE
 
68
#define INADDR_NONE  0xffffffff
 
69
#endif
 
70
 
 
71
Network::Network()
 
72
        :
 
73
        _ipaddr(INADDR_ANY),
 
74
        _sockfd(0),
 
75
        _listenfd(0),
 
76
        _port(0),
 
77
        _connected(false),
 
78
        _debug(false),
 
79
        _timeout(0)
 
80
{
 
81
//    GNASH_REPORT_FUNCTION;
 
82
#if defined(HAVE_WINSOCK_H) && !defined(__OS2__)
 
83
    WORD wVersionRequested;
 
84
    WSADATA wsaData;
 
85
    wVersionRequested = MAKEWORD(1, 1);         // Windows Sockets 1.1
 
86
    if (WSAStartup( wVersionRequested, &wsaData ) != 0) {
 
87
        log_error(_("Could not find a usable WinSock DLL"));
 
88
        exit(1);
 
89
    }
 
90
#endif
 
91
 
 
92
}
 
93
 
 
94
Network::~Network()
 
95
{
 
96
//    GNASH_REPORT_FUNCTION;
 
97
#if defined(HAVE_WINSOCK_H) && !defined(__OS2__)
 
98
    WSACleanup();
 
99
#else
 
100
    closeNet();
 
101
#endif
 
102
}
 
103
 
 
104
// Description: Create a tcp/ip network server. This creates a server
 
105
//              that listens for incoming socket connections. This
 
106
//              supports IP aliasing on the host, and will sequntially
 
107
//              look for IP address to bind this port to.
 
108
int
 
109
Network::createServer(void)
 
110
{
 
111
//    GNASH_REPORT_FUNCTION;
 
112
 
 
113
    return createServer(DEFAULTPORT);
 
114
}
 
115
 
 
116
// FIXME: Should also support IPv6 (AF_INET6)
 
117
int
 
118
Network::createServer(short port)
 
119
{
 
120
//    GNASH_REPORT_FUNCTION;
 
121
 
 
122
    struct protoent *ppe;
 
123
    struct sockaddr_in sock_in;
 
124
    int             on, type;
 
125
    int             retries = 0;
 
126
    in_addr_t       nodeaddr;
 
127
 
 
128
#if 0
 
129
    if (port < 1024) {
 
130
        log_error(_("Can't connect to privileged port #%d"), port);
 
131
        return -1;
 
132
    }
 
133
#endif
 
134
    
 
135
    if (_listenfd >= 2) {
 
136
        log_debug("already connected to port %hd", port);
 
137
        return _listenfd;
 
138
    }
 
139
    
 
140
    const struct hostent *host = gethostbyname("localhost");
 
141
    struct in_addr *thisaddr = reinterpret_cast<struct in_addr *>(host->h_addr_list[0]);
 
142
    _ipaddr = thisaddr->s_addr;
 
143
    memset(&sock_in, 0, sizeof(sock_in));
 
144
 
 
145
#if 0
 
146
    // Accept incoming connections only on our IP number
 
147
    sock_in.sin_addr.s_addr = thisaddr->s_addr;
 
148
#else
 
149
    // Accept incoming connections on any IP number
 
150
    sock_in.sin_addr.s_addr = INADDR_ANY;
 
151
#endif
 
152
 
 
153
    _ipaddr = sock_in.sin_addr.s_addr;
 
154
    sock_in.sin_family = AF_INET;
 
155
    sock_in.sin_port = htons(port);
 
156
 
 
157
    if ((ppe = getprotobyname(DEFAULTPROTO)) == 0) {
 
158
        log_error(_("unable to get protocol entry for %s"),
 
159
                DEFAULTPROTO);
 
160
        return -1;
 
161
    }
 
162
 
 
163
    // set protocol type
 
164
    if ( strcmp(DEFAULTPROTO, "udp") == 0) {
 
165
        type = SOCK_DGRAM;
 
166
    } else {
 
167
        type = SOCK_STREAM;
 
168
    }
 
169
 
 
170
    // Get a file descriptor for this socket connection
 
171
    _listenfd = socket(PF_INET, type, ppe->p_proto);
 
172
 
 
173
    // error, wasn't able to create a socket
 
174
    if (_listenfd < 0) {
 
175
        log_error(_("unable to create socket: %s"), strerror(errno));
 
176
        return -1;
 
177
    }
 
178
 
 
179
    on = 1;
 
180
    if (setsockopt(_listenfd, SOL_SOCKET, SO_REUSEADDR,
 
181
                   (char *)&on, sizeof(on)) < 0) {
 
182
        log_error(_("setsockopt SO_REUSEADDR failed"));
 
183
        return -1;
 
184
    }
 
185
 
 
186
    retries = 0;
 
187
 
 
188
    nodeaddr = inet_lnaof(*thisaddr);
 
189
    while (retries < 5) {
 
190
        if (bind(_listenfd, reinterpret_cast<struct sockaddr *>(&sock_in),
 
191
                 sizeof(sock_in)) == -1) {
 
192
            log_error(_("unable to bind to port %hd: %s"),
 
193
                    port, strerror(errno));
 
194
//                    inet_ntoa(sock_in.sin_addr), strerror(errno));
 
195
            retries++;
 
196
        }
 
197
 
 
198
        if (_debug) {
 
199
//              char  ascip[INET_ADDRSTRLEN];
 
200
//              inet_ntop(sock_in.sin_family, &_ipaddr, ascip, INET_ADDRSTRLEN);
 
201
                char *ascip = ::inet_ntoa(sock_in.sin_addr);
 
202
                log_debug(_("Server bound to service on %s, port %hd, using fd #%d"),
 
203
                    ascip, ntohs(sock_in.sin_port),
 
204
                    _listenfd);
 
205
        }
 
206
 
 
207
        if (type == SOCK_STREAM && listen(_listenfd, 5) < 0) {
 
208
            log_error(_("unable to listen on port: %hd: %s "),
 
209
                port, strerror(errno));
 
210
            return -1;
 
211
        }
 
212
 
 
213
        // We have a socket created
 
214
        _port = port;
 
215
        return _listenfd;
 
216
    }
 
217
    return -1;
 
218
}
 
219
 
 
220
// Description: Accept a new network connection for the port we have
 
221
//              created a server for.
 
222
// The default is to block.
 
223
int
 
224
Network::newConnection(void)
 
225
{
 
226
//    GNASH_REPORT_FUNCTION;
 
227
 
 
228
    return newConnection(true, _listenfd);
 
229
}
 
230
 
 
231
int
 
232
Network::newConnection(int fd)
 
233
{
 
234
//    GNASH_REPORT_FUNCTION;
 
235
 
 
236
    return newConnection(true, fd);
 
237
}
 
238
 
 
239
int
 
240
Network::newConnection(bool block)
 
241
{
 
242
//    GNASH_REPORT_FUNCTION;
 
243
 
 
244
    return newConnection(block, _listenfd);
 
245
}
 
246
 
 
247
int
 
248
Network::newConnection(bool block, int fd)
 
249
{
 
250
    GNASH_REPORT_FUNCTION;
 
251
 
 
252
    struct sockaddr     newfsin;
 
253
    socklen_t           alen;
 
254
    int                 ret;
 
255
    struct timeval        tval;
 
256
    fd_set                fdset;
 
257
    int                   retries = 3;
 
258
 
 
259
    alen = sizeof(struct sockaddr_in);
 
260
 
 
261
    if (fd <= 2) {
 
262
        return -1;
 
263
    }
 
264
    if (_debug) {
 
265
        log_debug(_("Trying to accept net traffic on fd #%d for port %d"), fd, _port);
 
266
    }
 
267
 
 
268
    while (retries--) {
 
269
        // We use select to wait for the read file descriptor to be
 
270
        // active, which means there is a client waiting to connect.
 
271
        FD_ZERO(&fdset);
 
272
        // also return on any input from stdin
 
273
//         if (_console) {
 
274
//             FD_SET(fileno(stdin), &fdset);
 
275
//         }
 
276
        FD_SET(fd, &fdset);
 
277
 
 
278
        // Reset the timeout value, since select modifies it on return. To
 
279
        // block, set the timeout to zero.
 
280
        tval.tv_sec = 1;
 
281
        tval.tv_usec = 0;
 
282
 
 
283
        if (block) {
 
284
            ret = select(fd+1, &fdset, NULL, NULL, NULL);
 
285
        } else {
 
286
            ret = select(fd+1, &fdset, NULL, NULL, &tval);
 
287
        }
 
288
 
 
289
        if (FD_ISSET(0, &fdset)) {
 
290
            if (_debug) {
 
291
                log_debug(_("There is data at the console for stdin"));
 
292
            }
 
293
            return 1;
 
294
        }
 
295
 
 
296
        // If interupted by a system call, try again
 
297
        if (ret == -1 && errno == EINTR) {
 
298
            log_debug(_("The accept() socket for fd #%d was interupted by a system call"), fd);
 
299
        }
 
300
 
 
301
        if (ret == -1) {
 
302
            log_debug(_("The accept() socket for fd #%d never was available for writing"), fd);
 
303
            return -1;
 
304
        }
 
305
 
 
306
        if (ret == 0) {
 
307
            if (_debug) {
 
308
                log_debug(_("The accept() socket for fd #%d timed out waiting to write"), fd);
 
309
            }
 
310
        }
 
311
    }
 
312
 
 
313
#ifndef HAVE_WINSOCK_H
 
314
    fcntl(_listenfd, F_SETFL, O_NONBLOCK); // Don't let accept() block
 
315
#endif
 
316
    _sockfd = accept(fd, &newfsin, &alen);
 
317
 
 
318
    if (_sockfd < 0) {
 
319
        log_error(_("unable to accept: %s"), strerror(errno));
 
320
        return -1;
 
321
    }
 
322
 
 
323
    if (_debug) {
 
324
        log_debug(_("Accepting tcp/ip connection on fd #%d for port %d"), _sockfd, _port);
 
325
    }
 
326
 
 
327
    return _sockfd;
 
328
}
 
329
 
 
330
#ifdef _WIN32
 
331
/* from sys/socket.h */
 
332
typedef unsigned short      sa_family_t;
 
333
 
 
334
/* from sys/un.h */
 
335
#define UNIX_PATH_MAX   108
 
336
 
 
337
struct sockaddr_un {
 
338
    sa_family_t sun_family; /* AF_UNIX */
 
339
    char sun_path[UNIX_PATH_MAX];   /* pathname */
 
340
};
 
341
 
 
342
#endif /* _WIN32 */
 
343
 
 
344
// Connect to a named pipe
 
345
bool
 
346
Network::connectSocket(const string &sockname)
 
347
{
 
348
//    GNASH_REPORT_FUNCTION;
 
349
 
 
350
    struct sockaddr_un  addr;
 
351
    fd_set              fdset;
 
352
    struct timeval      tval;
 
353
    int                 ret;
 
354
    int                 retries;
 
355
 
 
356
    addr.sun_family = AF_UNIX;
 
357
    // socket names must be 108 bytes or less as specifiec in sys/un.h.
 
358
    strncpy(addr.sun_path, sockname.c_str(), 100);
 
359
 
 
360
    _sockfd = ::socket(AF_UNIX, SOCK_STREAM, 0);
 
361
    if (_sockfd < 0)
 
362
        {
 
363
            log_error(_("unable to create socket: %s"), strerror(errno));
 
364
            _sockfd = -1;
 
365
            return false;
 
366
        }
 
367
 
 
368
    retries = 2;
 
369
    while (retries-- > 0) {
 
370
        // We use select to wait for the read file descriptor to be
 
371
        // active, which means there is a client waiting to connect.
 
372
        FD_ZERO(&fdset);
 
373
        FD_SET(_sockfd, &fdset);
 
374
 
 
375
        // Reset the timeout value, since select modifies it on return. To
 
376
        // block, set the timeout to zero.
 
377
        tval.tv_sec = 5;
 
378
        tval.tv_usec = 0;
 
379
 
 
380
        ret = ::select(_sockfd+1, &fdset, NULL, NULL, &tval);
 
381
 
 
382
        // If interupted by a system call, try again
 
383
        if (ret == -1 && errno == EINTR)
 
384
            {
 
385
                log_debug(_("The connect() socket for fd %d was interupted by a system call"),
 
386
                        _sockfd);
 
387
                continue;
 
388
            }
 
389
 
 
390
        if (ret == -1)
 
391
            {
 
392
                log_debug(_("The connect() socket for fd %d never was available for writing"),
 
393
                        _sockfd);
 
394
#ifdef HAVE_WINSOCK_H
 
395
                ::shutdown(_sockfd, 0); // FIXME: was SHUT_BOTH
 
396
#else
 
397
                ::shutdown(_sockfd, SHUT_RDWR);
 
398
#endif
 
399
                _sockfd = -1;
 
400
                return false;
 
401
            }
 
402
        if (ret == 0) {
 
403
            log_error(_("The connect() socket for fd %d timed out waiting to write"),
 
404
                      _sockfd);
 
405
            continue;
 
406
        }
 
407
 
 
408
        if (ret > 0) {
 
409
            ret = ::connect(_sockfd, reinterpret_cast<struct sockaddr *>(&addr), sizeof(addr));
 
410
            if (ret == 0) {
 
411
                log_debug(_("\tsocket name %s for fd %d"), sockname, _sockfd);
 
412
                _connected = true;
 
413
                assert(_sockfd > 0);
 
414
                return true;
 
415
            }
 
416
            if (ret == -1) {
 
417
                log_error(_("The connect() socket for fd %d never was available for writing"),
 
418
                        _sockfd);
 
419
                _sockfd = -1;
 
420
                assert(!_connected);
 
421
                return false;
 
422
            }
 
423
        }
 
424
    }
 
425
    
 
426
 
 
427
#ifndef HAVE_WINSOCK_H
 
428
    fcntl(_sockfd, F_SETFL, O_NONBLOCK);
 
429
#endif
 
430
 
 
431
    _connected = true;
 
432
    assert(_sockfd > 0);
 
433
    return true;    
 
434
}
 
435
 
 
436
// Create a client connection to a tcp/ip based service
 
437
bool
 
438
Network::createClient(void)
 
439
{
 
440
//    GNASH_REPORT_FUNCTION;
 
441
 
 
442
    return createClient("localhost", RTMP_PORT);
 
443
}
 
444
bool
 
445
Network::createClient(short /* port */)
 
446
{
 
447
//    GNASH_REPORT_FUNCTION;
 
448
 
 
449
    return false;
 
450
}
 
451
 
 
452
bool
 
453
Network::createClient(const string &hostname)
 
454
{
 
455
//    GNASH_REPORT_FUNCTION;
 
456
 
 
457
    return createClient(hostname, RTMP_PORT);
 
458
}
 
459
 
 
460
bool
 
461
Network::createClient(const string &hostname, short port)
 
462
{
 
463
    GNASH_REPORT_FUNCTION;
 
464
 
 
465
    struct sockaddr_in  sock_in;
 
466
    fd_set              fdset;
 
467
    struct timeval      tval;
 
468
    int                 ret;
 
469
    int                 retries;
 
470
    char                thishostname[MAXHOSTNAMELEN];
 
471
    struct protoent     *proto;
 
472
 
 
473
    assert( ! connected() );
 
474
 
 
475
    if (port < 1024) {
 
476
        log_error(_("Can't connect to privileged port %hd"), port);
 
477
        _connected = false;
 
478
        return false;
 
479
    }
 
480
 
 
481
    _port = port;    
 
482
    log_debug(_("%s: to host %s at port %d"), __FUNCTION__, hostname, port);
 
483
 
 
484
    memset(&sock_in, 0, sizeof(struct sockaddr_in));
 
485
    memset(&thishostname, 0, MAXHOSTNAMELEN);
 
486
    if (hostname.size() == 0) {
 
487
        if (gethostname(thishostname, MAXHOSTNAMELEN) == 0) {
 
488
            log_debug(_("The hostname for this machine is %s"), thishostname);
 
489
        } else {
 
490
            log_debug(_("Couldn't get the hostname for this machine"));
 
491
            return false;
 
492
        }
 
493
    }
 
494
    const struct hostent *hent = ::gethostbyname(hostname.c_str());
 
495
    if (hent > 0) {
 
496
        ::memcpy(&sock_in.sin_addr, hent->h_addr, hent->h_length);
 
497
    }
 
498
    sock_in.sin_family = AF_INET;
 
499
    sock_in.sin_port = ntohs(static_cast<short>(port));
 
500
 
 
501
#if 0
 
502
    char ascip[INET_ADDRSTRLEN];
 
503
    inet_ntop(sock_in.sin_family, &sock_in.sin_addr.s_addr, ascip, INET_ADDRSTRLEN);
 
504
    log_debug(_("The IP address for this client socket is %s"), ascip);
 
505
#endif
 
506
 
 
507
    proto = ::getprotobyname("TCP");
 
508
 
 
509
    _sockfd = ::socket(PF_INET, SOCK_STREAM, proto->p_proto);
 
510
    if (_sockfd < 0)
 
511
        {
 
512
            log_error(_("unable to create socket: %s"), strerror(errno));
 
513
            _sockfd = -1;
 
514
            return false;
 
515
        }
 
516
 
 
517
    retries = 2;
 
518
    while (retries-- > 0) {
 
519
        // We use select to wait for the read file descriptor to be
 
520
        // active, which means there is a client waiting to connect.
 
521
        FD_ZERO(&fdset);
 
522
        FD_SET(_sockfd, &fdset);
 
523
 
 
524
        // Reset the timeout value, since select modifies it on return. To
 
525
        // block, set the timeout to zero.
 
526
        tval.tv_sec = 5;
 
527
        tval.tv_usec = 0;
 
528
 
 
529
        ret = ::select(_sockfd+1, &fdset, NULL, NULL, &tval);
 
530
 
 
531
        // If interupted by a system call, try again
 
532
        if (ret == -1 && errno == EINTR)
 
533
            {
 
534
                log_debug(_("The connect() socket for fd %d was interupted by a system call"),
 
535
                        _sockfd);
 
536
                continue;
 
537
            }
 
538
 
 
539
        if (ret == -1)
 
540
            {
 
541
                log_debug(_("The connect() socket for fd %d never was available for writing"),
 
542
                        _sockfd);
 
543
#ifdef HAVE_WINSOCK_H
 
544
                ::shutdown(_sockfd, 0); // FIXME: was SHUT_BOTH
 
545
#else
 
546
                ::shutdown(_sockfd, SHUT_RDWR);
 
547
#endif
 
548
                _sockfd = -1;
 
549
                return false;
 
550
            }
 
551
        if (ret == 0) {
 
552
            log_error(_("The connect() socket for fd %d timed out waiting to write"),
 
553
                      _sockfd);
 
554
            continue;
 
555
        }
 
556
 
 
557
        if (ret > 0) {
 
558
            ret = ::connect(_sockfd, reinterpret_cast<struct sockaddr *>(&sock_in), sizeof(sock_in));
 
559
            if (ret == 0) {
 
560
                char *ascip = ::inet_ntoa(sock_in.sin_addr);
 
561
//              char ascip[INET_ADDRSTRLEN];
 
562
//              inet_ntop(sock_in.sin_family, &sock_in.sin_addr.s_addr, ascip, INET_ADDRSTRLEN);
 
563
                log_debug(_("\tport %d at IP %s for fd %d"), port,
 
564
                        ascip, _sockfd);
 
565
                _connected = true;
 
566
                assert(_sockfd > 0);
 
567
                return true;
 
568
            }
 
569
            if (ret == -1) {
 
570
                log_error(_("The connect() socket for fd %d never was available for writing"),
 
571
                        _sockfd);
 
572
                _sockfd = -1;
 
573
                assert(!_connected);
 
574
                return false;
 
575
            }
 
576
        }
 
577
    }
 
578
    //  ::close(_sockfd);
 
579
    //  return false;
 
580
 
 
581
    printf("\tConnected at port %d on IP %s for fd #%d", port,
 
582
           ::inet_ntoa(sock_in.sin_addr), _sockfd);
 
583
 
 
584
#ifndef HAVE_WINSOCK_H
 
585
    fcntl(_sockfd, F_SETFL, O_NONBLOCK);
 
586
#endif
 
587
 
 
588
    _connected = true;
 
589
    _port = port;
 
590
    assert(_sockfd > 0);
 
591
    return true;
 
592
}
 
593
 
 
594
bool
 
595
Network::closeNet()
 
596
{
 
597
    GNASH_REPORT_FUNCTION;
 
598
 
 
599
    if ((_sockfd > 0) && (_connected)) {
 
600
        closeNet(_sockfd);
 
601
        _sockfd = 0;
 
602
        _connected = false;
 
603
    }
 
604
 
 
605
    return false;
 
606
}
 
607
 
 
608
bool
 
609
Network::closeNet(int sockfd)
 
610
{
 
611
    GNASH_REPORT_FUNCTION;
 
612
 
 
613
    int retries = 0;
 
614
 
 
615
    // If we can't close the socket, other processes must be
 
616
    // locked on it, so we wait a second, and try again. After a
 
617
    // few tries, we give up, cause there must be something
 
618
    // wrong.
 
619
 
 
620
    if (sockfd <= 0) {
 
621
        return true;
 
622
    }
 
623
 
 
624
    while (retries < 3) {
 
625
        if (sockfd) {
 
626
            // Shutdown the socket connection
 
627
#if 0
 
628
            if (shutdown(sockfd, SHUT_RDWR) < 0) {
 
629
                if (errno != ENOTCONN) {
 
630
                    cerr << "WARNING: Unable to shutdown socket for fd #"
 
631
                         << sockfd << strerror(errno) << endl;
 
632
                } else {
 
633
                    cerr << "The socket using fd #" << sockfd
 
634
                         << " has been shut down successfully." << endl;
 
635
                    return true;
 
636
                }
 
637
            }
 
638
#endif
 
639
            if (::close(sockfd) < 0) {
 
640
                // If we have a bad file descriptor, it's because
 
641
                // this got closed already, usually by another
 
642
                // thread being paranoid.
 
643
                if (errno != EBADF) {
 
644
                    log_error(_("Unable to close the socket for fd #%d: %s"),
 
645
                              sockfd, strerror(errno));
 
646
                }
 
647
#ifndef HAVE_WINSOCK_H
 
648
                sleep(1);
 
649
#endif
 
650
                retries++;
 
651
            } else {
 
652
                log_debug(_("Closed the socket on fd #%d for port %d"), sockfd, _port);
 
653
                return true;
 
654
            }
 
655
        }
 
656
    }
 
657
    return false;
 
658
}
 
659
// Description: Close an open socket connection.
 
660
bool
 
661
Network::closeConnection(void)
 
662
{
 
663
//    GNASH_REPORT_FUNCTION;
 
664
 
 
665
    closeConnection(_sockfd);
 
666
    _sockfd = 0;
 
667
    closeConnection(_listenfd);
 
668
    _listenfd = 0;
 
669
    _connected = false;
 
670
 
 
671
    return false;
 
672
}
 
673
 
 
674
bool
 
675
Network::closeConnection(int fd)
 
676
{
 
677
    GNASH_REPORT_FUNCTION;
 
678
 
 
679
    if (fd > 0) {
 
680
        ::close(fd);
 
681
        log_debug("%s: Closed fd #%d", __FUNCTION__, fd);
 
682
//        closeNet(fd);
 
683
    }
 
684
 
 
685
    return false;
 
686
}
 
687
 
 
688
amf::Buffer *
 
689
Network::readNet()
 
690
{
 
691
//    GNASH_REPORT_FUNCTION;
 
692
 
 
693
    amf::Buffer *buffer = new amf::Buffer;
 
694
    int nbytes = readNet(buffer);
 
695
    if (nbytes > 0) {
 
696
        buffer->resize(nbytes);
 
697
        return buffer;
 
698
    }
 
699
 
 
700
    return 0;
 
701
}
 
702
 
 
703
// Read from the connection
 
704
int
 
705
Network::readNet(amf::Buffer *buffer)
 
706
{
 
707
//    GNASH_REPORT_FUNCTION;
 
708
    return readNet(_sockfd, buffer->reference(), buffer->size(), _timeout);
 
709
}
 
710
 
 
711
int
 
712
Network::readNet(amf::Buffer *buffer, int timeout)
 
713
{
 
714
//    GNASH_REPORT_FUNCTION;
 
715
    return readNet(_sockfd, buffer->reference(), buffer->size(), timeout);
 
716
}
 
717
 
 
718
int
 
719
Network::readNet(byte_t *buffer, int nbytes)
 
720
{
 
721
//    GNASH_REPORT_FUNCTION;
 
722
    return readNet(_sockfd, buffer, nbytes, _timeout);
 
723
}
 
724
 
 
725
int
 
726
Network::readNet(byte_t *buffer, int nbytes, int timeout)
 
727
{
 
728
//    GNASH_REPORT_FUNCTION;
 
729
    return readNet(_sockfd, buffer, nbytes, timeout);
 
730
}
 
731
 
 
732
int
 
733
Network::readNet(int fd, byte_t *buffer, int nbytes)
 
734
{
 
735
//    GNASH_REPORT_FUNCTION;
 
736
    return readNet(fd, buffer, nbytes, _timeout);
 
737
}
 
738
 
 
739
int
 
740
Network::readNet(int fd, byte_t *buffer, int nbytes, int timeout)
 
741
{
 
742
//    GNASH_REPORT_FUNCTION;
 
743
 
 
744
    fd_set              fdset;
 
745
    int                 ret = -1;
 
746
    struct timeval      tval;
 
747
 
 
748
    if (_debug) {
 
749
        log_debug (_("Trying to read %d bytes from fd #%d"), nbytes, fd);
 
750
    }
 
751
#ifdef NET_TIMING
 
752
    if (_timing_debug)
 
753
    {
 
754
        gettimeofday(&tp, NULL);
 
755
        read_start_time = static_cast<double>(tp.tv_sec)
 
756
            + static_cast<double>(tp.tv_usec*1e-6);
 
757
    }
 
758
#endif
 
759
    if (fd > 2) {
 
760
        FD_ZERO(&fdset);
 
761
        FD_SET(fd, &fdset);
 
762
 
 
763
        if (timeout == 0) {
 
764
            ret = select(fd+1, &fdset, NULL, NULL, NULL);
 
765
        } else {        
 
766
            tval.tv_sec = timeout;
 
767
            tval.tv_usec = 0;
 
768
            ret = select(fd+1, &fdset, NULL, NULL, &tval);
 
769
        }
 
770
 
 
771
        // If interupted by a system call, try again
 
772
        if (ret == -1 && errno == EINTR) {
 
773
            log_error (_("The socket for fd %d was interupted by a system call"), fd);
 
774
        }
 
775
 
 
776
        if (ret == -1) {
 
777
            log_error (_("The socket for fd %d was never available for reading"), fd);
 
778
            return -1;
 
779
        }
 
780
 
 
781
        if (ret == 0) {
 
782
            if (_debug) {
 
783
                log_debug (_("The socket for fd %d timed out waiting to read"), fd);
 
784
            }
 
785
            return 0;
 
786
        }
 
787
 
 
788
        ret = read(fd, buffer, nbytes);
 
789
        // If we read zero bytes, the network is closed, as we returned from the select()
 
790
        if (ret == 0) {
 
791
            return -1;
 
792
        }
 
793
        
 
794
        if (_debug) {
 
795
            log_debug (_("read %d bytes from fd %d from port %d"), ret, fd, _port);
 
796
        }
 
797
#if 0
 
798
        if (ret) {
 
799
            log_debug (_("%s: Read packet data from fd %d (%d bytes): \n%s"),
 
800
                       __FUNCTION__, fd, ret, hexify(buffer, ret, true));
 
801
        }
 
802
#endif    
 
803
    }
 
804
 
 
805
    return ret;
 
806
 
 
807
}
 
808
 
 
809
// Write to the connection
 
810
int
 
811
Network::writeNet(amf::Buffer *buffer)
 
812
{
 
813
    return writeNet(buffer->reference(), buffer->size());
 
814
};
 
815
 
 
816
int
 
817
Network::writeNet(const std::string& buffer)
 
818
{
 
819
    return writeNet(reinterpret_cast<const byte_t *>(buffer.c_str()), buffer.size());
 
820
}
 
821
 
 
822
int
 
823
Network::writeNet(const byte_t *buffer, int nbytes)
 
824
{
 
825
    return writeNet(_sockfd, buffer, nbytes, _timeout);
 
826
}
 
827
 
 
828
// int
 
829
// Network::writeNet(const byte_t *buffer, int nbytes)
 
830
// {
 
831
//     return writeNet(_sockfd, buffer, nbytes, _timeout);
 
832
// }
 
833
 
 
834
// int
 
835
// Network::writeNet(int fd, const byte_t *buffer)
 
836
// {
 
837
//     return writeNet(fd, buffer, strlen(buffer), _timeout);
 
838
// }
 
839
 
 
840
int
 
841
Network::writeNet(int fd, const byte_t *buffer, int nbytes)
 
842
{
 
843
    return writeNet(fd, buffer, nbytes, _timeout);
 
844
}
 
845
 
 
846
int
 
847
Network::writeNet(int fd, const byte_t *buffer, int nbytes, int timeout)
 
848
{
 
849
    fd_set              fdset;
 
850
    int                 ret = -1;
 
851
    struct timeval      tval;
 
852
 
 
853
    // We need a writable, and not const point for byte arithmetic.
 
854
    byte_t *bufptr = const_cast<byte_t *>(buffer);
 
855
 
 
856
#ifdef NET_TIMING
 
857
    // If we are debugging the tcp/ip timings, get the initial time.
 
858
    if (_timing_debug)
 
859
    {
 
860
        gettimeofday(&starttime, 0);
 
861
    }
 
862
#endif
 
863
    if (fd > 2) {
 
864
        FD_ZERO(&fdset);
 
865
        FD_SET(fd, &fdset);
 
866
 
 
867
        // Reset the timeout value, since select modifies it on return
 
868
        if (timeout <= 0) {
 
869
            timeout = 5;
 
870
        }
 
871
        tval.tv_sec = timeout;
 
872
        tval.tv_usec = 0;
 
873
        ret = select(fd+1, NULL, &fdset, NULL, &tval);
 
874
 
 
875
        // If interupted by a system call, try again
 
876
        if (ret == -1 && errno == EINTR) {
 
877
            log_error (_("The socket for fd %d was interupted by a system call"), fd);
 
878
        }
 
879
 
 
880
        if (ret == -1) {
 
881
            log_error (_("The socket for fd %d was never available for writing"), fd);
 
882
        }
 
883
 
 
884
        if (ret == 0) {
 
885
            log_debug (_("The socket for fd %d timed out waiting to write"), fd);
 
886
            return 0;
 
887
        }
 
888
 
 
889
        ret = write(fd, bufptr, nbytes);
 
890
 
 
891
        if (ret == 0) {
 
892
            log_error (_("Wrote zero out of %d bytes to fd %d: %s"), 
 
893
                nbytes, fd, strerror(errno));
 
894
            return ret;
 
895
        }
 
896
        if (ret < 0) {
 
897
            log_error (_("Couldn't write %d bytes to fd %d: %s"), 
 
898
                nbytes, fd, strerror(errno));
 
899
            return ret;
 
900
        }
 
901
        if (ret > 0) {
 
902
            bufptr += ret;
 
903
            if (ret != nbytes) {
 
904
                if (_debug) {
 
905
                    log_debug (_("wrote %d bytes to fd %d, expected %d"),
 
906
                               ret, fd, nbytes);
 
907
                }
 
908
            } else {
 
909
                if (_debug) {
 
910
                    log_debug (_("wrote %d bytes to fd %d for port %d"),
 
911
                               ret, fd, _port);
 
912
                }
 
913
//                return ret;
 
914
            }
 
915
        }
 
916
#if 0
 
917
        if (ret) {
 
918
            log_debug (_("%s: Wrote packet data to fd %d: \n%s"),
 
919
                       __FUNCTION__, fd, hexify(buffer, ret, true));
 
920
        }
 
921
#endif    
 
922
    }
 
923
 
 
924
#ifdef NET_TIMING
 
925
    if (_timing_debug)
 
926
    {
 
927
        gettimeofday(&endtime, 0);
 
928
 
 
929
        if ((endtime.tv_sec - starttime.tv_sec) &&
 
930
            endtime.tv_usec - starttime.tv_usec)
 
931
        {
 
932
            log_debug (_("took %d usec to write (%d bytes)"),
 
933
                endtime.tv_usec - starttime.tv_usec, bytes_written);
 
934
        }
 
935
    }
 
936
#endif
 
937
 
 
938
 
 
939
    return ret;
 
940
}
 
941
 
 
942
void
 
943
Network::toggleDebug(bool val)
 
944
{
 
945
    // Turn on our own debugging
 
946
    _debug = val;
 
947
 
 
948
    // Turn on debugging for the utility methods
 
949
                // recursive on all control paths,
 
950
                // function will cause runtime stack overflow
 
951
 
 
952
                // toggleDebug(true);
 
953
}
 
954
 
 
955
 
 
956
} // end of gnash namespace
 
957
 
 
958
// Local Variables:
 
959
// mode: C++
 
960
// indent-tabs-mode: t
 
961
// End: