Merge branch 'master' into release_0_8_9
[gnash.git] / cygnal / libnet / network.cpp
blobf0b0e8e84735f1385eed84e2f0947e1b719490f0
1 //
2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
3 // 2011 Free Software Foundation, Inc
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 //xs
20 #ifdef HAVE_CONFIG_H
21 #include "gnashconfig.h"
22 #endif
24 #include <boost/thread/mutex.hpp>
25 #include <boost/shared_ptr.hpp>
26 #include <vector>
28 #include "utility.h"
29 #include "log.h"
30 #include "network.h"
32 #include <sys/types.h>
33 #include <cstring>
34 #include <cstdio>
35 #include <cerrno>
36 #include <fcntl.h>
37 #if defined(HAVE_WINSOCK_H) && !defined(__OS2__)
38 # include <winsock2.h>
39 # include <windows.h>
40 # include <sys/stat.h>
41 # include <io.h>
42 # include <ws2tcpip.h>
43 #else
44 # include <sys/ioctl.h>
45 # include <sys/time.h>
46 # include <unistd.h>
47 # include <sys/select.h>
48 # include <netinet/in.h>
49 # include <arpa/inet.h>
50 # include <sys/socket.h>
51 # include <sys/un.h>
52 # include <netdb.h>
53 # include <sys/param.h>
54 # include <sys/select.h>
55 #include <csignal>
57 // This is for non-standard signal functions such as sigemptyset.
58 #include <signal.h>
60 #ifdef HAVE_POLL_H
61 # include <poll.h>
62 #else
63 # ifdef HAVE_EPOLL_H
64 # include <epoll.h>
65 # endif
66 #endif
67 #endif
69 #include "buffer.h"
70 #include "GnashException.h"
72 #ifndef MAXHOSTNAMELEN
73 #define MAXHOSTNAMELEN 256
74 #endif
76 #ifndef FIONREAD
77 #define FIONREAD 0
78 #endif
80 using std::string;
81 using std::vector;
83 /// \namespace gnash
84 /// This is the main namespace for Gnash and it's libraries.
85 namespace gnash {
87 static const char *DEFAULTPROTO = "tcp";
88 static const short DEFAULTPORT = RTMP_PORT;
90 #ifndef INADDR_NONE
91 #define INADDR_NONE 0xffffffff
92 #endif
94 static void cntrlc_handler(int sig);
95 // this is set when we get a signal during a pselect() or ppoll()
96 static int sig_number = 0;
98 Network::Network()
100 _ipaddr(INADDR_ANY),
101 _sockfd(0),
102 _listenfd(0),
103 _port(0),
104 _connected(false),
105 _debug(false),
106 _timeout(0)
108 // GNASH_REPORT_FUNCTION;
109 #if defined(HAVE_WINSOCK_H) && !defined(__OS2__)
110 WORD wVersionRequested;
111 WSADATA wsaData;
112 wVersionRequested = MAKEWORD(1, 1); // Windows Sockets 1.1
113 if (WSAStartup( wVersionRequested, &wsaData ) != 0) {
114 log_error(_("Could not find a usable WinSock DLL"));
115 exit(EXIT_FAILURE);
117 #endif
121 Network::~Network()
123 // GNASH_REPORT_FUNCTION;
124 #if defined(HAVE_WINSOCK_H) && !defined(__OS2__)
125 WSACleanup();
126 #else
127 closeNet();
128 #endif
131 // Description: Create a tcp/ip network server. This creates a server
132 // that listens for incoming socket connections. This
133 // supports IP aliasing on the host, and will sequntially
134 // look for IP address to bind this port to.
136 Network::createServer(void)
138 // GNASH_REPORT_FUNCTION;
140 short port;
142 if (_port) {
143 port = _port;
144 } else {
145 port = DEFAULTPORT;
147 return createServer(port);
150 // FIXME: Should also support IPv6 (AF_INET6)
152 Network::createServer(short port)
154 // GNASH_REPORT_FUNCTION;
156 struct protoent *ppe;
157 struct sockaddr_in sock_in;
158 int on, type;
159 int retries = 0;
161 if (_listenfd >= 2) {
162 log_debug("already connected to port %hd", port);
163 return _listenfd;
166 const struct hostent *host = gethostbyname("localhost");
167 struct in_addr *thisaddr = reinterpret_cast<struct in_addr *>(host->h_addr_list[0]);
168 _ipaddr = thisaddr->s_addr;
169 memset(&sock_in, 0, sizeof(sock_in));
171 #if 0
172 // Accept incoming connections only on our IP number
173 sock_in.sin_addr.s_addr = thisaddr->s_addr;
174 #else
175 // Accept incoming connections on any IP number
176 sock_in.sin_addr.s_addr = INADDR_ANY;
177 #endif
179 _ipaddr = sock_in.sin_addr.s_addr;
180 sock_in.sin_family = AF_INET;
181 sock_in.sin_port = htons(port);
183 if ((ppe = getprotobyname(DEFAULTPROTO)) == 0) {
184 log_error(_("unable to get protocol entry for %s"),
185 DEFAULTPROTO);
186 return -1;
189 // set protocol type
190 if ( strcmp(DEFAULTPROTO, "udp") == 0) {
191 type = SOCK_DGRAM;
192 } else {
193 type = SOCK_STREAM;
196 // Get a file descriptor for this socket connection
197 _listenfd = socket(PF_INET, type, ppe->p_proto);
199 // error, wasn't able to create a socket
200 if (_listenfd < 0) {
201 log_error(_("unable to create socket: %s"), strerror(errno));
202 return -1;
205 on = 1;
206 if (setsockopt(_listenfd, SOL_SOCKET, SO_REUSEADDR,
207 (char *)&on, sizeof(on)) < 0) {
208 log_error(_("setsockopt SO_REUSEADDR failed"));
209 return -1;
212 retries = 0;
214 // in_addr_t nodeaddr;
215 // nodeaddr = inet_lnaof(*thisaddr);
216 while (retries < 5) {
217 if (bind(_listenfd, reinterpret_cast<struct sockaddr *>(&sock_in),
218 sizeof(sock_in)) == -1) {
219 log_error(_("unable to bind to port %hd: %s"),
220 port, strerror(errno));
221 // inet_ntoa(sock_in.sin_addr), strerror(errno));
222 retries++;
225 if (_debug) {
226 // char ascip[INET_ADDRSTRLEN];
227 // inet_ntop(sock_in.sin_family, &_ipaddr, ascip, INET_ADDRSTRLEN);
228 char *ascip = ::inet_ntoa(sock_in.sin_addr);
229 log_debug(_("Server bound to service on %s, port %hd, using fd #%d"),
230 ascip, ntohs(sock_in.sin_port),
231 _listenfd);
234 if (type == SOCK_STREAM && listen(_listenfd, 5) < 0) {
235 log_error(_("unable to listen on port: %hd: %s "),
236 port, strerror(errno));
237 return -1;
240 // We have a socket created
241 _port = port;
242 return _listenfd;
244 return -1;
247 // Description: Accept a new network connection for the port we have
248 // created a server for.
249 // The default is to block.
251 Network::newConnection(void)
253 // GNASH_REPORT_FUNCTION;
255 return newConnection(true, _listenfd);
259 Network::newConnection(int fd)
261 // GNASH_REPORT_FUNCTION;
263 return newConnection(true, fd);
267 Network::newConnection(bool block)
269 // GNASH_REPORT_FUNCTION;
271 return newConnection(block, _listenfd);
275 Network::newConnection(bool block, int fd)
277 // GNASH_REPORT_FUNCTION;
279 struct sockaddr newfsin;
280 socklen_t alen;
281 int ret;
282 fd_set fdset;
283 int retries = 3;
285 alen = sizeof(struct sockaddr_in);
287 if (fd <= 2) {
288 return -1;
290 if (_debug) {
291 log_debug(_("Waiting to accept net traffic on fd #%d for port %d"), fd, _port);
294 #ifdef HAVE_PSELECT
295 struct timespec tval;
296 sigset_t sigset, blockset, pending;
297 sigemptyset(&blockset);
298 // sigaddset(&blockset, SIGINT); /* Block SIGINT */
299 sigaddset(&blockset, SIGPIPE); /* Block SIGPIPE */
300 sigprocmask(SIG_BLOCK, &blockset, &sigset);
301 #else
302 struct timeval tval;
303 #endif
305 while (retries--) {
306 // We use select to wait for the read file descriptor to be
307 // active, which means there is a client waiting to connect.
308 FD_ZERO(&fdset);
309 // also return on any input from stdin
310 // if (_console) {
311 // FD_SET(fileno(stdin), &fdset);
312 // }
313 FD_SET(fd, &fdset);
315 // Reset the timeout value, since select modifies it on return. To
316 // block, set the timeout to zero.
317 #ifdef HAVE_PSELECT
318 tval.tv_sec = _timeout;
319 tval.tv_nsec = 0;
320 if (block) {
321 ret = pselect(fd+1, &fdset, NULL, NULL, NULL, &blockset);
322 } else {
323 ret = pselect(fd+1, &fdset, NULL, NULL, &tval, &blockset);
325 if (sig_number) {
326 log_debug("Have a SIGINT interupt waiting!");
328 sigpending(&pending);
329 if (sigismember(&pending, SIGINT)) {
330 log_debug("Have a pending SIGINT interupt waiting!");
331 int sig;
332 sigwait(&blockset, &sig);
334 if (sigismember(&pending, SIGPIPE)) {
335 log_debug("Have a pending SIGPIPE interupt waiting!");
336 int sig;
337 sigwait(&blockset, &sig);
339 #else
340 tval.tv_sec = 1;
341 tval.tv_usec = 0;
342 if (block) {
343 ret = select(fd+1, &fdset, NULL, NULL, NULL);
344 } else {
345 ret = select(fd+1, &fdset, NULL, NULL, &tval);
347 #endif
349 if (FD_ISSET(0, &fdset)) {
350 if (_debug) {
351 log_debug(_("There is a new network connection request."));
353 return 1;
356 // If interrupted by a system call, try again
357 if (ret == -1 && errno == EINTR) {
358 log_debug(_("The accept() socket for fd #%d was interrupted by a system call"), fd);
361 if (ret == -1) {
362 log_debug(_("The accept() socket for fd #%d never was available"), fd);
363 return -1;
366 if (ret == 0) {
367 if (_debug) {
368 log_debug(_("The accept() socket for fd #%d timed out waitingfor data"), fd);
369 return 0;
375 #ifndef HAVE_WINSOCK_H
376 fcntl(_listenfd, F_SETFL, O_NONBLOCK); // Don't let accept() block
377 #endif
378 _sockfd = accept(fd, &newfsin, &alen);
380 if (_sockfd < 0) {
381 log_error(_("unable to accept: %s"), strerror(errno));
382 return -1;
385 if (_debug) {
386 log_debug(_("Accepting tcp/ip connection on fd #%d for port %d"), _sockfd, _port);
389 return _sockfd;
392 #if defined(_WIN32) || defined(__amigaos4__)
393 /* from sys/socket.h */
394 typedef unsigned short sa_family_t;
396 /* from sys/un.h */
397 #define UNIX_PATH_MAX 108
399 struct sockaddr_un {
400 sa_family_t sun_family; /* AF_UNIX */
401 char sun_path[UNIX_PATH_MAX]; /* pathname */
404 #endif /* _WIN32 */
406 // Connect to a named pipe
407 bool
408 Network::connectSocket(const string &sockname)
410 // GNASH_REPORT_FUNCTION;
412 struct sockaddr_un addr;
413 fd_set fdset;
414 struct timeval tval;
415 int ret;
416 int retries;
418 addr.sun_family = AF_UNIX;
419 // socket names must be 108 bytes or less as specifiec in sys/un.h.
420 strncpy(addr.sun_path, sockname.c_str(), 100);
422 _sockfd = ::socket(AF_UNIX, SOCK_STREAM, 0);
423 if (_sockfd < 0) {
424 log_error(_("unable to create socket: %s"), strerror(errno));
425 _sockfd = -1;
426 return false;
429 retries = 2;
430 while (retries-- > 0) {
431 // We use select to wait for the read file descriptor to be
432 // active, which means there is a client waiting to connect.
433 FD_ZERO(&fdset);
434 FD_SET(_sockfd, &fdset);
436 // Reset the timeout value, since select modifies it on return. To
437 // block, set the timeout to zero.
438 tval.tv_sec = 5;
439 tval.tv_usec = 0;
441 ret = ::select(_sockfd+1, &fdset, NULL, NULL, &tval);
443 // If interrupted by a system call, try again
444 if (ret == -1 && errno == EINTR) {
445 log_debug(_("The connect() socket for fd %d was interrupted by a system call"),
446 _sockfd);
447 continue;
450 if (ret == -1) {
451 log_debug(_("The connect() socket for fd %d never was available for writing"),
452 _sockfd);
453 #ifdef HAVE_WINSOCK_H
454 ::shutdown(_sockfd, 0); // FIXME: was SHUT_BOTH
455 #else
456 ::shutdown(_sockfd, SHUT_RDWR);
457 #endif
458 _sockfd = -1;
459 return false;
461 if (ret == 0) {
462 log_error(_("The connect() socket for fd %d timed out waiting to write"),
463 _sockfd);
464 continue;
467 if (ret > 0) {
468 ret = ::connect(_sockfd, reinterpret_cast<struct sockaddr *>(&addr), sizeof(addr));
469 if (ret == 0) {
470 log_debug(_("\tsocket name %s for fd %d"), sockname, _sockfd);
471 _connected = true;
472 assert(_sockfd > 0);
473 return true;
475 if (ret == -1) {
476 log_error(_("The connect() socket for fd %d never was available for writing"),
477 _sockfd);
478 _sockfd = -1;
479 assert(!_connected);
480 return false;
486 #ifndef HAVE_WINSOCK_H
487 fcntl(_sockfd, F_SETFL, O_NONBLOCK);
488 #endif
490 _connected = true;
491 assert(_sockfd > 0);
492 return true;
495 // Create a client connection to a tcp/ip based service
496 bool
497 Network::createClient(void)
499 // GNASH_REPORT_FUNCTION;
501 short port;
503 if (_port) {
504 port = _port;
505 } else {
506 port = RTMP_PORT;
508 return createClient("localhost", port);
510 bool
511 Network::createClient(short /* port */)
513 // GNASH_REPORT_FUNCTION;
515 return false;
518 bool
519 Network::createClient(const string &hostname)
521 // GNASH_REPORT_FUNCTION;
523 short port;
525 if (_port) {
526 port = _port;
527 } else {
528 port = RTMP_PORT;
530 return createClient(hostname, port);
533 bool
534 Network::createClient(const string &hostname, short port)
536 // GNASH_REPORT_FUNCTION;
538 struct sockaddr_in sock_in;
539 fd_set fdset;
540 struct timeval tval;
541 int ret;
542 int retries;
543 char thishostname[MAXHOSTNAMELEN];
544 struct protoent *proto;
546 // assert( ! connected() );
547 if (connected()) {
548 return true;
551 _port = port;
552 log_debug(_("%s: to host %s at port %d"), __FUNCTION__, hostname, port);
554 memset(&sock_in, 0, sizeof(struct sockaddr_in));
555 memset(&thishostname, 0, MAXHOSTNAMELEN);
556 if (hostname.size() == 0) {
557 if (gethostname(thishostname, MAXHOSTNAMELEN) == 0) {
558 log_debug(_("The hostname for this machine is %s"), thishostname);
559 } else {
560 log_debug(_("Couldn't get the hostname for this machine"));
561 return false;
565 const struct hostent *hent = ::gethostbyname(hostname.c_str());
566 if (hent > 0) {
567 ::memcpy(&sock_in.sin_addr, hent->h_addr, hent->h_length);
569 sock_in.sin_family = AF_INET;
570 sock_in.sin_port = ntohs(static_cast<short>(port));
572 #if 0
573 char ascip[INET_ADDRSTRLEN];
574 inet_ntop(sock_in.sin_family, &sock_in.sin_addr.s_addr, ascip, INET_ADDRSTRLEN);
575 log_debug(_("The IP address for this client socket is %s"), ascip);
576 #endif
578 proto = ::getprotobyname("TCP");
580 _sockfd = ::socket(PF_INET, SOCK_STREAM, proto->p_proto);
581 if (_sockfd < 0) {
582 log_error(_("unable to create socket: %s"), strerror(errno));
583 _sockfd = -1;
584 return false;
587 retries = 2;
588 while (retries-- > 0) {
589 // We use select to wait for the read file descriptor to be
590 // active, which means there is a client waiting to connect.
591 FD_ZERO(&fdset);
592 FD_SET(_sockfd, &fdset);
594 // Reset the timeout value, since select modifies it on return. To
595 // block, set the timeout to zero.
596 tval.tv_sec = 5;
597 tval.tv_usec = 0;
599 ret = ::select(_sockfd+1, &fdset, NULL, NULL, &tval);
601 // If interrupted by a system call, try again
602 if (ret == -1 && errno == EINTR) {
603 log_debug(_("The connect() socket for fd %d was interrupted "
604 "by a system call"), _sockfd);
605 continue;
608 if (ret == -1) {
609 log_debug(_("The connect() socket for fd %d never was "
610 "available for writing"), _sockfd);
611 #ifdef HAVE_WINSOCK_H
612 ::shutdown(_sockfd, 0); // FIXME: was SHUT_BOTH
613 #else
614 ::shutdown(_sockfd, SHUT_RDWR);
615 #endif
616 ::close(_sockfd);
617 _sockfd = -1;
618 return false;
621 if (ret == 0) {
622 #ifdef HAVE_WINSOCK_H
623 ::shutdown(_sockfd, 0); // FIXME: was SHUT_BOTH
624 #else
625 ::shutdown(_sockfd, SHUT_RDWR);
626 #endif
627 log_error(_("The connect() socket for fd %d timed out waiting "
628 "to write"), _sockfd);
629 ::close(_sockfd);
630 continue;
633 if (ret > 0) {
634 ret = ::connect(_sockfd,
635 reinterpret_cast<struct sockaddr *>(&sock_in),
636 sizeof(sock_in));
638 if (ret == 0) {
639 char *ascip = ::inet_ntoa(sock_in.sin_addr);
640 // char ascip[INET_ADDRSTRLEN];
641 // inet_ntop(sock_in.sin_family, &sock_in.sin_addr.s_addr, ascip, INET_ADDRSTRLEN);
642 log_debug(_("\tport %d at IP %s for fd %d"), port,
643 ascip, _sockfd);
644 _connected = true;
645 assert(_sockfd > 0);
646 return true;
648 if (ret == -1) {
649 log_error(_("The connect() socket for fd %d never was "
650 "available for writing"), _sockfd);
651 #ifdef HAVE_WINSOCK_H
652 ::shutdown(_sockfd, 0); // FIXME: was SHUT_BOTH
653 #else
654 ::shutdown(_sockfd, SHUT_RDWR);
655 #endif
656 ::close(_sockfd);
657 _sockfd = -1;
658 assert(!_connected);
659 return false;
663 // ::close(_sockfd);
664 // return false;
666 printf("\tConnected at port %d on IP %s for fd #%d", port,
667 ::inet_ntoa(sock_in.sin_addr), _sockfd);
669 #ifndef HAVE_WINSOCK_H
670 fcntl(_sockfd, F_SETFL, O_NONBLOCK);
671 #endif
673 _connected = true;
674 _port = port;
675 assert(_sockfd > 0);
676 return true;
679 bool
680 Network::closeNet()
682 // GNASH_REPORT_FUNCTION;
684 if ((_sockfd > 0) && (_connected)) {
685 closeNet(_sockfd);
686 _sockfd = 0;
687 _connected = false;
690 return false;
693 bool
694 Network::closeNet(int sockfd)
696 // GNASH_REPORT_FUNCTION;
698 int retries = 0;
700 // If we can't close the socket, other processes must be
701 // locked on it, so we wait a second, and try again. After a
702 // few tries, we give up, cause there must be something
703 // wrong.
705 if (sockfd <= 0) {
706 return true;
709 while (retries < 3) {
710 if (sockfd) {
711 // Shutdown the socket connection
712 #if 0
713 if (shutdown(sockfd, SHUT_RDWR) < 0) {
714 if (errno != ENOTCONN) {
715 cerr << "WARNING: Unable to shutdown socket for fd #"
716 << sockfd << strerror(errno) << endl;
717 } else {
718 cerr << "The socket using fd #" << sockfd
719 << " has been shut down successfully." << endl;
720 return true;
723 #endif
724 if (::close(sockfd) < 0) {
725 // If we have a bad file descriptor, it's because
726 // this got closed already, usually by another
727 // thread being paranoid.
728 if (errno != EBADF) {
729 log_error(_("Unable to close the socket for fd #%d: %s"),
730 sockfd, strerror(errno));
732 #ifndef HAVE_WINSOCK_H
733 sleep(1);
734 #endif
735 retries++;
736 } else {
737 log_debug(_("Closed the socket on fd #%d"), sockfd);
738 return true;
742 return false;
744 // Description: Close an open socket connection.
745 bool
746 Network::closeConnection(void)
748 // GNASH_REPORT_FUNCTION;
750 closeConnection(_sockfd);
751 _sockfd = 0;
752 closeConnection(_listenfd);
753 _listenfd = 0;
754 _connected = false;
756 return false;
759 bool
760 Network::closeConnection(int fd)
762 // GNASH_REPORT_FUNCTION;
764 if (fd > 0) {
765 ::close(fd);
766 log_debug("%s: Closed fd #%d", __FUNCTION__, fd);
767 // closeNet(fd);
770 return false;
773 boost::shared_ptr<cygnal::Buffer>
774 Network::readNet()
776 // GNASH_REPORT_FUNCTION;
777 boost::shared_ptr<cygnal::Buffer> buffer(new cygnal::Buffer);
778 int ret = readNet(*buffer);
779 if (ret > 0) {
780 buffer->resize(ret);
782 return buffer;
785 // Read from the connection
787 Network::readNet(int fd, cygnal::Buffer &buffer)
789 // GNASH_REPORT_FUNCTION;
790 int ret = readNet(fd, buffer.reference(), buffer.size(), _timeout);
791 if (ret > 0) {
792 buffer.resize(ret);
795 return ret;
799 Network::readNet(int fd, cygnal::Buffer *buffer)
801 // GNASH_REPORT_FUNCTION;
802 int ret = readNet(fd, buffer->reference(), buffer->size(), _timeout);
803 if (ret > 0) {
804 buffer->setSeekPointer(buffer->reference() + ret);
807 return ret;
811 Network::readNet(cygnal::Buffer &buffer)
813 // GNASH_REPORT_FUNCTION;
814 int ret = readNet(_sockfd, buffer, _timeout);
816 return ret;
820 Network::readNet(cygnal::Buffer &buffer, int timeout)
822 // GNASH_REPORT_FUNCTION;
823 int ret = readNet(_sockfd, buffer.reference(), buffer.size(), timeout);
824 if (ret > 0) {
825 buffer.resize(ret); // FIXME: why does this corrupt
828 return ret;
832 Network::readNet(int fd, cygnal::Buffer &buffer, int timeout)
834 // GNASH_REPORT_FUNCTION;
835 int ret = readNet(fd, buffer.reference(), buffer.size(), timeout);
836 buffer.setSeekPointer(ret);
837 #if 0
838 if (ret > 0) {
839 buffer.resize(ret); // FIXME: why does this corrupt
841 #endif
843 return ret;
847 Network::readNet(byte_t *data, int nbytes)
849 // GNASH_REPORT_FUNCTION;
850 return readNet(_sockfd, data, nbytes, _timeout);
854 Network::readNet(byte_t *data, int nbytes, int timeout)
856 // GNASH_REPORT_FUNCTION;
857 return readNet(_sockfd, data, nbytes, timeout);
861 Network::readNet(int fd, byte_t *data, int nbytes)
863 // GNASH_REPORT_FUNCTION;
864 return readNet(fd, data, nbytes, _timeout);
868 Network::readNet(int fd, byte_t *buffer, int nbytes, int timeout)
870 // GNASH_REPORT_FUNCTION;
872 fd_set fdset;
873 int ret = -1;
875 // boost::mutex::scoped_lock lock(_net_mutex);
877 if (_debug) {
878 log_debug (_("Trying to read %d bytes from fd #%d"), nbytes, fd);
880 #ifdef NET_TIMING
881 if (_timing_debug)
883 gettimeofday(&tp, NULL);
884 read_start_time = static_cast<double>(tp.tv_sec)
885 + static_cast<double>(tp.tv_usec*1e-6);
887 #endif
888 if (fd > 2) {
889 FD_ZERO(&fdset);
890 FD_SET(fd, &fdset);
892 #ifdef HAVE_PSELECT
893 struct timespec tval;
894 sigset_t pending, blockset;
895 sigemptyset(&blockset);
896 // sigaddset(&blockset, SIGINT); /* Block SIGINT */
897 // sigaddset(&blockset, SIGPIPE); /* Block SIGPIPE */
898 sigprocmask(SIG_BLOCK, &blockset, NULL);
900 // Trap ^C (SIGINT) so we can kill all the threads
901 // struct sigaction act;
902 // act.sa_handler = cntrlc_handler;
903 // act.sa_flags = 0;
904 // sigemptyset(&act.sa_mask);
905 // sigaction (SIGINT, &act, NULL);
906 #else
907 struct timeval tval;
908 #endif
909 if (timeout == 0) {
910 #ifdef HAVE_PSELECT
911 ret = pselect(fd+1, &fdset, NULL, NULL, NULL, &blockset);
912 #else
913 ret = select(fd+1, &fdset, NULL, NULL, NULL);
914 #endif
915 } else {
916 #ifdef HAVE_PSELECT
917 tval.tv_sec = timeout;
918 tval.tv_nsec = 0;
919 ret = pselect(fd+1, &fdset, NULL, NULL, &tval, &blockset);
920 sigpending(&pending);
921 if (sigismember(&pending, SIGINT)) {
922 log_debug("Have a pending SIGINT interupt waiting!");
923 int sig;
924 sigwait(&blockset, &sig);
925 cntrlc_handler(SIGINT);
927 if (sigismember(&pending, SIGPIPE)) {
928 log_debug("Have a pending SIGPIPE interupt waiting!");
929 int sig;
930 sigwait(&blockset, &sig);
931 cntrlc_handler(SIGINT);
933 #else
934 tval.tv_sec = timeout;
935 tval.tv_usec = 0;
936 ret = select(fd+1, &fdset, NULL, NULL, &tval);
937 #endif
940 // If interrupted by a system call, try again
941 if (ret == -1 && errno == EINTR) {
942 log_error (_("The socket for fd #%d was interrupted by a system call"), fd);
945 if (ret == -1) {
946 log_error (_("The socket for fd #%d was never available for reading"), fd);
947 return -1;
950 if (ret == 0) {
951 if (_debug) {
952 log_debug (_("The socket for #fd %d timed out waiting to read"), fd);
954 return 0;
957 #ifdef USE_SSL
958 if (_ssl) {
959 ret = _ssl->sslRead(buffer, nbytes);
960 } else {
961 ret = read(fd, buffer, nbytes);
963 #else
964 ret = read(fd, buffer, nbytes);
965 #endif
967 // If we read zero bytes, the network may be closed, as we returned from the select()
968 if (ret == -1) {
969 log_error (_("The socket for fd #%d was never available for reading data"), fd);
970 return -1;
973 if (ret == 0) {
974 if (_debug) {
975 log_debug (_("The socket for #fd %d timed out waiting to read data"), fd);
977 return 0;
980 if (_debug) {
981 log_debug (_("read %d bytes from fd #%d from port %d"), ret, fd, _port);
983 #if 0
984 if (ret) {
985 log_debug (_("%s: Read packet data from fd #%d (%d bytes): \n%s"),
986 __FUNCTION__, fd, ret, hexify(buffer, ret, true));
988 #endif
991 return ret;
995 // Write to the connection
997 Network::writeNet(cygnal::Buffer *buffer)
999 // GNASH_REPORT_FUNCTION;
1000 return writeNet(buffer->reference(), buffer->allocated());
1004 Network::writeNet(int fd, cygnal::Buffer *buffer)
1006 // GNASH_REPORT_FUNCTION;
1007 return writeNet(fd, buffer->reference(), buffer->allocated());
1010 // Write to the connection
1012 Network::writeNet(cygnal::Buffer &buffer)
1014 // GNASH_REPORT_FUNCTION;
1015 return writeNet(buffer.reference(), buffer.allocated());
1018 // Write to the connection
1020 Network::writeNet(int fd, cygnal::Buffer &buffer)
1022 // GNASH_REPORT_FUNCTION;
1023 return writeNet(fd, buffer.reference(), buffer.allocated());
1027 Network::writeNet(const std::string& data)
1029 // GNASH_REPORT_FUNCTION;
1030 return writeNet(reinterpret_cast<const byte_t *>(data.c_str()), data.size());
1034 Network::writeNet(const byte_t *data, int nbytes)
1036 // GNASH_REPORT_FUNCTION;
1037 return writeNet(_sockfd, data, nbytes, _timeout);
1040 // int
1041 // Network::writeNet(const byte_t *buffer, int nbytes)
1042 // {
1043 // return writeNet(_sockfd, buffer, nbytes, _timeout);
1044 // }
1046 // int
1047 // Network::writeNet(int fd, const byte_t *buffer)
1048 // {
1049 // return writeNet(fd, buffer, strlen(buffer), _timeout);
1050 // }
1053 Network::writeNet(int fd, const byte_t *data, int nbytes)
1055 // GNASH_REPORT_FUNCTION;
1056 return writeNet(fd, data, nbytes, _timeout);
1060 Network::writeNet(int fd, const byte_t *buffer, int nbytes, int timeout)
1062 // GNASH_REPORT_FUNCTION;
1064 fd_set fdset;
1065 int ret = -1;
1067 boost::mutex::scoped_lock lock(_net_mutex);
1069 // We need a writable, and not const point for byte arithmetic.
1070 byte_t *bufptr = const_cast<byte_t *>(buffer);
1072 #ifdef NET_TIMING
1073 // If we are debugging the tcp/ip timings, get the initial time.
1074 if (_timing_debug)
1076 gettimeofday(&starttime, 0);
1078 #endif
1079 if (fd > 2) {
1080 FD_ZERO(&fdset);
1081 FD_SET(fd, &fdset);
1083 #ifdef HAVE_PSELECT
1084 struct timespec tval;
1085 sigset_t pending, blockset; //, emptyset;
1086 sigemptyset(&blockset);
1087 // sigaddset(&blockset, SIGINT); /* Block SIGINT */
1088 sigaddset(&blockset, SIGPIPE);
1089 sigprocmask(SIG_BLOCK, &blockset, NULL);
1090 #else
1091 struct timeval tval;
1092 #endif
1093 // Reset the timeout value, since select modifies it on return
1094 if (timeout <= 0) {
1095 timeout = 5;
1097 #ifdef HAVE_PSELECT
1098 tval.tv_sec = timeout;
1099 tval.tv_nsec = 0;
1100 ret = pselect(fd+1, NULL, &fdset, NULL, &tval, &blockset);
1101 sigpending(&pending);
1102 if (sigismember(&pending, SIGINT)) {
1103 log_debug("Have a pending SIGINT interupt waiting!");
1104 int sig;
1105 sigwait(&blockset, &sig);
1106 cntrlc_handler(SIGINT);
1108 #else
1109 tval.tv_sec = timeout;
1110 tval.tv_usec = 0;
1111 ret = select(fd+1, NULL, &fdset, NULL, &tval);
1112 #endif
1114 // If interrupted by a system call, try again
1115 if (ret == -1 && errno == EINTR) {
1116 log_error (_("The socket for fd #%d was interrupted by a system call"), fd);
1119 if (ret == -1) {
1120 log_error (_("The socket for fd #%d was never available for writing"), fd);
1123 if (ret == 0) {
1124 log_debug (_("The socket for fd #%d timed out waiting to write"), fd);
1125 return 0;
1128 #ifdef USE_SSL
1129 if (_ssl) {
1130 ret = _ssl->sslWrite(buffer, nbytes);
1131 } else {
1132 ret = write(fd, bufptr, nbytes);
1134 #else
1135 ret = write(fd, bufptr, nbytes);
1136 #endif
1137 if (ret == 0) {
1138 log_error (_("Wrote zero out of %d bytes to fd #%d: %s"),
1139 nbytes, fd, strerror(errno));
1140 return ret;
1142 if (ret < 0) {
1143 log_error (_("Couldn't write %d bytes to fd #%d: %s"),
1144 nbytes, fd, strerror(errno));
1145 return ret;
1147 if (ret > 0) {
1148 bufptr += ret;
1149 if (ret != nbytes) {
1150 if (_debug) {
1151 log_debug (_("wrote %d bytes to fd #%d, expected %d"),
1152 ret, fd, nbytes);
1154 } else {
1155 if (_debug) {
1156 log_debug (_("wrote %d bytes to fd #%d for port %d"),
1157 ret, fd, _port);
1159 // return ret;
1162 #if 0
1163 if (ret) {
1164 log_debug (_("%s: Wrote packet data to fd #%d: \n%s"),
1165 __FUNCTION__, fd, hexify(buffer, ret, true));
1167 #endif
1170 #ifdef NET_TIMING
1171 if (_timing_debug)
1173 gettimeofday(&endtime, 0);
1175 if ((endtime.tv_sec - starttime.tv_sec) &&
1176 endtime.tv_usec - starttime.tv_usec)
1178 log_debug (_("took %d usec to write (%d bytes)"),
1179 endtime.tv_usec - starttime.tv_usec, bytes_written);
1182 #endif
1185 return ret;
1188 void
1189 Network::addPollFD(struct pollfd &fd, Network::entry_t *func)
1191 // GNASH_REPORT_FUNCTION;
1193 log_debug("%s: adding fd #%d to pollfds", __PRETTY_FUNCTION__, fd.fd);
1194 boost::mutex::scoped_lock lock(_poll_mutex);
1195 _handlers[fd.fd] = func;
1196 _pollfds.push_back(fd);
1197 // notify();
1200 void
1201 Network::addPollFD(struct pollfd &fd)
1203 // GNASH_REPORT_FUNCTION;
1204 log_debug("%s: adding fd #%d to pollfds", __PRETTY_FUNCTION__, fd.fd);
1205 boost::mutex::scoped_lock lock(_poll_mutex);
1206 _pollfds.push_back(fd);
1207 // notify();
1210 struct pollfd
1211 &Network::getPollFD(int index)
1213 // GNASH_REPORT_FUNCTION;
1214 boost::mutex::scoped_lock lock(_poll_mutex);
1215 return _pollfds[index];
1218 struct pollfd *
1219 Network::getPollFDPtr()
1221 // GNASH_REPORT_FUNCTION;
1222 boost::mutex::scoped_lock lock(_poll_mutex);
1223 return &_pollfds[0];
1226 void
1227 Network::erasePollFD(int fd)
1229 // GNASH_REPORT_FUNCTION;
1230 log_debug("%s: erasing fd #%d from pollfds", __PRETTY_FUNCTION__, fd);
1231 boost::mutex::scoped_lock lock(_poll_mutex);
1232 if (_pollfds.size() > 0) {
1233 vector<struct pollfd>::iterator it;
1234 for (it=_pollfds.begin(); it<_pollfds.end(); it++) {
1235 if ((*it).fd == fd) {
1236 _pollfds.erase(it);
1237 break;
1243 void
1244 Network::erasePollFD(vector<struct pollfd>::iterator &itt)
1246 // GNASH_REPORT_FUNCTION;
1247 boost::mutex::scoped_lock lock(_poll_mutex);
1248 if (_pollfds.size() == 1) {
1249 _pollfds.clear();
1250 } else {
1251 _pollfds.erase(itt);
1255 void
1256 Network::addEntry(int fd, Network::entry_t *func)
1258 // GNASH_REPORT_FUNCTION;
1259 boost::mutex::scoped_lock lock(_poll_mutex);
1260 _handlers[fd] = func;
1263 Network::entry_t *
1264 Network::getEntry(int fd)
1266 // GNASH_REPORT_FUNCTION;
1267 boost::mutex::scoped_lock lock(_poll_mutex);
1268 return _handlers[fd];
1271 boost::shared_ptr<std::vector<struct pollfd> >
1272 Network::waitForNetData(int limit, struct pollfd *fds)
1274 // GNASH_REPORT_FUNCTION;
1276 boost::shared_ptr<vector<struct pollfd> > hits(new vector<struct pollfd>);
1278 log_debug("%s: waiting for %d fds", __FUNCTION__, limit);
1280 if ((fds == 0) || (limit == 0)) {
1281 return hits;
1284 int timeout = _timeout;
1285 if (timeout <= 0) {
1286 timeout = 5;
1288 #ifdef HAVE_PPOLL
1289 struct timespec tval;
1290 sigset_t pending, blockset;
1291 sigemptyset(&blockset); /* Block SIGINT */
1292 // sigaddset(&blockset, SIGINT);
1293 // sigaddset(&blockset, SIGPIPE);
1294 sigprocmask(SIG_BLOCK, &blockset, NULL);
1296 tval.tv_sec = 5; // FIXME: was _timeout;
1297 tval.tv_nsec = 0;
1298 int ret = ppoll(fds, limit, &tval, &blockset);
1299 sigpending(&pending);
1300 if (sigismember(&pending, SIGINT)) {
1301 log_debug("Have a pending SIGINT interupt waiting!");
1302 int sig;
1303 sigwait(&blockset, &sig);
1305 #else
1306 #ifdef HAVE_POLL_H
1307 int ret = poll(fds, limit, _timeout);
1308 #else
1309 fd_set fdset;
1310 struct timeval tval;
1311 tval.tv_sec = timeout;
1312 tval.tv_usec = 0;
1313 int ret = select(limit+1, &fdset, NULL, NULL, &tval);
1314 #endif
1315 #endif
1317 log_debug("Poll returned: %d, timeout is: %d", ret, _timeout);
1319 while (ret--) {
1320 for (int i = 0; i<limit; i++) {
1321 // If we get this event, the other end of the connection has been shut down
1322 #if 0
1323 if (fds[i].revents &POLLPRI ) {
1324 log_debug("%s: Revents has a POLLPRI set 0x%x for fd #%d",
1325 __FUNCTION__, fds[i].revents, fds[i].fd);
1327 if (fds[i].revents & POLLRDNORM) {
1328 log_debug("%s: Revents has a POLLRDNORM set 0x%x for fd #%d",
1329 __FUNCTION__, fds[i].revents, fds[i].fd);
1331 if (fds[i].revents & POLLHUP) {
1332 log_debug("%s: Revents has a POLLHUP set 0x%x for fd #%d",
1333 __FUNCTION__, fds[i].revents, fds[i].fd);
1337 if (fds[i].revents & POLLERR) {
1338 log_debug("%s: Revents has a POLLERR set 0x%x for fd #%d",
1339 __FUNCTION__, fds[i].revents, fds[i].fd);
1341 if (fds[i].revents & POLLHUP) {
1342 log_debug("%s: Revents has a POLLHUP set 0x%x for fd #%d",
1343 __FUNCTION__, fds[i].revents, fds[i].fd);
1345 if (fds[i].revents & POLLNVAL) {
1346 log_debug("%s: Revents has a POLLNVAL set 0x%x for fd #%d",
1347 __FUNCTION__, fds[i].revents, fds[i].fd);
1348 // throw GnashException("Polling an invalid file descritor");
1350 if (fds[i].revents & POLLIN) {
1351 log_debug("%s: Revents has a POLLIN set 0x%x for fd #%d",
1352 __FUNCTION__, fds[i].revents, fds[i].fd);
1354 if (fds[i].revents & POLLMSG) {
1355 log_debug("%s: Revents has a POLLMSG set 0x%x for fd #%d",
1356 __FUNCTION__, fds[i].revents, fds[i].fd);
1358 if (fds[i].revents & POLLREMOVE) {
1359 log_debug("%s: Revents has a POLLREMOVE set 0x%x for fd #%d",
1360 __FUNCTION__, fds[i].revents, fds[i].fd);
1362 if (fds[i].revents & POLLRDHUP) {
1363 log_debug("%s: Revents has a POLLRDHUP set 0x%x for fd #%d",
1364 __FUNCTION__, fds[i].revents, fds[i].fd);
1365 // throw GnashException("Connection dropped from client side.");
1367 #endif
1368 // if ((fds[i].revents & POLLIN) || (fds[i].revents & POLLRDHUP)) {
1369 hits->push_back(fds[i]);
1370 // // If we got as many matches as were seen by poll(), then
1371 // // stop searching the rest of the items in the array.
1372 // if (hits->size() == ret) {
1373 // break;
1374 // }
1375 // } else {
1376 // log_debug("No data on fd #%d, revents is 0x%x", fds[i].fd, fds[i].revents);
1377 // }
1381 return hits;
1384 fd_set
1385 Network::waitForNetData(vector<int> &data)
1387 // GNASH_REPORT_FUNCTION;
1389 fd_set fdset;
1390 FD_ZERO(&fdset);
1392 if (data.size()) {
1393 int max = 0;
1395 for (size_t i = 0; i<data.size(); i++) {
1396 FD_SET(data[i], &fdset);
1397 if (data[i] > max) {
1398 max = data[i];
1401 return waitForNetData(max+1, fdset);
1404 return fdset;
1407 fd_set
1408 Network::waitForNetData(int limit, fd_set files)
1410 // GNASH_REPORT_FUNCTION;
1412 // select modifies the set of file descriptors, and we don't
1413 // want to modify the one passed as an argument, so we make a copy.
1414 fd_set fdset = files;
1416 // Reset the timeout value, since select modifies it on return
1417 int timeout = _timeout;
1418 if (timeout <= 0) {
1419 timeout = 30;
1421 #ifdef HAVE_PSELECT_XX
1422 struct timespec tval;
1423 sigset_t pending, sigmask;
1424 sigprocmask(SIG_BLOCK, &sigmask, NULL);
1426 tval.tv_sec = 0;
1427 tval.tv_nsec = timeout * 1000000000;
1428 int ret = pselect(limit+1, &fdset, NULL, NULL, &tval, &sigmask);
1429 sigpending(&pending);
1430 if (sigismember(&pending, SIGINT)) {
1431 log_debug("Have a pending SIGINT interupt waiting!");
1432 int sig;
1433 sigwait(&sigmask, &sig);
1435 if (sigismember(&pending, SIGPIPE)) {
1436 log_debug("Have a pending SIGPIPE interupt waiting!");
1437 int sig;
1438 sigwait(&sigmask, &sig);
1440 #else
1441 struct timeval tval;
1442 tval.tv_sec = 0;
1443 tval.tv_usec = timeout * 1000; // was 1000000
1444 int ret = select(limit+1, &fdset, NULL, NULL, &tval);
1445 #endif
1446 // If interrupted by a system call, try again
1447 if (ret == -1 && errno == EINTR) {
1448 log_error (_("Waiting for data was interrupted by a system call"));
1451 if (ret == -1) {
1452 log_error (_("Waiting for data for fdset, was never available for reading"));
1453 FD_ZERO(&fdset);
1454 FD_SET(0, &fdset);
1455 return fdset;
1458 if (ret == 0) {
1459 // log_debug (_("Waiting for data for fdset, timed out waiting for data"));
1460 FD_ZERO(&fdset);
1461 FD_SET(0, &fdset);
1462 return fdset;
1465 if (ret < 0) {
1466 log_error("select() got an error: %s.", strerror(errno));
1467 FD_ZERO(&fdset);
1468 FD_SET(0, &fdset);
1469 } else {
1470 log_network("select() saw activity on %d file descriptors.", ret);
1473 return fdset;
1476 Network &
1477 Network::operator = (Network &net)
1479 GNASH_REPORT_FUNCTION;
1481 // the file descriptor used for reading and writing
1482 _sockfd= net.getFileFd();
1483 // the file descriptor used to listen for new connections
1484 _listenfd = net.getListenFd();
1485 _port = net.getPort();
1486 _portstr = net.getPortStr();
1487 _url = net.getURL();
1488 _protocol = net.getProtocol();
1489 _host = net.getHost();
1490 _path = net.getPath();
1491 _connected = net.connected();
1492 _debug = net.netDebug();
1493 _timeout = net.getTimeout();
1494 return *this;
1497 void
1498 Network::toggleDebug(bool val)
1500 // Turn on our own debugging
1501 _debug = val;
1503 // Turn on debugging for the utility methods
1504 // recursive on all control paths,
1505 // toggleDebug(true);
1508 #ifdef USE_SSL
1509 bool
1510 Network::initSSL(std::string &hostname)
1512 GNASH_REPORT_FUNCTION;
1513 string nothing;
1514 initSSL(hostname, nothing);
1517 bool
1518 Network::initSSL(std::string &hostname, std::string &password)
1520 GNASH_REPORT_FUNCTION;
1521 string nothing;
1523 initSSL(hostname, password, nothing, nothing, nothing, true);
1526 bool
1527 Network::initSSL(std::string &hostname, std::string &password, bool auth)
1529 GNASH_REPORT_FUNCTION;
1531 string nothing;
1532 initSSL(hostname, password, nothing, nothing, nothing, auth);
1535 bool
1536 Network::initSSL(std::string &hostname, std::string &passwd,
1537 std::string &keyfile, std::string &calist,
1538 std::string &rootpath, bool auth)
1540 GNASH_REPORT_FUNCTION;
1542 // FIXME: make sure we have a connection
1544 if (_sockfd == 0) {
1545 if ((_sockfd = createClient(hostname, SSL_PORT) == false)) {
1546 log_error("Can't connect to server %s", hostname);
1547 return false;
1551 if (!_ssl) {
1552 _ssl.reset(new SSLClient);
1555 if (!hostname.empty()) {
1556 _ssl->setHostname(hostname);
1557 } else {
1558 log_debug("Using default hostname: \"%s\"", _host);
1560 if (!keyfile.empty()) {
1561 _ssl->setKeyfile(keyfile);
1562 } else {
1563 log_debug("Using default keyfile: \"%s\"", _ssl->getKeyfile());
1565 if (!calist.empty()) {
1566 _ssl->setCAlist(calist);
1567 } else {
1568 log_debug("Using default CA List: \"%s\"", _ssl->getCAlist());
1571 if (!passwd.empty()) {
1572 _ssl->setPassword(passwd);
1573 } else {
1574 log_debug("Using default Password: \"%s\"", _ssl->getPassword());
1576 if (!rootpath.empty()) {
1577 _ssl->setRootPath(rootpath);
1578 } else {
1579 log_debug("Using default Root Path to PEM files: \"%s\"",
1580 _ssl->getRootPath());
1583 if (_ssl->sslConnect(_sockfd)) {
1584 log_debug("Connected to SSL server");
1585 } else {
1586 log_error("Couldn't connect to SSL server");
1587 return false;
1590 // If we got this far, everthing worked
1591 return true;
1593 #endif
1595 // Use an ioctl() to see how many bytes are in the network buffers.
1596 size_t
1597 Network::sniffBytesReady(int fd)
1599 // GNASH_REPORT_FUNCTION;
1601 int bytes = 0;
1602 fd_set fdset;
1604 FD_SET(fd, &fdset);
1606 struct timeval tval;
1607 tval.tv_sec = 0;
1608 tval.tv_usec = 10;
1609 if (select(fd+1, &fdset, NULL, NULL, &tval)) {
1610 if (FD_ISSET(fd, &fdset)) {
1611 #ifndef _WIN32
1612 ioctl(fd, FIONREAD, &bytes);
1613 #else
1614 ioctlSocket(fd, FIONREAD, &bytes);
1615 #endif
1619 log_network("#%d bytes waiting in kernel network buffer.", bytes);
1621 return bytes;
1624 // Trap Control-C so we can cleanly exit
1625 static void
1626 cntrlc_handler (int sig)
1628 GNASH_REPORT_FUNCTION;
1629 sig_number = sig;
1630 log_debug(_("Got an %d interrupt while blocked on pselect()"), sig);
1631 exit(EXIT_FAILURE);
1634 } // end of gnash namespace
1636 // Local Variables:
1637 // mode: C++
1638 // indent-tabs-mode: t
1639 // End: